corectrl-v1.4.2/000077500000000000000000000000001467225065400135345ustar00rootroot00000000000000corectrl-v1.4.2/.clang-format000066400000000000000000000033271467225065400161140ustar00rootroot00000000000000# -- General settings -- Language: Cpp # Merge empty functions in a single line. AllowShortFunctionsOnASingleLine: None # Align pointers and references to the right PointerAlignment: Right DerivePointerAlignment: false # Remove space after template keyword SpaceAfterTemplateKeyword: false # Avoid mixing comments with code when code containing comments has been commented ReflowComments: false # Sort options SortIncludes: true # -- Indentation settings -- UseTab: Never TabWidth: 2 IndentWidth: 2 IndentCaseLabels: true ContinuationIndentWidth: 4 # Indentation witdh before ':' in constructors and class inheritance lists. ConstructorInitializerIndentWidth: 0 # Enable indentation for [public, private, protected] # and takes one space from the general indentation setting. AccessModifierOffset: -1 # -- Break settings-- BreakBeforeBraces: Custom BraceWrapping: AfterClass: true AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: false AfterStruct: true AfterUnion: true AfterExternBlock: false BeforeCatch: true BeforeElse: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true # Initializers breaks. BreakConstructorInitializers: BeforeComma # Inheritance breaks. BreakInheritanceList: BeforeComma #BreakBeforeInheritanceComma: true # Use with clang < 7 # Template breaks. AlwaysBreakTemplateDeclarations: true # Penalties PenaltyBreakAssignment: 30 PenaltyBreakBeforeFirstCallParameter: 10 PenaltyExcessCharacter: 15 # Uncoment to reset line breaks #ColumnLimit: 500 ... corectrl-v1.4.2/.gitignore000066400000000000000000000001651467225065400155260ustar00rootroot00000000000000*.o *.gch *.pch *.so *.a *.out *.swp *.swo *.un~ *.orig *.txt.user *.txt.autosave *.patch *.qm compile_commands.json corectrl-v1.4.2/.gitlab/000077500000000000000000000000001467225065400150545ustar00rootroot00000000000000corectrl-v1.4.2/.gitlab/issue_templates/000077500000000000000000000000001467225065400202625ustar00rootroot00000000000000corectrl-v1.4.2/.gitlab/issue_templates/Bug.md000066400000000000000000000012421467225065400213200ustar00rootroot00000000000000Please, follow the [Issues writing guidelines](CONTRIBUTING.md#Issues-writing-guidelines). **CoreCtrl version:** **Distribution:** **Kernel version:** **GPU model:** **GPU driver:** **GPU driver parameters:** Please, add more info if needed, like desktop enviroment or other system components. # Description of the bug Please, describe your bug here. Be precise and clear. # Reproduction Simplified, easy to follow steps to reproduce the bug: 1. 2. 3. **Actual result:** **Expected result:** # Additional information Include other files here (screenshots, logs, backtraces...). For logs, backtraces or console output, use text format instead of screenshots. corectrl-v1.4.2/.gitlab/issue_templates/Default.md000066400000000000000000000017241467225065400221740ustar00rootroot00000000000000Please, choose a template for your issue using the **template selector** under the *Description* field. All driver bugs must be [reported upstream](https://gitlab.com/corectrl/corectrl/-/wikis/FAQ#i-found-a-driver-bug-where-can-i-report-it). You can easily check if the issue is a driver bug by trying to reproduce it using different kernel versions. When an issue is only reproducible on some kernels versions, it's most likely due to a driver bug. As a general rule, **do not report driver bugs in this issue tracker**. Exceptionally, you can report them here if you feel that other corectrl users must be aware about them or you think that a workaround could be implemented in corectrl (don't forget to explain it in detail). Please, label these issues using the `driver issue` tag. Any issues not following the previous recommendations and the [Issues writing guidelines](CONTRIBUTING.md#Issues-writing-guidelines) **may be closed as invalid** without further explanation. corectrl-v1.4.2/.gitlab/issue_templates/Feature.md000066400000000000000000000003301467225065400221730ustar00rootroot00000000000000# Description Please, describe your feature request here. Add files and links which would help for understanding the feature you are describing. # Use cases If needed, explain the use cases or problems to solve. corectrl-v1.4.2/.gitlab/merge_request_templates/000077500000000000000000000000001467225065400220015ustar00rootroot00000000000000corectrl-v1.4.2/.gitlab/merge_request_templates/Default.md000066400000000000000000000001711467225065400237060ustar00rootroot00000000000000Please, follow the [Merge request guidelines](CONTRIBUTING.md#Merge-request) before starting to work on a merge request. corectrl-v1.4.2/CHANGELOG.md000066400000000000000000000423031467225065400153470ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. ## Unreleased ## CoreCtrl 1.4.2 (2024-09-17) ### Fixed - Main window not visible after application startup when the system tray icon has been disabled (#458). - CPU Energy Performance Preference only shows `performance` as the available option when launching the application while the CPU governor is set to `performance` (#466). ### Added - Power profiles support for AMD RX 7600 (#447). Requires Linux 6.11 or later. ## CoreCtrl 1.4.1 (2024-05-21) ### Fixed - Compilation on architectures without atomics support (#435). ### Added - Register Catch2 tests in CTest. Thanks to Leonidas Spyropoulos (!47). ## CoreCtrl 1.4.0 (2024-03-17) ### Fixed - QML Connections deprecation warning (#123). ### Changed - Require Qt 5.15. - Require a C++20 compiler (gcc 13.1 or later, clang 17 or later). - Require CMake 3.22. - Require Catch2 3.0 or later when building tests. Based on the work done by Leonidas Spyropoulos (!44). - Require trompeloeil 40 or later when building tests. - Require QuaZip 1.0 or later. - Require pugixml 1.11 or later. - Replace easyloggingpp with spdlog (version 1.4 or later). The new library is required to compile the application. - Command line arguments that affect a running instance of the application can now be used together. The argument `--minimize-systray` takes precedence over `--toggle-window-visibility`. - Use `org.corectrl.CoreCtrl` in both the icon name and the manifest's application ID to better conform to FreeDesktop specifications. Thanks to Reilly Brogan (!41). - Disable building the testing suite by default. ### Added - Implement resizable graph and sensors regions. Both regions are configurable by dragging their split handles and the sizes persist between sessions (#309). - CPU usage sensor. Based on the work done by Milan Čermák (!38). - Intel CPU temperature sensor for `coretemp` driver. Thanks to Milan Čermák (!38). - Botan 3 compilation support (#373). Botan 2 is still supported. Botan 3 takes precedence over Botan 2 when both versions are installed in the system. - Manual profile activation at application startup using the command line argument `-m, --toggle-manual-profile` (#366). - Automatic and curve fan controls for AMD RX 7000 series (#344). - CPU Energy Performance Preference control (#404). This feature is only available for hardware with active governing support and can be accessed by setting the CPU frequency scaling governor to `Powersave`. - Swedish translation. Thanks to Jon (!45). ### Removed - Bundled version of Catch2. - Bundled version of trompeloeil. - Bundled version of easyloggingpp. - Bundled version of pugixml. - fmt library dependency. - Unimplemented custom frequency option from CPU performance scaling governor control (#175). ## CoreCtrl 1.3.11 (2024-03-10) ### Fixed - Default power limit value when power limit reset support is not available (#422). - Crash when toggling a non-existing manual profile through the command line (#429). - Typo in README. Thanks to paintdev (!43). ### Removed - Workaround for automatic profiles not working with Linux 6.7 and Linux 6.6.13 (#416). The change that triggers this regression was reverted in Linux 6.7.6 and 6.6.18. ## CoreCtrl 1.3.10 (2024-02-04) ### Fixed - Compilation with clang and linking errors (#417). - Missing power limit control on Linux 6.7 (#415). ### Added - Workaround for automatic profiles not working with Linux 6.7 and Linux 6.6.13 (#416). ## CoreCtrl 1.3.9 (2024-01-14) ### Fixed - Power sensor not working on older AMD GPU models under Linux 6.6 (#398). ### Changed - Disable hwmon based fan controls for RX 7000 series while using Linux 6.7 or later, as these controls no longer work on such hardware. ## CoreCtrl 1.3.8 (2023-11-05) ### Fixed - Compilation issues with Linux 6.6 API headers (#393). From now own a C compiler is also needed to build the application. ## CoreCtrl 1.3.7 (2023-11-01) ### Fixed - Window association with the application desktop file under Wayland. Thanks to Reilly Brogan (!41). - Compilation with gcc 14. Thanks to Kostadin (!42). ## CoreCtrl 1.3.6 (2023-10-16) ### Fixed - Voltage curve control creation failing on RX 7000 series. Do not attempt to create such control when the overdrive voltage curve is not really a frequency/voltage curve. - Crash due to kernel driver reporting bogus data on `pp_dpm_sclk` or `pp_dpm_mclk` (#387). - English translation typo. Thanks to Flora Aubry (!40). ## CoreCtrl 1.3.5 (2023-04-01) ### Fixed - No power limit control available (#356). ## CoreCtrl 1.3.4 (2023-03-28) ### Fixed - Crash due to kernel driver reporting bogus power limit range bound values (#337). The power limit control won't be created in the affected kernel versions. ## CoreCtrl 1.3.3 (2023-02-26) ### Fixed - Tests segfault on Release build (#351). ## CoreCtrl 1.3.2 (2023-02-19) ### Fixed - Automatic profiles are not activated using the default wine packages in Pop!_OS (#161). - Crash due to kernel driver reporting bogus power limit range bound values (#337). The power limit control won't be created in the affected kernel versions. ### Changed - Prefer external third-party libraries over the bundled ones. This should help package maintainers to follow their distribution policies (#13, #346). Version requirements for the external libraries: - fmt 5.0 or later. - pugixml 1.11 or later. - units 2.3.1 or later. - easyloggingpp 9.96.7 or later. - catch2 2.6 to <3.0 when compiling tests. - trompeloeil 40 or later when compiling tests. - Replace file headers license section with [SPDX unique license identifiers](https://spdx.dev/ids/). ### Removed - `BUILD_SPLIT_TESTS` configuration option. ## CoreCtrl 1.3.1 (2022-10-08) ### Fixed - Incorrect alignment of state voltage labels when automatic voltage is selected on the frequency & voltage control. - CPU performance scaling mode not being restored from file (#322). - Compilation issues with Linux 6.0 API headers (#325). ### Changed - Explicitly require Qt 5.9 (or compatible versions). - Install application binary and library files into GNU standard installation directories (#324). ## CoreCtrl 1.3.0 (2022-09-18) ### Fixed - Profiles not loading consistently between reboots when using multiple GPUs (#300). If you are affected by this issue and your GPUs supports unique IDs (Vega and later models), re-save your profiles. More info on the [Known Issues](https://gitlab.com/corectrl/corectrl/-/wikis/Known-issues#profiles-reset-randomly-between-reboots-when-using-multiple-gpus) Wiki page. - Active profile is not deactivated after changing its name or executable name. - Profile icons and other displayed images not preserving their aspect ratio (#310). - Crash on application exit when running under some window managers (like IceWM). - Crash when applying specific fan curves in some circumstances (#164). Now, only constant and ascending curves can be created and used as fan curves. - `corectrl_helper` blocking when running on kernels in which the option `CONFIG_PROC_EVENTS` has not been set (#71). The automatic profiles won't work when running on such kernels, though. ### Changed - Replace KAuth dependency with Polkit, D-Bus and Qt5::DBus. - Replace KArchive dependency with QuaZip. - Update Russian translation. Thanks to OlesyaGerasimenko (!35). ### Added - Display the GPU unique ID in the GPU info tab. Available on Vega and later GPU models. - Make custom profile icons optional in the profile dialog. The user can now select a custom icon or simply use the default one in their profiles (#127). - Manual profiles. The user can now create profiles to partially or completely override the settings applied by the global and per-application profiles. They can be toggled from the system tray or through the main GUI (#49). - System tray menu entry to hide and show the main window (#280). - New command line options: - `--minimize-systray`: starts the application minimized either to the system tray (when available) or to the taskbar. When an instance of the application is already running, the action will be applied to its main window (#78). - `--toggle-window-visibility`: when an instance of the application is already running, it will toggle the main window visibility showing or minimizing it, either to the taskbar or to system tray. - `m`, `--toggle-manual-profile`: when an instance of the application is already running, it will toggle the given manual profile (#224). - Option to save the window geometry (#312). The saved geometry is always restored at application startup. Restoring some window properties, such as window position, can be unreliable under Wayland. - German translation. Thanks to Rüdiger Arp, polyphase and SE. (#104). ## CoreCtrl 1.2.7 (2022-08-09) ### Fixed - Fix power profiles parsing on sienna cichlid asics (#305). ### Added - Workaround for a [long-standing driver bug](https://gitlab.freedesktop.org/drm/amd/-/issues/1706) which affects the RX6000 series. It allows the user to control the maximum memory frequency when using these cards. Turned out that this was not the cause of the low memory frequency issue (#304), so it should be safe to restore this functionality. ## CoreCtrl 1.2.6 (2022-08-06) ### Removed - Workaround for a [long-standing driver bug](https://gitlab.freedesktop.org/drm/amd/-/issues/1706) affecting the RX6000 series. This workaround allowed the user to control the maximum memory frequency on those models. Unfortunately, this functionality triggers another memory related driver bug that locks the memory frequency to a low value (#304). ## CoreCtrl 1.2.5 (2022-08-02) ### Added - Add a workaround for a [long-standing driver bug](https://gitlab.freedesktop.org/drm/amd/-/issues/1706) which affects the RX6000 series. It allows the user to control the maximum memory frequency when using these cards. - Support power profile mode on asics without heuristics settings (#303). ## CoreCtrl 1.2.4 (2022-07-17) ### Fixed - Fix clangd not picking the project C++ standard level. - Fix deprecated calls to QProcess::start. - Fix warning on FindBotan.cmake. - Explicitly disable QApplication quit on last window closed. - Fix voltage offset not being restored during the initialization phase. ### Added - Add support for unix paths to .exe files on wine launch cmdline. - Add Czech translation. Thanks to viktorp (!32). - Add Dutch translation. Thanks to Heimen Stoffels (!33). ## CoreCtrl 1.2.3 (2022-02-23) ### Fixed - Use QObject parent/child ownership to manage system tray icon lifetime (#76). - Parse kernel versions without patch number (#254). ## CoreCtrl 1.2.2 (2021-11-14) ### Fixed - Various fixes for some wine apps not being recognized when launched: - Using custom compatibility tools on Steam. - Having uppercase extensions and launched from a case sensitive file system. - Fixed missing profile icon after editing the profile executable name. - Fixed profile not being monitored after editing the profile executable name. ### Changed - Session code improvements. ## CoreCtrl 1.2.1 (2021-09-19) ### Fixed - Use tension instead of voltage on french translation. Thanks to DarkeoX ABYSSION Tar Valantinir (!31). - Fixed system hang on some models of RX 6000 XT series (#213). - Fixed ignored disabled states on overdrive frequency + voltage controls (#218). - Rework command generation and handling. The number of submitted commands has been reduced and now commands writing to different files won't be interleaved, thus improving the stability of the system. The previous implementation might trigger unexpected driver behavior and bugs that might hang the system, as reported on both #217 and #218. ### Changed - Rework driver quirks handling. Now, it's done in a more granular way, per overdrive control. As a consequence of this, the fallback fixed frequency control is now only used when `pp_od_clk_voltage` is missing or empty (typically, when the user has not set `amdgpu.ppfeaturemask`). - Reduce the amount of events sent to the process monitor. Process thread events are now filtered out. ## CoreCtrl 1.2.0 (2021-09-05) ### Added - Added GPU memory and junction sensors (#36). - Added GPU voltage sensor. - Added support for voltage offset (#139). With this RX 6XXX are fully supported. Use with caution, as no voltage range is provided by the driver. - Added noop control. This control can be used to hand over control of certain components to other programs. More info in the Wiki: [Do not control mode](https://gitlab.com/corectrl/corectrl/-/wikis/How-profiles-works#do-not-control-mode), [Controlling parts of your system with external applications](https://gitlab.com/corectrl/corectrl/-/wikis/How-profiles-works#controlling-parts-of-your-system-with-external-applications). - Modularized overdrive controls. This adds clock controls to RX 6XXX (#139). ### Changed - Sensor color is no longer stored in profiles. - Group sensor's colors by type. ## CoreCtrl 1.1.5 (2021-08-22) ### Fixed - Fixed wrong VRAM usage shown (#92). Thanks to Dmitry Fateev (!30). - Fixed incorrect amount of VRAM detected (#83). GPU video ram is now read from ioctl. - Fixed advanced performance settings not being cleaned when switching to other performance modes (#204). ### Changed - Minor code refactorings. - Move translations and QT_STYLE_OVERRIDE messages to INFO level. ## CoreCtrl 1.1.4 (2021-07-25) ### Changed - Code cleanups. - Remove unsafe flags on arch installation instructions (#181). ### Added - Rework AMD fan sensors creation logic (#184). ## CoreCtrl 1.1.3 (2021-05-09) ### Fixed - Fix tests compilation (#178). ### Added - Make path to pci.ids configurable at build time using -DWITH_PCI_IDS_PATH=. Thanks to Alexander Kapshuna (!26). ## CoreCtrl 1.1.2 (2021-05-02) ### Fixed - Fixed theme by ignoring QT_STYLE_OVERRIDE environment variable (#106). - Fixed header width of mode selector controls (#176). ### Changed - Use KDEInstallDirs instead of hardcoded paths to install resources. Thanks to Alexander Kapshuna (!27). ## CoreCtrl 1.1.1 (2020-08-19) ### Fixed - Fixed kernel version parsing. Thanks to Norbert Preining (#82). - Added svg Qt component as required dependency (#61). - Fixed incorrect executable file name on profile dialog (#94). - Added a workaround for bogus values on critical temperature (#103). - Fixed settings are not being applied with some wine executables (#121). ### Added - Added Bulgarian translation. Thanks to Xrey274 (!17). - Added Russian translation to launcher.desktop comment. Thanks to Harry Kane (!24). ## CoreCtrl 1.1.0 (2020-05-31) ### Fixed - Fixed compilation with newer versions of gcc (#54, #62). - Reworked vega20 (navi... and newer hardware) advanced power management controls (#37). ### Added - Added French translation. Thanks to DarkeoX ABYSSION Tar Valantinir (#30). - Added Catalan translation. Thanks to bla6 (#72). - Added workaround for high cpu load on some hardware (#29). - Added navi support (#41). ## CoreCtrl 1.0.9 (2020-04-19) ### Fixed - Fix compilation on some systems (#62). ## CoreCtrl 1.0.8 (2020-03-15) ### Fixed - Fix compilation with gcc 10 (#54). ## CoreCtrl 1.0.7 (2019-11-23) ### Fixed - Missing character on profile menu icon. - Skip empty GPU info vendor, device and subdevice names. - Add deferred system tray icon support (#43). ### Changed - Code cleanups. - Removed Patreon info. ## CoreCtrl 1.0.6 (2019-08-08) ### Fixed - Missing controls when using Qt 5.9 (#17). - UI performance issues (#28). ### Changed - Update russian translation. Thanks to Schwonder Reismus (!13). - Do not create controls and sensors when data sources have invalid data. - Check and try to fix the state of some controls and all profiles after importing wrong values. - Fan curve control scale the curve into valid range. - Reduce CPU usage when the sensors graph is not visible. ### Added - Restore previous hardware state after init. ## CoreCtrl 1.0.5 (2019-07-22) ### Fixed - Remove qca build dependency. - Fix wrong icon size. If you installed CoreCtrol from source, you may want to uninstall it before instaling this version. This will remove no longer used files from your computer. You can also remove them manually: ``` sudo rm /usr/share/applications/CoreCtrl.desktop /usr/share/icons/hicolor/196x196/apps/corectrl.svg ``` If `/usr/share/icons/hicolor/196x196` directory only contains `apps/corectrl.svg` remove it with: ``` sudo rm /usr/share/applications/CoreCtrl.desktop sudo rm -rf /usr/share/icons/hicolor/196x196 ``` ### Added - Add Russian translation. - Add AppStream metadata file. ### Changed - Improve default cpu frequency scaling governor selection. - Follow freedesktop naming conventions for the .desktop file. ## CoreCtrl 1.0.4 (2019-07-17) ### Fixed - Removed an unused qml module import. ### Changed - CoreCtrl now does not start minimized on system tray by default. ## CoreCtrl 1.0.3 (2019-07-15) ### Fixed - Fixed application crash when using Qt 5.9. ### Added - Add uninstall target to CMake. ## CoreCtrl 1.0.2 (2019-07-15) ### Fixed - Require CMake version 3.12 instead 3.3. - Launcher doesn't show its icon due to installed icons having a wrong name. ## CoreCtrl 1.0.1 (2019-07-14) ### Fixed - Compilation failed due to a wrong symbolic link. - Some typos. ## CoreCtrl 1.0.0 (2019-07-14) ### Added - Automatic application of profiles for native and Windows programs. - Full AMD GPUs controls (for both old and new models). - Basic CPU controls. corectrl-v1.4.2/CMakeLists.txt000066400000000000000000000066761467225065400163130ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.22) project(CoreCtrl HOMEPAGE_URL "https://gitlab.com/corectrl/corectrl") set(PROJECT_FQDN "org.corectrl.CoreCtrl") set(PROJECT_VERSION 1.4.2) include(GNUInstallDirs) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # add uninstall target if(NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif() set(CMAKE_CXX_STANDARD 20) option (WITH_DEBUG_INFO "Add debug information (to Debug builds)" OFF) if(CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions("-D_DEBUG") add_compile_options("-W;-Wall;-Wextra") add_compile_options("-Wno-redundant-move;-Wno-sign-compare") if (WITH_DEBUG_INFO) add_compile_options("-ggdb;-fno-omit-frame-pointer") endif() endif() # require libatomic on architectures without atomics support include(CheckAtomic) if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB) list(APPEND ATOMIC_LIB "atomic") endif() find_package(Qt5 5.15 COMPONENTS Core DBus Quick Charts Widgets Network Svg REQUIRED) find_package(Qt5LinguistTools REQUIRED) find_package(QuaZip-Qt5 1.0 REQUIRED) find_package(spdlog 1.4 REQUIRED) find_package(pugixml 1.11 REQUIRED) find_package(Botan QUIET) if(NOT Botan_FOUND) message(FATAL_ERROR "Botan library not found") endif() find_package(units 2.3.1 QUIET) if(NOT units_FOUND) message("Using bundled units library") list(APPEND 3RDPARTY_INCLUDE_DIRECTORIES ${PROJECT_SOURCE_DIR}/3rdparty/units) endif() list(APPEND 3RDPARTY_DEFINITIONS UNIT_LIB_DISABLE_IOSTREAM DISABLE_PREDEFINED_UNITS ENABLE_PREDEFINED_DATA_UNITS ENABLE_PREDEFINED_ANGLE_UNITS ENABLE_PREDEFINED_TIME_UNITS ENABLE_PREDEFINED_ANGULAR_VELOCITY_UNITS ENABLE_PREDEFINED_FREQUENCY_UNITS ENABLE_PREDEFINED_VOLTAGE_UNITS ENABLE_PREDEFINED_POWER_UNITS ENABLE_PREDEFINED_TEMPERATURE_UNITS ENABLE_PREDEFINED_CONVERT_UNITS ENABLE_PREDEFINED_CONCENTRATION_UNITS ) # Allow pci.ids path customization using -DWITH_PCI_IDS_PATH= (#136) set(WITH_PCI_IDS_PATH "/usr/share/hwdata/pci.ids" CACHE FILEPATH "Path to pci.ids file") add_subdirectory(src) # Tests # # NOTE: CTest provides a BUILD_TESTING option set by default to ON. This setting # is useful for developers but not for most users, who will only waste time and # energy compiling the testing suite when -DBUILD_TESTING=OFF is omitted at # configuration time. # # Do not build the testing suite by default. include(CTest) option(BUILD_TESTING "Build the testing suite" OFF) if(BUILD_TESTING) enable_testing() add_subdirectory(tests) endif() # Icons string(TOLOWER "${PROJECT_NAME}" ICON_NAME) foreach(ICON_SIZE 16 22 24 32 48 64 72 96 128 192 256) install( FILES resources/icon/app_${ICON_SIZE}.svg DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/${ICON_SIZE}x${ICON_SIZE}/apps RENAME ${ICON_NAME}.svg ) endforeach() # .desktop file install( FILES resources/launcher.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/applications RENAME ${PROJECT_FQDN}.desktop ) # AppStream metadata configure_file(resources/appdata.xml.in resources/appdata.xml) install( FILES ${CMAKE_BINARY_DIR}/resources/appdata.xml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/metainfo RENAME ${PROJECT_FQDN}.appdata.xml ) corectrl-v1.4.2/CONTRIBUTING.md000066400000000000000000000054031467225065400157670ustar00rootroot00000000000000# Contributing CoreCtrl welcomes your contributions. ## Build instructions You can find the build instructions on the [wiki](https://gitlab.com/corectrl/corectrl/wikis/Installation). ## Issues writing guidelines Please, follow these guidelines to write your issues. Reported issues not following this guidelines may be closed as invalid. * One issue per report. * Be precise and clear. * Use the issue templates. * Use good descriptive titles for new issues. As first step, read the [FAQ](https://gitlab.com/corectrl/corectrl/wikis/FAQ) and [Known issues](https://gitlab.com/corectrl/corectrl/wikis/Known-issues). If your issue doesn't appear on them, search for similar issues on the issue tracker. If you find an already opened issue and you can provide new information, then add a new comment (please, do not write +1 o similar comments). If the issue is closed, open a new one and include a reference to the old one (for example, add 'Related to #'). ## Merge request Before starting to work on a merge request, please follow these instructions: 1. Open an issue explaining the reason for the change, state that you want to work on it and wait for the developers response. 2. Create a merge request from a **new branch** (do not create the MR from the master branch) and link it with the issue. The merge request must be focused on only one feature (a translation, a sensor, a control, ...). 3. Follow the [coding style](#coding-style) rules and make sure your code integrates well into the application architecture. 4. Make sure that all unit tests pass when you are working on existing controls. If you are working on a new control, you must write tests for it. 5. Commit your work on atomic unit of changes. For example, if you are working on a new sensor that requires the refactoring of an existing function, make a commit with the function refactor first and then make another commit with the sensor implementation (including all the new sensor related stuff, like translations and new utility functions and their tests). If you are unsure of how to do it, check the commit history for plenty of examples of such commits. 6. Explain the changes introduced by non straightforward commits on their commit message. 7. During the merge request, be concise on your comments and make sure that you fully understand what you are stating on them. Take your time and, when needed, do your research before posting. ## Coding style * Format your code with clang-format. You can do it with your editor or running `./format.sh` on the root project directory, then pick the formatted files that you are working on. * Use [east const](https://mariusbancila.ro/blog/2018/11/23/join-the-east-const-revolution/). * Use plain C++20 as much as possible. Don't use Qt functionality unless you have to. corectrl-v1.4.2/COPYING000066400000000000000000001045151467225065400145750ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 of the License, or (at your option) any later version. 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . corectrl-v1.4.2/LICENSE000066400000000000000000000004501467225065400145400ustar00rootroot00000000000000All CoreCtrl source files are licensed under the GNU General Public License. See the 'COPYING' file for details. Thirdparty project files from Easylogging++, {fmt}, pugixml, UNITS, Catch2 and Trompeloeil use their own license. See the accompanying LICENSE file of each project for more details. corectrl-v1.4.2/README.md000066400000000000000000000103451467225065400150160ustar00rootroot00000000000000# CoreCtrl [![CoreCtrl 1.0 overview video](https://gitlab.com/corectrl/corectrl/wikis/img/overview-1.0.png)](https://www.youtube.com/watch?v=6uchS6OiwiU) **CoreCtrl** is a Free and Open Source GNU/Linux application that allows you to control with ease your computer hardware using application profiles. It aims to be flexible, comfortable and accessible to regular users. There are already others GNU/Linux applications that allow you to control your hardware. *Some* of them are pretty good. *Most* of them are not built with regular users in mind and/or are focused on some specific hardware or features, so usually you end up with multiple control programs installed and running at the same time, each of them having its own specific configuration. Also, most of them do not respond to external events other that the hardware events they control so, if you want to change the behavior of the system for a given period of time, let's say, during one specific program execution, you have to manually interact with each control program in order to change its behavior, before and after that specific program execution. All of this is perceived by regular users as a big burden or even a barrier that impedes them to migrate to GNU/Linux for some specific tasks (as gaming). **CoreCtrl** aims to be a game changer in this particular field. You can use it to automatically configure your system when a program is launched (works for Windows applications too). It doesn't matter what the program is, a game, a 3D modeling application, a video editor or... even a compiler! It offers you full hardware control per application. The actual version of **CoreCtrl** automatically apply profiles for native and Windows applications, has basic CPU controls and full AMD GPUs controls (for both old and new models). The goal is to support as much hardware as possible, even from other vendors. Please, see [Future work](https://gitlab.com/corectrl/corectrl/wikis/home#future-work) for more details. ## Installation ### Distribution packages This list may contain unofficial distribution packages, maintained by other people not directly related with this proyect. Please report any problems you find in these packages to them. For security reasons, always be extra careful on what you install on your system. If you are suspicious about them, you can wait until you distribution packages CoreCtrl officially or you can install it from the [source code](https://gitlab.com/corectrl/corectrl/wikis/Installation). If you find something malicious on any of them, please open an issue so the list can be updated. #### Arch Linux pacman -S corectrl #### Fedora sudo dnf install corectrl #### Gentoo Add the [farmboy0](https://github.com/farmboy0/portage-overlay) overlay. Then run: emerge --ask --verbose kde-misc/corectrl #### openSUSE Install the [corectrl](https://software.opensuse.org/download.html?project=home%3ADead_Mozay&package=corectrl) package from OBS. #### Debian / Ubuntu sudo apt install corectrl If you are running an old version of Ubuntu that doesn't have corectrl in their repository, you can install it from the [`Ernst ppa-mesarc`](https://launchpad.net/~ernstp/+archive/ubuntu/mesarc) PPA. **WARNING:** This repository also hosts **release candidate and development versions** of many other packages. Notice that, by installing such packages, you can run into bugs that could break your system. Most users may only want to install `corectrl` from this PPA. If so, create the file `/etc/apt/preferences.d/corectrl` with the following content: # Never prefer packages from the ernstp repository Package: * Pin: release o=LP-PPA-ernstp-mesarc Pin-Priority: 1 # Allow upgrading only corectrl from LP-PPA-ernstp-mesarc Package: corectrl Pin: release o=LP-PPA-ernstp-mesarc Pin-Priority: 500 Then run: sudo apt install corectrl #### Others For other installation methods, see [Installation](https://gitlab.com/corectrl/corectrl/-/wikis/Installation). ## Setup It's **strongly recommended** to [setup your system](https://gitlab.com/corectrl/corectrl/-/wikis/Setup) for better user experience and to unlock **hidden hardware features**. ## More info Check the [Wiki](https://gitlab.com/corectrl/corectrl/wikis/home) for more useful info. corectrl-v1.4.2/cmake/000077500000000000000000000000001467225065400146145ustar00rootroot00000000000000corectrl-v1.4.2/cmake/CheckAtomic.cmake000066400000000000000000000062041467225065400177720ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2003-2018 University of Illinois at Urbana-Champaign. # # SPDX-License-Identifier: BSD-3-Clause #[=======================================================================[.rst: CheckAtomic ----------- Check if the compiler supports std:atomic out of the box or if libatomic is needed for atomic support. If it is needed, ``HAVE_CXX_ATOMICS_WITH_LIB`` or ``HAVE_CXX_ATOMICS64_WITH_LIB`` set to ``ON``. Since 5.75.0. #]=======================================================================] include(CheckCXXSourceCompiles) include(CheckLibraryExists) # Sometimes linking against libatomic is required for atomic ops, if # the platform doesn't support lock-free atomics. function(check_working_cxx_atomics varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") check_cxx_source_compiles(" #include std::atomic x; std::atomic y; std::atomic z; int main() { ++z; ++y; return ++x; } " ${varname}) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) endfunction() function(check_working_cxx_atomics64 varname) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") check_cxx_source_compiles(" #include #include std::atomic x (0); int main() { uint64_t i = x.load(std::memory_order_relaxed); x.is_lock_free(); return 0; } " ${varname}) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) endfunction() # Check for (non-64-bit) atomic operations. if(MSVC) set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) else() # First check if atomics work without the library. check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) # If not, check if the library exists, and atomics work with it. if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) if(HAVE_LIBATOMIC) list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) if (NOT HAVE_CXX_ATOMICS_WITH_LIB) message(FATAL_ERROR "Host compiler must support std::atomic!") endif() else() message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") endif() endif() endif() # Check for 64 bit atomic operations. if(MSVC) set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) else() # First check if atomics work without the library. check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) # If not, check if the library exists, and atomics work with it. if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64) if(HAVE_CXX_LIBATOMICS64) list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!") endif() else() message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.") endif() endif() endif() corectrl-v1.4.2/cmake/FindBotan.cmake000066400000000000000000000031521467225065400174630ustar00rootroot00000000000000# - Find botan # Find the botan cryptographic library # # This module defines the following variables: # Botan_FOUND - True if library and include directory are found # If set to TRUE, the following are also defined: # Botan_INCLUDE_DIRS - The directory where to find the header file # Botan_LIBRARIES - Where to find the library file # # For convenience, these variables are also set. They have the same values # than the variables above. The user can thus choose his/her preferred way # to write them. # Botan_LIBRARY # Botan_INCLUDE_DIR # # This file is in the public domain find_package(PkgConfig REQUIRED) macro(FIND_BOTAN_IN_FS BOTAN_VER) find_path(Botan_INCLUDE_DIRS NAMES botan/types.h PATH_SUFFIXES ${BOTAN_VER} DOC "The botan include directory") find_library(Botan_LIBRARIES NAMES botan ${BOTAN_VER} DOC "The botan library") # Use some standard module to handle the QUIETLY and REQUIRED arguments, and # set Botan_FOUND to TRUE if these two variables are set. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Botan REQUIRED_VARS Botan_LIBRARIES Botan_INCLUDE_DIRS) if(Botan_FOUND) set(Botan_LIBRARY ${Botan_LIBRARIES} CACHE INTERNAL "") set(Botan_INCLUDE_DIR ${Botan_INCLUDE_DIRS} CACHE INTERNAL "") set(Botan_FOUND ${Botan_FOUND} CACHE INTERNAL "") endif() endmacro() pkg_check_modules(Botan botan-3) if(NOT Botan_FOUND) find_botan_in_fs(botan-3) endif() if(NOT Botan_FOUND) pkg_check_modules(Botan botan-2) if(NOT Botan_FOUND) find_botan_in_fs(botan-2) endif() endif() mark_as_advanced(Botan_INCLUDE_DIRS Botan_LIBRARIES) corectrl-v1.4.2/cmake/cmake_uninstall.cmake.in000066400000000000000000000021331467225065400213730ustar00rootroot00000000000000# # From CMake FAQ: # https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake # if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) corectrl-v1.4.2/format.sh000077500000000000000000000003161467225065400153630ustar00rootroot00000000000000#!/bin/bash echo "Formatting code..." find . -type d -name 3rdparty -prune -o -type f \( -name "*\.h" -o -name "*\.cpp" \) -print0 | xargs -0 -I '{}' sh -c "clang-format -i {}; echo -n '.'" echo "Done." corectrl-v1.4.2/resources/000077500000000000000000000000001467225065400155465ustar00rootroot00000000000000corectrl-v1.4.2/resources/appdata.xml.in000066400000000000000000000021511467225065400203060ustar00rootroot00000000000000 @PROJECT_FQDN@ CC0 GPL-3.0-or-later @PROJECT_NAME@ A friendly hardware control

CoreCtrl is a Free and Open Source GNU/Linux application that allows you to control with ease your computer hardware using application profiles. It aims to be flexible, comfortable and accessible to regular users.

corectrl @PROJECT_HOMEPAGE_URL@/wikis/img/screenshot1.png Juan Palacios @PROJECT_HOMEPAGE_URL@ @PROJECT_HOMEPAGE_URL@/issues @PROJECT_HOMEPAGE_URL@/tree/master/src/translations @PROJECT_HOMEPAGE_URL@/wikis
corectrl-v1.4.2/resources/icon/000077500000000000000000000000001467225065400164765ustar00rootroot00000000000000corectrl-v1.4.2/resources/icon/app_128.svg000066400000000000000000000261261467225065400204000ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_16.svg000066400000000000000000000122201467225065400203020ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_192.svg000066400000000000000000000304041467225065400203730ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_22.svg000066400000000000000000000207371467225065400203130ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_24.svg000066400000000000000000000223061467225065400203070ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_256.svg000066400000000000000000000263761467225065400204110ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_32.svg000066400000000000000000000252111467225065400203040ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_48.svg000066400000000000000000000227161467225065400203220ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_64.svg000066400000000000000000000246121467225065400203150ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_72.svg000066400000000000000000000271241467225065400203150ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/icon/app_96.svg000066400000000000000000000264051467225065400203240ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/resources/launcher.desktop000077500000000000000000000015041467225065400207450ustar00rootroot00000000000000[Desktop Entry] Name=CoreCtrl GenericName=Core control Comment=Control your computer with ease using application profiles Exec=corectrl Icon=corectrl StartupNotify=true StartupWMClass=corectrl Terminal=false Type=Application Categories=System;Settings;Utility; Keywords=core;control;system;hardware; # Translations GenericName[bg]=Централен Контрол Comment[bg]=Управлявайте компютъра си с лекота, изполвайки профили за програмите ви GenericName[es_ES]=Control central Comment[es_ES]=Controle su computadora fácilmente usando perfiles de aplicaciones GenericName[ru]=Центральный контроль Comment[ru]=Управляйте своим оборудованием с легкостью, используя профили приложений corectrl-v1.4.2/src/000077500000000000000000000000001467225065400143235ustar00rootroot00000000000000corectrl-v1.4.2/src/CMakeLists.txt000066400000000000000000000416211467225065400170670ustar00rootroot00000000000000configure_file(config.h.in config.h) list(APPEND APP_COMPILE_DEFINITIONS ${3RDPARTY_DEFINITIONS} SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE ) list(APPEND COMMON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/common/fileutils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common/stringutils.cpp ) list(APPEND CRYPTO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/common/cryptolayer.cpp ) list(APPEND CORE_SRC core/filecache.cpp core/profileiconcache.cpp core/commandqueue.cpp core/sysmodel.cpp core/sysexplorer.cpp core/sysmodelfactory.cpp core/sysmodelsyncer.cpp core/session.cpp core/profileview.cpp core/profilepartview.cpp core/profileviewfactory.cpp core/profilestorage.cpp core/profilexmlparserfactory.cpp core/profilepartxmlparserprovider.cpp core/profilexmlparser.cpp core/profilepartxmlparser.cpp core/profilemanager.cpp core/profile.cpp core/profilepart.cpp core/profilepartprovider.cpp core/profilefactory.cpp core/ccpro/zipdatasource.cpp core/ccpro/zipdatasink.cpp core/ccpro/ccproparser.cpp core/info/cpuinfo.cpp core/info/gpuinfo.cpp core/info/swinfo.cpp core/info/hwiddatasource.cpp core/info/hwidtranslator.cpp core/components/commonutils.cpp core/components/cpuutils.cpp core/components/amdutils.cpp core/components/gpu.cpp core/components/gpuprofilepart.cpp core/components/gpuxmlparser.cpp core/components/cpu.cpp core/components/cpuprofilepart.cpp core/components/cpuxmlparser.cpp core/components/controls/control.cpp core/components/controls/controlmode.cpp core/components/controls/controlmodeprofilepart.cpp core/components/controls/controlmodexmlparser.cpp core/components/controls/controlgroup.cpp core/components/controls/controlgroupprofilepart.cpp core/components/controls/controlgroupxmlparser.cpp ) list(APPEND INFO_SRC core/info/infoproviderregistry.cpp core/info/common/cpuinfolscpu.cpp core/info/common/cpuinfoproccpuinfo.cpp core/info/common/gpuinfouevent.cpp core/info/common/gpuinforevision.cpp core/info/common/gpuinfoopengl.cpp core/info/common/gpuinfovulkan.cpp core/info/common/swinfokernel.cpp core/info/common/swinfomesa.cpp core/info/amd/gpuinfopm.cpp core/info/amd/gpuinfopmoverdrive.cpp core/info/amd/gpuinfovbios.cpp core/info/amd/gpuinfovram.cpp core/info/amd/gpuinfouniqueid.cpp core/info/amd/gpuinfoodfanctrl.cpp ) list(APPEND CONTROLS_SRC core/components/controls/noop.cpp core/components/controls/noopprofilepart.cpp core/components/controls/noopxmlparser.cpp core/components/controls/gpucontrolprovider.cpp core/components/controls/amd/pm/handlers/ppdpmhandler.cpp core/components/controls/amd/pm/pmperfmodeprovider.cpp core/components/controls/amd/pm/pmperfmodeprofilepart.cpp core/components/controls/amd/pm/pmperfmodexmlparser.cpp core/components/controls/amd/pm/auto/pmauto.cpp core/components/controls/amd/pm/auto/pmautolegacy.cpp core/components/controls/amd/pm/auto/pmautor600.cpp core/components/controls/amd/pm/auto/pmautoprovider.cpp core/components/controls/amd/pm/auto/pmautoprofilepart.cpp core/components/controls/amd/pm/auto/pmautoxmlparser.cpp core/components/controls/amd/pm/fixed/pmfixed.cpp core/components/controls/amd/pm/fixed/pmfixedlegacy.cpp core/components/controls/amd/pm/fixed/pmfixedr600.cpp core/components/controls/amd/pm/fixed/pmfixedprovider.cpp core/components/controls/amd/pm/fixed/pmfixedprofilepart.cpp core/components/controls/amd/pm/fixed/pmfixedxmlparser.cpp core/components/controls/amd/pm/advanced/pmadvancedprovider.cpp core/components/controls/amd/pm/advanced/pmadvancedprofilepart.cpp core/components/controls/amd/pm/advanced/pmadvancedxmlparser.cpp core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreq.cpp core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqprovider.cpp core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqprofilepart.cpp core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqxmlparser.cpp core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreq.cpp core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqprovider.cpp core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqadvprovider.cpp core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqprofilepart.cpp core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqxmlparser.cpp core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeprovider.cpp core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeprofilepart.cpp core/components/controls/amd/pm/advanced/freqmode/pmfreqmodexmlparser.cpp core/components/controls/amd/pm/advanced/overclock/pmoverclockprovider.cpp core/components/controls/amd/pm/advanced/overclock/pmoverclockprofilepart.cpp core/components/controls/amd/pm/advanced/overclock/pmoverclockxmlparser.cpp core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqod.cpp core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodprovider.cpp core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodprofilepart.cpp core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodxmlparser.cpp core/components/controls/amd/pm/advanced/overdrive/pmoverdrive.cpp core/components/controls/amd/pm/advanced/overdrive/pmoverdriveprovider.cpp core/components/controls/amd/pm/advanced/overdrive/pmoverdriveprofilepart.cpp core/components/controls/amd/pm/advanced/overdrive/pmoverdrivexmlparser.cpp core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvolt.cpp core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvoltprovider.cpp core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvoltprofilepart.cpp core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvoltxmlparser.cpp core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrange.cpp core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrangeprovider.cpp core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrangeprofilepart.cpp core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrangexmlparser.cpp core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurve.cpp core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurveprovider.cpp core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurveprofilepart.cpp core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurvexmlparser.cpp core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffset.cpp core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffsetprovider.cpp core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffsetprofilepart.cpp core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffsetxmlparser.cpp core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofile.cpp core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileprovider.cpp core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileprofilepart.cpp core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofilexmlparser.cpp core/components/controls/amd/pm/advanced/powercap/pmpowercap.cpp core/components/controls/amd/pm/advanced/powercap/pmpowercapprovider.cpp core/components/controls/amd/pm/advanced/powercap/pmpowercapprofilepart.cpp core/components/controls/amd/pm/advanced/powercap/pmpowercapxmlparser.cpp core/components/controls/amd/pm/powerstate/pmpowerstate.cpp core/components/controls/amd/pm/powerstate/pmpowerstateprovider.cpp core/components/controls/amd/pm/powerstate/pmpowerstateprofilepart.cpp core/components/controls/amd/pm/powerstate/pmpowerstatexmlparser.cpp core/components/controls/amd/pm/powerstate/pmpowerstatemodeprovider.cpp core/components/controls/amd/pm/powerstate/pmpowerstatemodeprofilepart.cpp core/components/controls/amd/pm/powerstate/pmpowerstatemodexmlparser.cpp core/components/controls/amd/fan/fanmodeprovider.cpp core/components/controls/amd/fan/fanmodeprofilepart.cpp core/components/controls/amd/fan/fanmodexmlparser.cpp core/components/controls/amd/fan/auto/fanauto.cpp core/components/controls/amd/fan/auto/fanautoprovider.cpp core/components/controls/amd/fan/auto/fanautoprofilepart.cpp core/components/controls/amd/fan/auto/fanautoxmlparser.cpp core/components/controls/amd/fan/fixed/fanfixed.cpp core/components/controls/amd/fan/fixed/fanfixedprovider.cpp core/components/controls/amd/fan/fixed/fanfixedprofilepart.cpp core/components/controls/amd/fan/fixed/fanfixedxmlparser.cpp core/components/controls/amd/fan/curve/fancurve.cpp core/components/controls/amd/fan/curve/fancurveprovider.cpp core/components/controls/amd/fan/curve/fancurveprofilepart.cpp core/components/controls/amd/fan/curve/fancurvexmlparser.cpp core/components/controls/amd/fan/overdrive/auto/odfanauto.cpp core/components/controls/amd/fan/overdrive/auto/odfanautoprovider.cpp core/components/controls/amd/fan/overdrive/auto/odfanautoprofilepart.cpp core/components/controls/amd/fan/overdrive/auto/odfanautoxmlparser.cpp core/components/controls/amd/fan/overdrive/curve/odfancurve.cpp core/components/controls/amd/fan/overdrive/curve/odfancurveprovider.cpp core/components/controls/amd/fan/overdrive/curve/odfancurveprofilepart.cpp core/components/controls/amd/fan/overdrive/curve/odfancurvexmlparser.cpp core/components/controls/cpucontrolprovider.cpp core/components/controls/cpu/cpufreq.cpp core/components/controls/cpu/cpufreqprovider.cpp core/components/controls/cpu/cpufreqprofilepart.cpp core/components/controls/cpu/cpufreqxmlparser.cpp core/components/controls/cpu/cpufreqmodeprovider.cpp core/components/controls/cpu/cpufreqmodeprofilepart.cpp core/components/controls/cpu/cpufreqmodexmlparser.cpp core/components/controls/cpu/handlers/epphandler.cpp ) list(APPEND SENSORS_SRC core/components/sensors/graphitemprofilepart.cpp core/components/sensors/graphitemxmlparser.cpp core/components/sensors/gpusensorprovider.cpp core/components/sensors/amd/gpufreq.cpp core/components/sensors/amd/memfreq.cpp core/components/sensors/amd/gputemp.cpp core/components/sensors/amd/junctiontemp.cpp core/components/sensors/amd/memorytemp.cpp core/components/sensors/amd/gpuvolt.cpp core/components/sensors/amd/power.cpp core/components/sensors/amd/activity.cpp core/components/sensors/amd/memusage.cpp core/components/sensors/amd/fanspeedrpm.cpp core/components/sensors/amd/fanspeedperc.cpp core/components/sensors/cpusensorprovider.cpp core/components/sensors/cpu/cpufreqpack.cpp core/components/sensors/cpu/cpuusage.cpp core/components/sensors/cpu/cpucoretemp.cpp ) list(APPEND UI_COMPONENTS_SRC core/uifactory.cpp core/qmlitem.cpp core/profilemanagerui.cpp core/systeminfoui.cpp core/qmlcomponentfactory.cpp core/qmlcomponentregistry.cpp core/sysmodelqmlitem.cpp core/components/gpuqmlitem.cpp core/components/cpuqmlitem.cpp core/components/sensors/graphitem.cpp core/components/sensors/amd/gpufreqgraphitem.cpp core/components/sensors/amd/memfreqgraphitem.cpp core/components/sensors/amd/gputempgraphitem.cpp core/components/sensors/amd/junctiontempgraphitem.cpp core/components/sensors/amd/memorytempgraphitem.cpp core/components/sensors/amd/gpuvoltgraphitem.cpp core/components/sensors/amd/powergraphitem.cpp core/components/sensors/amd/activitygraphitem.cpp core/components/sensors/amd/memusagegraphitem.cpp core/components/sensors/amd/fanspeedrpmgraphitem.cpp core/components/sensors/amd/fanspeedpercgraphitem.cpp core/components/sensors/cpu/cpufreqpackgraphitem.cpp core/components/sensors/cpu/cpuusagegraphitem.cpp core/components/sensors/cpu/cpucoretempgraphitem.cpp core/components/controls/controlmodeqmlitem.cpp core/components/controls/controlgroupqmlitem.cpp core/components/controls/noopqmlitem.cpp core/components/controls/amd/pm/pmperfmodeqmlitem.cpp core/components/controls/amd/pm/auto/pmautoqmlitem.cpp core/components/controls/amd/pm/fixed/pmfixedqmlitem.cpp core/components/controls/amd/pm/advanced/pmadvancedqmlitem.cpp core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqqmlitem.cpp core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqqmlitem.cpp core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeqmlitem.cpp core/components/controls/amd/pm/advanced/overclock/pmoverclockqmlitem.cpp core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodqmlitem.cpp core/components/controls/amd/pm/advanced/overdrive/pmoverdriveqmlitem.cpp core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvoltqmlitem.cpp core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrangeqmlitem.cpp core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurveqmlitem.cpp core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffsetqmlitem.cpp core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileqmlitem.cpp core/components/controls/amd/pm/advanced/powercap/pmpowercapqmlitem.cpp core/components/controls/amd/pm/powerstate/pmpowerstateqmlitem.cpp core/components/controls/amd/pm/powerstate/pmpowerstatemodeqmlitem.cpp core/components/controls/amd/fan/fanmodeqmlitem.cpp core/components/controls/amd/fan/auto/fanautoqmlitem.cpp core/components/controls/amd/fan/fixed/fanfixedqmlitem.cpp core/components/controls/amd/fan/curve/fancurveqmlitem.cpp core/components/controls/amd/fan/overdrive/auto/odfanautoqmlitem.cpp core/components/controls/amd/fan/overdrive/curve/odfancurveqmlitem.cpp core/components/controls/cpu/cpufreqqmlitem.cpp core/components/controls/cpu/cpufreqmodeqmlitem.cpp ) list(APPEND APP_SRC app/app.cpp app/appfactory.cpp app/settings.cpp app/singleinstance.cpp app/systray.cpp helper/helpercontrol.cpp helper/helpermonitor.cpp helper/helpersysctl.cpp ) list (APPEND TRANSLATABLE_FILES ${UI_COMPONENTS_SRC} app/systray.cpp qml/main.qml qml/ProfileButton.qml qml/ProfileInfoDialog.qml qml/FVControl.qml qml/FreqStateControl.qml qml/Profiles.qml qml/System.qml qml/About.qml qml/SettingsDialog.qml qml/SettingsGeneral.qml qml/SettingsWorkarounds.qml qml/SysModelForm.qml qml/CPUForm.qml qml/GPUForm.qml qml/SensorGraph.qml qml/NoopForm.qml qml/AMDPMPerfModeForm.qml qml/AMDPMAutoForm.qml qml/AMDPMFixedForm.qml qml/AMDPMAdvancedForm.qml qml/AMDPMDynamicFreqForm.qml qml/AMDPMFixedFreqForm.qml qml/AMDPMFreqModeForm.qml qml/AMDPMOverclockForm.qml qml/AMDPMFreqVoltForm.qml qml/AMDPMFreqRangeForm.qml qml/AMDPMVoltCurveForm.qml qml/AMDPMVoltOffsetForm.qml qml/AMDPMFreqOdForm.qml qml/AMDPMPowerProfileForm.qml qml/AMDPMPowerCapForm.qml qml/AMDPMPowerStateForm.qml qml/AMDPMPowerStateModeForm.qml qml/AMDFanModeForm.qml qml/AMDFanAutoForm.qml qml/AMDFanFixedForm.qml qml/AMDFanCurveForm.qml qml/AMDOdFanAutoForm.qml qml/AMDOdFanCurveForm.qml qml/CPUFreqForm.qml qml/CPUFreqModeForm.qml ) list(APPEND TRANSLATIONS translations/lang_en_EN.ts translations/lang_es_ES.ts translations/lang_ru_RU.ts translations/lang_fr_FR.ts translations/lang_ca_ES.ts translations/lang_bg_BG.ts translations/lang_cs_CZ.ts translations/lang_nl_NL.ts translations/lang_de_DE.ts translations/lang_sv_SE.ts ) set_source_files_properties(${TRANSLATIONS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/translations ) option (UPDATE_TRANSLATIONS "Update translation files" OFF) if (UPDATE_TRANSLATIONS) qt5_create_translation(QM_FILES ${TRANSLATABLE_FILES} ${TRANSLATIONS} OPTIONS -noobsolete) else (UPDATE_TRANSLATIONS) qt5_add_translation(QM_FILES ${TRANSLATIONS}) endif (UPDATE_TRANSLATIONS) add_custom_target(translations DEPENDS ${QM_FILES}) qt5_add_resources(CPP_QRC resources.qrc) set(CMAKE_AUTOMOC ON) add_library(corectrl_lib SHARED ${3RDPARTY_SRC} ${COMMON_SRC} ${CORE_SRC} ${INFO_SRC} ${CONTROLS_SRC} ${SENSORS_SRC} ) set(CMAKE_AUTOMOC OFF) target_include_directories(corectrl_lib PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${3RDPARTY_INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR} ) target_compile_definitions(corectrl_lib PRIVATE ${APP_COMPILE_DEFINITIONS}) target_link_libraries(corectrl_lib PRIVATE Qt5::Core QuaZip::QuaZip stdc++fs pthread spdlog::spdlog pugixml::pugixml $<$:units::units> ${ATOMIC_LIB} ) set_target_properties(corectrl_lib PROPERTIES OUTPUT_NAME corectrl) set(CMAKE_AUTOMOC ON) add_executable(corectrl main.cpp ${CRYPTO_SRC} ${UI_COMPONENTS_SRC} ${APP_SRC} ${CPP_QRC} ${QM_FILES} ) set(CMAKE_AUTOMOC OFF) target_include_directories(corectrl PRIVATE ${3RDPARTY_INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR} ${Botan_INCLUDE_DIRS} ) target_compile_definitions(corectrl PRIVATE ${APP_COMPILE_DEFINITIONS}) target_link_libraries(corectrl PRIVATE corectrl_lib Qt5::Core Qt5::Quick Qt5::Charts Qt5::Widgets Qt5::Network Qt5::DBus spdlog::spdlog ${Botan_LIBRARIES} ${ATOMIC_LIB} ) install( TARGETS corectrl corectrl_lib RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} ) add_subdirectory(helper) corectrl-v1.4.2/src/app/000077500000000000000000000000001467225065400151035ustar00rootroot00000000000000corectrl-v1.4.2/src/app/app.cpp000066400000000000000000000277221467225065400164010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "app.h" #include "common/stringutils.h" #include "core/isession.h" #include "core/isysmodelsyncer.h" #include "core/iuifactory.h" #include "helper/ihelpercontrol.h" #include "settings.h" #include "systray.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_DEBUG) #include #endif App::App(std::unique_ptr &&helperControl, std::shared_ptr sysSyncer, std::unique_ptr &&session, std::unique_ptr &&uiFactory) noexcept : QObject() , appInfo_(App::Name, App::VersionStr) , singleInstance_(App::Name) , helperControl_(std::move(helperControl)) , sysSyncer_(std::move(sysSyncer)) , session_(std::move(session)) , uiFactory_(std::move(uiFactory)) { } App::~App() = default; int App::exec(int argc, char **argv) { QCoreApplication::setApplicationName(QString(App::Name.data()).toLower()); QCoreApplication::setApplicationVersion(App::VersionStr.data()); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QGuiApplication::setDesktopFileName(QString(App::Fqdn.data())); // Ignore QT_STYLE_OVERRIDE. It breaks the qml theme. if (qEnvironmentVariableIsSet("QT_STYLE_OVERRIDE")) { SPDLOG_INFO("Ignoring QT_STYLE_OVERRIDE environment variable."); qunsetenv("QT_STYLE_OVERRIDE"); } QApplication app(argc, argv); #if defined(_DEBUG) QQmlDebuggingEnabler enabler; #endif int const minHelperTimeout = helperControl_->minExitTimeout().to(); int const helperTimeout{std::max(180000, // default helper timeout in milliseconds minHelperTimeout)}; setupCmdParser(cmdParser_, minHelperTimeout, helperTimeout); cmdParser_.process(app); // exit if there is another instance running if (!singleInstance_.mainInstance(app.arguments())) return 0; noop_ = cmdParser_.isSet("help") || cmdParser_.isSet("version"); if (noop_) return 0; QString lang = cmdParser_.isSet("lang") ? cmdParser_.value("lang") : QLocale().system().name(); QTranslator translator; if (!translator.load(QStringLiteral(":/translations/lang_") + lang)) { SPDLOG_INFO("No translation found for locale {}", lang.toStdString()); SPDLOG_INFO("Using en_EN translation."); if (!translator.load(QStringLiteral(":/translations/lang_en_EN"))) SPDLOG_ERROR("Cannot load en_EN translation."); } app.installTranslator(&translator); app.setWindowIcon(QIcon::fromTheme(QString(App::Name.data()).toLower())); // Ensure that the application do not implicitly call to quit after closing // the last window, which is not the desired behaviour when minimize to // system tray is being used. app.setQuitOnLastWindowClosed(false); try { settings_ = std::make_unique(QString(App::Name.data()).toLower()); int timeoutValue = helperTimeout; if (cmdParser_.isSet("helper-timeout") && Utils::String::toNumber( timeoutValue, cmdParser_.value("helper-timeout").toStdString())) { timeoutValue = std::max(helperControl_->minExitTimeout().to(), timeoutValue); } helperControl_->init(units::time::millisecond_t(timeoutValue)); sysSyncer_->init(); session_->init(sysSyncer_->sysModel()); QQmlApplicationEngine qmlEngine; buildUI(qmlEngine); // Load and apply stored settings settings_->signalSettings(); initSysTrayWindowState(); handleToggleManualProfileCmd(); return app.exec(); } catch (std::exception const &e) { SPDLOG_WARN(e.what()); SPDLOG_WARN("Initialization failed"); SPDLOG_WARN("Exiting..."); return -1; } return 0; } void App::exit() { if (!noop_) { sysSyncer_->stop(); helperControl_->stop(); // Shutdown spdlog before QApplication quits to always flush the logs. // See: https://github.com/gabime/spdlog/issues/2502 spdlog::shutdown(); } } void App::showMainWindow(bool show) { if (show) { mainWindow_->show(); mainWindow_->raise(); mainWindow_->requestActivate(); } else { if (sysTray_->isVisible()) mainWindow_->hide(); else mainWindow_->showMinimized(); } } void App::onNewInstance(QStringList args) { cmdParser_.parse(args); bool runtimeCmds{false}; runtimeCmds |= handleToggleManualProfileCmd(); runtimeCmds |= handleWindowVisibilityCmds(); // No runtime commands were used as arguments. // Show the main window unconditionally. if (!runtimeCmds) showMainWindow(true); } void App::onSysTrayActivated() { showMainWindow(!mainWindow_->isVisible()); } void App::onSettingChanged(QString const &key, QVariant const &value) { sysTray_->settingChanged(key, value); sysSyncer_->settingChanged(key, value); } void App::initSysTrayWindowState() { bool minimizeArgIsSet = cmdParser_.isSet("minimize-systray"); bool enableSysTray = settings_->getValue("sysTray", true).toBool(); if (minimizeArgIsSet || enableSysTray) sysTray_->show(); bool startOnSysTray = settings_->getValue("startOnSysTray", false).toBool(); bool showWindow = !minimizeArgIsSet && !(sysTray_->isAvailable() && enableSysTray && startOnSysTray); showMainWindow(showWindow); } void App::setupCmdParser(QCommandLineParser &parser, int minHelperTimeout, int helperTimeout) const { parser.addHelpOption(); parser.addVersionOption(); parser.addOptions({ {{"l", "lang"}, "Forces a specific , given in locale format. Example: " "en_EN.", "language"}, {{"m", "toggle-manual-profile"}, "Activate the manual profile whose name is <\"profile name\">.\nWhen an " "instance of the application is already running, it will toggle " "the manual profile whose name is <\"profile name\">.", "\"profile name\""}, {"minimize-systray", "Minimizes the main window either to the system tray (when " "available) or to the taskbar.\nWhen an instance of the application is " "already running, the action will be applied to its main window."}, {{"t", "helper-timeout"}, "Sets helper auto exit timeout. " "The helper process kills himself when no signals are received from " "the application before the timeout expires.\nValues lesser than " + QString::number(minHelperTimeout) + +" milliseconds will be ignored.\nDefault value: " + QString::number(helperTimeout) + " milliseconds.", "milliseconds"}, {"toggle-window-visibility", "When an instance of the application is already running, it will toggle " "the main window visibility showing or minimizing it, either to the " "taskbar or to system tray."}, }); } void App::buildUI(QQmlApplicationEngine &qmlEngine) { qmlEngine.rootContext()->setContextProperty("appInfo", &appInfo_); qmlEngine.rootContext()->setContextProperty("settings", &*settings_); uiFactory_->build(qmlEngine, sysSyncer_->sysModel(), *session_); mainWindow_ = qobject_cast(qmlEngine.rootObjects().value(0)); setupMainWindowGeometry(); connect(&qmlEngine, &QQmlApplicationEngine::quit, QApplication::instance(), &QApplication::quit); connect(QApplication::instance(), &QApplication::aboutToQuit, this, &App::exit); connect(&*settings_, &Settings::settingChanged, this, &App::onSettingChanged); connect(&singleInstance_, &SingleInstance::newInstance, this, &App::onNewInstance); sysTray_ = new SysTray(&*session_, mainWindow_); connect(sysTray_, &SysTray::quit, this, &QApplication::quit); connect(sysTray_, &SysTray::activated, this, &App::onSysTrayActivated); connect(sysTray_, &SysTray::showMainWindowToggled, this, &App::showMainWindow); connect(mainWindow_, &QQuickWindow::visibleChanged, &*sysTray_, &SysTray::onMainWindowVisibleChanged); qmlEngine.rootContext()->setContextProperty("systemTray", sysTray_); } void App::setupMainWindowGeometry() { restoreMainWindowGeometry(); // The geometry save timer is used to reduce the window geometry changed // events fired within a time interval into a single event that will save the // window geometry. geometrySaveTimer_.setInterval(2000); geometrySaveTimer_.setSingleShot(true); connect(&geometrySaveTimer_, &QTimer::timeout, this, &App::saveMainWindowGeometry); connect(mainWindow_, &QWindow::heightChanged, this, [&](int) { geometrySaveTimer_.start(); }); connect(mainWindow_, &QWindow::widthChanged, this, [&](int) { geometrySaveTimer_.start(); }); connect(mainWindow_, &QWindow::xChanged, this, [&](int) { geometrySaveTimer_.start(); }); connect(mainWindow_, &QWindow::yChanged, this, [&](int) { geometrySaveTimer_.start(); }); } void App::saveMainWindowGeometry() { if (!settings_->getValue("saveWindowGeometry", true).toBool()) return; if (mainWindow_ == nullptr) return; auto windowGeometry = mainWindow_->geometry(); auto savedXPos = settings_->getValue("Window/main-x-pos", DefaultWindowGeometry.x()).toInt(); if (savedXPos != windowGeometry.x()) settings_->setValue("Window/main-x-pos", windowGeometry.x()); auto savedYPos = settings_->getValue("Window/main-y-pos", DefaultWindowGeometry.y()).toInt(); if (savedYPos != windowGeometry.y()) settings_->setValue("Window/main-y-pos", windowGeometry.y()); auto savedWidth = settings_->getValue("Window/main-width", DefaultWindowGeometry.width()) .toInt(); if (savedWidth != windowGeometry.width()) settings_->setValue("Window/main-width", windowGeometry.width()); auto savedHeight = settings_->getValue("Window/main-height", DefaultWindowGeometry.height()) .toInt(); if (savedHeight != windowGeometry.height()) settings_->setValue("Window/main-height", windowGeometry.height()); } void App::restoreMainWindowGeometry() { if (mainWindow_ == nullptr) return; auto x = settings_->getValue("Window/main-x-pos", DefaultWindowGeometry.x()).toInt(); auto y = settings_->getValue("Window/main-y-pos", DefaultWindowGeometry.y()).toInt(); auto width = settings_->getValue("Window/main-width", DefaultWindowGeometry.width()) .toInt(); auto height = settings_->getValue("Window/main-height", DefaultWindowGeometry.height()) .toInt(); mainWindow_->setGeometry(x, y, width, height); } bool App::handleToggleManualProfileCmd() { auto cmdHandled{false}; if (cmdParser_.isSet("toggle-manual-profile")) { auto profileName = cmdParser_.value("toggle-manual-profile").toStdString(); if (profileName.empty() || profileName.length() >= 512) SPDLOG_WARN("'{}' is not a valid manual profile name.", profileName); else if (!session_->toggleManualProfile(profileName)) SPDLOG_WARN("Cannot toggle manual profile '{}': Missing profile or not a " "manual profile.", profileName); cmdHandled = true; } return cmdHandled; } bool App::handleWindowVisibilityCmds() { auto cmdHandled{false}; auto show{false}; // Minimize to system tray takes precedence over any other window visibility // command. if (cmdParser_.isSet("minimize-systray")) { cmdHandled = true; } else if (cmdParser_.isSet("toggle-window-visibility")) { // When the window is minimized, calling show() will raise it. auto minimized = ((mainWindow_->windowState() & Qt::WindowState::WindowMinimized) == Qt::WindowState::WindowMinimized); show = minimized ? true : !mainWindow_->isVisible(); cmdHandled = true; } if (cmdHandled) showMainWindow(show); return cmdHandled; } corectrl-v1.4.2/src/app/app.h000066400000000000000000000050421467225065400160350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "config.h" #include "singleinstance.h" #include #include #include #include #include #include #include #include #include class IHelperControl; class ISession; class ISysModelSyncer; class IUIFactory; class QQmlApplicationEngine; class QQuickWindow; class Settings; class SysTray; class AppInfo final : public QObject { Q_OBJECT Q_PROPERTY(QString name READ getName CONSTANT) Q_PROPERTY(QString version READ getVersion CONSTANT) public: AppInfo(std::string_view appName, std::string_view appVersion) noexcept : QObject() , name_(appName.data()) , version_(appVersion.data()) { } QString const &getName() const { return name_; } QString const &getVersion() const { return version_; } private: QString const name_; QString const version_; }; class App final : public QObject { Q_OBJECT public: static constexpr std::string_view Name{PROJECT_NAME}; static constexpr std::string_view VersionStr{PROJECT_VERSION}; static constexpr std::string_view Fqdn{PROJECT_FQDN}; static constexpr QRect DefaultWindowGeometry{0, 0, 970, 600}; App(std::unique_ptr &&helperControl, std::shared_ptr sysSyncer, std::unique_ptr &&session, std::unique_ptr &&uiFactory) noexcept; ~App(); int exec(int argc, char **argv); private slots: void exit(); void showMainWindow(bool show); void onNewInstance(QStringList args); void onSysTrayActivated(); void onSettingChanged(QString const &key, QVariant const &value); void saveMainWindowGeometry(); private: void initSysTrayWindowState(); void setupCmdParser(QCommandLineParser &parser, int minHelperTimeout, int helperTimeout) const; void buildUI(QQmlApplicationEngine &qmlEngine); void setupMainWindowGeometry(); void restoreMainWindowGeometry(); bool handleToggleManualProfileCmd(); bool handleWindowVisibilityCmds(); AppInfo appInfo_; SingleInstance singleInstance_; QCommandLineParser cmdParser_; QTimer geometrySaveTimer_; std::unique_ptr helperControl_; std::shared_ptr sysSyncer_; std::unique_ptr session_; std::unique_ptr uiFactory_; std::unique_ptr settings_; bool noop_{false}; QQuickWindow *mainWindow_{nullptr}; SysTray *sysTray_{nullptr}; }; corectrl-v1.4.2/src/app/appfactory.cpp000066400000000000000000000145561467225065400177720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "appfactory.h" #include "app.h" #include "common/cryptolayer.h" #include "config.h" #include "core/ccpro/ccproparser.h" #include "core/components/controls/cpucontrolprovider.h" #include "core/components/controls/gpucontrolprovider.h" #include "core/components/sensors/cpusensorprovider.h" #include "core/components/sensors/gpusensorprovider.h" #include "core/filecache.h" #include "core/info/hwiddatasource.h" #include "core/info/hwidtranslator.h" #include "core/info/infoproviderregistry.h" #include "core/info/swinfo.h" #include "core/iprofileparser.h" #include "core/profile.h" #include "core/profilefactory.h" #include "core/profileiconcache.h" #include "core/profilemanager.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/profilestorage.h" #include "core/profileviewfactory.h" #include "core/profilexmlparserfactory.h" #include "core/qmlcomponentfactory.h" #include "core/qmlcomponentregistry.h" #include "core/session.h" #include "core/sysexplorer.h" #include "core/sysmodelfactory.h" #include "core/sysmodelsyncer.h" #include "core/uifactory.h" #include "helper/helpercontrol.h" #include "helper/helpermonitor.h" #include "helper/helpersysctl.h" #include #include #include #include #include #include #include #include namespace fs = std::filesystem; AppFactory::AppFactory() noexcept : gpuVendors_{Vendor::AMD} { } std::unique_ptr AppFactory::build() const { try { std::string appName(App::Name); std::transform(appName.cbegin(), appName.cend(), appName.begin(), ::tolower); auto [config, cache] = standardDirectories(); createAppDirectories(appName, config, cache); auto cryptoLayer = std::make_shared(); auto helperControl = std::make_unique(cryptoLayer); InfoProviderRegistry infoProviderRegistry; auto swInfo = std::make_unique(); swInfo->initialize(infoProviderRegistry.swInfoProviders()); SysModelFactory sysModelFactory( std::move(swInfo), std::make_unique(gpuVendors_), std::make_unique( gpuVendors_, std::make_unique(PCI_IDS_PATH)), std::make_unique(), std::make_unique(), std::make_unique(), std::make_unique(), infoProviderRegistry, infoProviderRegistry); auto sysModel = sysModelFactory.build(); ProfileFactory profileFactory(std::make_unique()); auto defaultProfile = profileFactory.build(*sysModel); ProfileXMLParserFactory parserFactory( std::make_unique()); auto profileParser = parserFactory.build(*defaultProfile); auto profileFileParser = std::make_unique(); auto iconCache = std::make_unique( std::make_unique(cache / appName / "icons")); auto profileManager = std::make_unique( std::move(defaultProfile), std::make_unique( config / appName / "profiles", std::move(profileParser), std::move(profileFileParser), std::move(iconCache))); auto sysModelSyncer = std::make_shared( std::move(sysModel), std::make_unique(cryptoLayer)); auto session = std::make_unique( sysModelSyncer, std::move(profileManager), std::make_unique(), std::make_unique(cryptoLayer)); auto uiFactory = std::make_unique(std::make_unique( std::make_unique())); return std::make_unique(std::move(helperControl), std::move(sysModelSyncer), std::move(session), std::move(uiFactory)); } catch (std::exception const &e) { SPDLOG_WARN("Cannot create main application"); SPDLOG_WARN(e.what()); } return nullptr; } std::tuple AppFactory::standardDirectories() const { return {QStandardPaths::standardLocations(QStandardPaths::ConfigLocation) .first() .toStdString(), QStandardPaths::standardLocations(QStandardPaths::CacheLocation) .first() .toStdString()}; } void AppFactory::createAppDirectories(std::string const &appDirectory, std::filesystem::path const &config, std::filesystem::path const &cache) const { std::error_code ec; fs::perms dirPerms = fs::perms::owner_all | fs::perms::group_read | fs::perms::group_exec | fs::perms::others_read | fs::perms::others_exec; if (!fs::exists(config)) { fs::create_directory(config); fs::permissions(config, dirPerms, ec); if (ec.value() != 0) SPDLOG_DEBUG("Cannot set permissions for {}", config.c_str()); } if (!fs::is_directory(config)) throw std::runtime_error( std::format("{} is not a directory", config.c_str())); fs::path appConfigDir = config / appDirectory; if (!fs::exists(appConfigDir)) { fs::create_directory(appConfigDir); fs::permissions(appConfigDir, dirPerms, ec); if (ec.value() != 0) SPDLOG_DEBUG("Cannot set permissions for {}", appConfigDir.c_str()); } if (!fs::is_directory(appConfigDir)) throw std::runtime_error( std::format("{} is not a directory", appConfigDir.c_str())); if (!fs::exists(cache)) { fs::create_directory(cache); fs::permissions(cache, dirPerms, ec); if (ec.value() != 0) SPDLOG_DEBUG("Cannot set permissions for {}", cache.c_str()); } if (!fs::is_directory(cache)) throw std::runtime_error(std::format("{} is not a directory", cache.c_str())); fs::path cacheApp = cache / appDirectory; if (!fs::exists(cacheApp)) { fs::create_directory(cacheApp); fs::permissions(cacheApp, dirPerms, ec); if (ec.value() != 0) SPDLOG_DEBUG("Cannot set permissions for {}", cacheApp.c_str()); } if (!fs::is_directory(cacheApp)) throw std::runtime_error( std::format("{} is not a directory", cacheApp.c_str())); } corectrl-v1.4.2/src/app/appfactory.h000066400000000000000000000012601467225065400174230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/info/vendor.h" #include #include #include #include #include class App; class AppFactory final { public: AppFactory() noexcept; std::unique_ptr build() const; private: std::tuple standardDirectories() const; void createAppDirectories(std::string const &appDirectory, std::filesystem::path const &config, std::filesystem::path const &cache) const; std::vector gpuVendors_; }; corectrl-v1.4.2/src/app/settings.cpp000066400000000000000000000022421467225065400174470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "settings.h" Settings::Settings(QString const &appName) noexcept : QSettings(QSettings::IniFormat, QSettings::UserScope, appName, appName) { } void Settings::setValue(QString const &key, QVariant const &value) { QSettings::setValue(key, value); emit settingChanged(key, value); } QVariant Settings::getValue(QString const &key, QVariant const &defaultValue) const { auto value = QSettings::value(key, defaultValue); value.convert(static_cast(defaultValue.type())); return value; } void Settings::setStringList(QString const &key, QStringList const &list) { if (list.empty()) QSettings::remove(key); else QSettings::setValue(key, list); emit settingChanged(key, list); } QVariant Settings::getStringList(QString const &key, QStringList const &defaultValue) const { auto value = QSettings::value(key, defaultValue); return value.toStringList(); } void Settings::signalSettings() { auto keys = QSettings::allKeys(); for (auto const &key : keys) emit settingChanged(key, QSettings::value(key)); } corectrl-v1.4.2/src/app/settings.h000066400000000000000000000015111467225065400171120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include class Settings final : public QSettings { Q_OBJECT public: Settings(QString const &appName) noexcept; Q_INVOKABLE void setValue(QString const &key, QVariant const &value); Q_INVOKABLE QVariant getValue(QString const &key, QVariant const &defaultValue) const; Q_INVOKABLE void setStringList(QString const &key, QStringList const &list); Q_INVOKABLE QVariant getStringList(QString const &key, QStringList const &defaultList) const; void signalSettings(); signals: void settingChanged(QString const &key, QVariant const &value); }; corectrl-v1.4.2/src/app/singleinstance.cpp000066400000000000000000000037171467225065400206250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "singleinstance.h" SingleInstanceClient::SingleInstanceClient(QLocalSocket *client) : QObject(client) { connect(client, &QLocalSocket::readyRead, this, &SingleInstanceClient::onReadyRead); connect(client, &QLocalSocket::disconnected, this, &SingleInstanceClient::onDisconnected); connect(client, &QLocalSocket::disconnected, client, &QLocalSocket::deleteLater); } void SingleInstanceClient::onReadyRead() { QLocalSocket *client = qobject_cast(parent()); args_ = fromRawData(client->readAll()); } void SingleInstanceClient::onDisconnected() { emit newInstance(args_); } QStringList SingleInstanceClient::fromRawData(QByteArray const &data) const { QStringList result; auto dataList = data.split('\0'); for (auto const &rawData : dataList) result.push_back(QString::fromUtf8(rawData)); return result; } SingleInstance::SingleInstance(std::string_view name, QObject *parent) : QObject(parent) , name_(name.data()) { connect(&server_, &QLocalServer::newConnection, this, &SingleInstance::newConnection); } bool SingleInstance::mainInstance(QStringList const &args) { QLocalSocket socket; socket.connectToServer(name_, QLocalSocket::WriteOnly); if (socket.waitForConnected(100)) { socket.write(toRawData(args)); socket.flush(); socket.disconnectFromServer(); return false; } server_.removeServer(name_); server_.listen(name_); return true; } void SingleInstance::newConnection() { auto client = new SingleInstanceClient(server_.nextPendingConnection()); connect(client, &SingleInstanceClient::newInstance, this, &SingleInstance::newInstance); } QByteArray SingleInstance::toRawData(QStringList const &data) const { QByteArray result; for (auto const &item : data) { result.append(item.toUtf8()); result.append('\0'); } return result; } corectrl-v1.4.2/src/app/singleinstance.h000066400000000000000000000017171467225065400202700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include #include class SingleInstance : public QObject { Q_OBJECT public: explicit SingleInstance(std::string_view name, QObject *parent = 0); bool mainInstance(QStringList const &args); signals: void newInstance(QStringList args); private slots: void newConnection(); private: QByteArray toRawData(QStringList const &data) const; QString const name_; QLocalServer server_; }; class SingleInstanceClient : public QObject { Q_OBJECT public: SingleInstanceClient(QLocalSocket *client); signals: void newInstance(QStringList args); public slots: void onReadyRead(); void onDisconnected(); private: QStringList fromRawData(QByteArray const &data) const; QStringList args_; }; corectrl-v1.4.2/src/app/systray.cpp000066400000000000000000000204421467225065400173270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "systray.h" #include "app.h" #include "core/iprofile.h" #include "core/iprofilemanager.h" #include "core/isession.h" #include #include #include class SysTray::ProfileManagerObserver : public IProfileManager::Observer { public: ProfileManagerObserver(SysTray &outer) noexcept : outer_(outer) { } void profileAdded(std::string const &profileName) override; void profileRemoved(std::string const &profileName) override; void profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) override; void profileChanged(std::string const &) override { } void profileActiveChanged(std::string const &, bool) override { } void profileSaved(std::string const &) override { } private: SysTray &outer_; }; void SysTray::ProfileManagerObserver::profileAdded(std::string const &profileName) { outer_.profileAdded(profileName); } void SysTray::ProfileManagerObserver::profileRemoved(std::string const &profileName) { outer_.profileRemoved(profileName); } void SysTray::ProfileManagerObserver::profileInfoChanged( IProfile::Info const &oldInfo, IProfile::Info const &newInfo) { outer_.profileInfoChanged(oldInfo, newInfo); } class SysTray::ManualProfileObserver : public ISession::ManualProfileObserver { public: ManualProfileObserver(SysTray &outer) noexcept : outer_(outer) { } void toggled(std::string const &profileName, bool active) override; private: SysTray &outer_; }; void SysTray::ManualProfileObserver::toggled(const std::string &profileName, bool active) { outer_.manualProfileToggled(profileName, active); } SysTray::SysTray(ISession *session, QObject *parent) : QObject(parent) , session_(session) , profileManager_(&session->profileManager()) , menu_() , profileManagerObserver_( std::make_shared(*this)) , manualProfileObserver_(std::make_shared(*this)) { session_->addManualProfileObserver(manualProfileObserver_); profileManager_->addObserver(profileManagerObserver_); sysTray_ = createSystemTrayIcon(); } bool SysTray::isAvailable() const { return QSystemTrayIcon::isSystemTrayAvailable(); } bool SysTray::isVisible() const { return isAvailable() && sysTray_->isVisible(); } void SysTray::show() { sysTray_->show(); } void SysTray::hide() { sysTray_->hide(); } void SysTray::settingChanged(QString const &key, QVariant const &value) { if (key == "sysTray") sysTray_->setVisible(value.toBool()); } void SysTray::onMainWindowVisibleChanged(bool isVisible) { showMainWindow_ = isVisible; showMainWindowAction_->setText(isVisible ? tr("Hide") : tr("Show")); } void SysTray::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason) { case QSystemTrayIcon::Trigger: emit activated(); break; default: break; } } void SysTray::onShowMainWindowActionTriggered() { emit showMainWindowToggled(!showMainWindow_); } QSystemTrayIcon *SysTray::createSystemTrayIcon() { auto sysTray = new QSystemTrayIcon(this); sysTray->setIcon(QIcon::fromTheme(QString(App::Name.data()).toLower())); sysTray->setContextMenu(menu()); connect(sysTray, &QSystemTrayIcon::activated, this, &SysTray::onTrayIconActivated); return sysTray; } QMenu *SysTray::menu() { if (menu_.isEmpty()) { showMainWindowAction_ = new QAction(&menu_); onMainWindowVisibleChanged(false); // initialize label and state connect(showMainWindowAction_, &QAction::triggered, this, &SysTray::onShowMainWindowActionTriggered); menu_.addAction(showMainWindowAction_); menu_.addSeparator(); manualProfileMenu_ = menu_.addMenu(tr("Manual profiles")); addManualProfilesTo(manualProfileMenu_); menu_.addSeparator(); QAction *quitAction = new QAction(tr("Quit"), &menu_); connect(quitAction, &QAction::triggered, this, &SysTray::quit); menu_.addAction(quitAction); } return &menu_; } QAction *SysTray::createManualProfileAction(QMenu *menu, std::string const &profileName) { QAction *action = new QAction(QString::fromStdString(profileName), menu); action->setCheckable(true); connect(action, &QAction::triggered, this, [=, this]() { onManualProfileMenuTriggered(action->text()); }); return action; } std::optional SysTray::findManualProfileAction(std::string const &profileName) { auto name = QString::fromStdString(profileName); auto actions = manualProfileMenu_->actions(); auto actionIt = std::find_if( actions.begin(), actions.end(), [&](QAction *action) { return action->text() == name; }); return actionIt != actions.end() ? std::make_optional(*actionIt) : std::nullopt; } QAction * SysTray::findNextManualProfileActionPosition(std::string const &profileName) { auto name = QString::fromStdString(profileName); auto actions = manualProfileMenu_->actions(); auto actionIt = std::find_if( actions.begin(), actions.end(), [&](QAction *action) { return action->text() > name; }); return actionIt != actions.end() ? *actionIt : nullptr; } void SysTray::addManualProfilesTo(QMenu *menu) { auto profiles = profileManager_->profiles(); std::sort(profiles.begin(), profiles.end()); for (auto const &profileName : profiles) { auto const &profile = profileManager_->profile(profileName); if (profile->get().info().exe == IProfile::Info::ManualID) { auto action = createManualProfileAction(menu, profileName); menu->addAction(action); } } menu->setDisabled(menu->isEmpty()); } void SysTray::onManualProfileMenuTriggered(QString const &profile) { session_->toggleManualProfile(profile.toStdString()); } void SysTray::profileAdded(std::string const &profileName) { auto profile = profileManager_->profile(profileName); if (profile.has_value() && profile->get().info().exe == IProfile::Info::ManualID) { auto action = createManualProfileAction(manualProfileMenu_, profileName); auto beforeAction = findNextManualProfileActionPosition(profileName); manualProfileMenu_->insertAction(beforeAction, action); manualProfileMenu_->setDisabled(false); } } void SysTray::profileRemoved(std::string const &profileName) { auto action = findManualProfileAction(profileName); if (action.has_value()) { manualProfileMenu_->removeAction(*action); delete *action; manualProfileMenu_->setDisabled(manualProfileMenu_->isEmpty()); } } void SysTray::profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) { if (oldInfo.exe == IProfile::Info::ManualID || newInfo.exe == IProfile::Info::ManualID) { // automatic profile converted to manual profile if (oldInfo.exe != IProfile::Info::ManualID && newInfo.exe == IProfile::Info::ManualID) { auto action = createManualProfileAction(manualProfileMenu_, newInfo.name); auto beforeAction = findNextManualProfileActionPosition(newInfo.name); manualProfileMenu_->insertAction(beforeAction, action); } // manual profile converted to automatic profile else if (oldInfo.exe == IProfile::Info::ManualID && newInfo.exe != IProfile::Info::ManualID) { profileRemoved(oldInfo.name); } // manual profile name has changed else if (oldInfo.name != newInfo.name) { auto action = findManualProfileAction(oldInfo.name); if (action.has_value()) { // remove old action auto isChecked = (*action)->isChecked(); manualProfileMenu_->removeAction(*action); delete *action; // insert a new action auto action = createManualProfileAction(manualProfileMenu_, newInfo.name); action->setChecked(isChecked); auto beforeAction = findNextManualProfileActionPosition(newInfo.name); manualProfileMenu_->insertAction(beforeAction, action); } } manualProfileMenu_->setDisabled(manualProfileMenu_->isEmpty()); } } void SysTray::manualProfileToggled(std::string const &profileName, bool active) { auto action = findManualProfileAction(profileName); if (action.has_value()) (*action)->setChecked(active); } corectrl-v1.4.2/src/app/systray.h000066400000000000000000000040351467225065400167740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/iprofile.h" #include #include #include #include #include #include #include #include #include class IProfileManager; class ISession; class SysTray : public QObject { Q_OBJECT public: explicit SysTray(ISession *session, QObject *parent = nullptr); Q_INVOKABLE bool isAvailable() const; Q_INVOKABLE bool isVisible() const; signals: void activated(); void quit(); void showMainWindowToggled(bool visible); public slots: void show(); void hide(); void settingChanged(QString const &key, QVariant const &value); void onMainWindowVisibleChanged(bool isVisible); private slots: void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason); void onShowMainWindowActionTriggered(); private: void profileAdded(std::string const &profileName); void profileRemoved(std::string const &profileName); void profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo); void manualProfileToggled(std::string const &profileName, bool active); QSystemTrayIcon *createSystemTrayIcon(); QMenu *menu(); QAction *createManualProfileAction(QMenu *menu, std::string const &profileName); std::optional findManualProfileAction(std::string const &profileName); QAction *findNextManualProfileActionPosition(std::string const &profileName); void addManualProfilesTo(QMenu *menu); void onManualProfileMenuTriggered(QString const &profile); ISession *session_; IProfileManager *profileManager_; QSystemTrayIcon *sysTray_{nullptr}; QMenu menu_; QMenu *manualProfileMenu_{nullptr}; QAction *showMainWindowAction_{nullptr}; bool showMainWindow_; class ProfileManagerObserver; std::shared_ptr profileManagerObserver_; class ManualProfileObserver; std::shared_ptr manualProfileObserver_; }; corectrl-v1.4.2/src/common/000077500000000000000000000000001467225065400156135ustar00rootroot00000000000000corectrl-v1.4.2/src/common/cryptolayer.cpp000066400000000000000000000034671467225065400207060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cryptolayer.h" #include #include #include #include #include #include #include #include #include #include void CryptoLayer::init() { privateKey_ = std::make_unique(Botan::system_rng()); } QByteArray CryptoLayer::publicKey() { auto key = Botan::X509::PEM_encode(*privateKey_); return {key.c_str()}; } void CryptoLayer::usePublicKey(QByteArray const &publicKey) { auto keyStr = publicKey.toStdString(); Botan::DataSource_Memory pubKey(keyStr); opPublicKey_ = std::unique_ptr(Botan::X509::load_key(pubKey)); } bool CryptoLayer::verify(QByteArray const &data, QByteArray const &signature) { try { Botan::PK_Verifier verifier(*opPublicKey_, "SHA-512"); auto decodedSignature = Botan::base64_decode(signature.toStdString()); return verifier.verify_message( reinterpret_cast(data.data()), static_cast(data.size()), decodedSignature.data(), decodedSignature.size()); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } QByteArray CryptoLayer::signature(QByteArray const &data) { try { Botan::PK_Signer signer(*privateKey_, Botan::system_rng(), "SHA-512"); auto signature = signer.sign_message( reinterpret_cast(data.data()), static_cast(data.size()), Botan::system_rng()); auto encodedSignature = Botan::base64_encode(signature); return {encodedSignature.c_str()}; } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return {}; } corectrl-v1.4.2/src/common/cryptolayer.h000066400000000000000000000011501467225065400203360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icryptolayer.h" #include #include class CryptoLayer final : public ICryptoLayer { public: void init() override; QByteArray publicKey() override; void usePublicKey(QByteArray const &publicKey) override; bool verify(QByteArray const &data, QByteArray const &signature) override; QByteArray signature(QByteArray const &data) override; private: std::unique_ptr privateKey_; std::unique_ptr opPublicKey_; }; corectrl-v1.4.2/src/common/fileutils.cpp000066400000000000000000000070101467225065400203150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fileutils.h" #include #include #include #include #include namespace fs = std::filesystem; namespace Utils::File { std::vector readFile(std::filesystem::path const &path) { std::vector data; if (isFilePathValid(path)) { std::ifstream file(path, std::ios::binary); if (file.is_open()) { data.resize(fs::file_size(path)); file.read(data.data(), data.size()); } else SPDLOG_DEBUG("Cannot open file {}", path.c_str()); } else SPDLOG_DEBUG("Invalid file path {}", path.c_str()); return data; } bool writeFile(std::filesystem::path const &path, std::vector const &data) { std::ofstream file(path, std::ios::binary); if (file.is_open()) { file.write(data.data(), data.size()); return true; } else SPDLOG_DEBUG("Cannot open file {}", path.c_str()); return false; } std::vector readFileLines(std::filesystem::path const &path, char delim) { std::vector entries; if (isFilePathValid(path)) { std::ifstream file(path); if (file.is_open()) { for (std::string entry; std::getline(file, entry, delim);) entries.emplace_back(std::move(entry)); } else SPDLOG_DEBUG("Cannot open file {}", path.c_str()); } else SPDLOG_DEBUG("Invalid file path {}", path.c_str()); return entries; } bool isFilePathValid(std::filesystem::path const &path) { try { return fs::exists(path) && fs::is_regular_file(path); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } bool isDirectoryPathValid(std::filesystem::path const &path) { try { return fs::exists(path) && fs::is_directory(path); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } std::vector search(std::regex const ®ex, std::filesystem::path const &path) { std::vector paths; if (isDirectoryPathValid(path)) { for (auto const &entry : fs::directory_iterator(path)) { auto const &entryDirPath = entry.path(); std::string entryDirName((*(--entryDirPath.end())).string()); if (std::regex_search(entryDirName, regex)) paths.push_back(entryDirPath); } } else SPDLOG_DEBUG("Invalid directory path {}", path.c_str()); return paths; } std::optional findHWMonXDirectory(std::filesystem::path const &path) { std::regex const hwmonXRegex(R"(hwmon[0-9]+)"); auto paths = Utils::File::search(hwmonXRegex, path); if (!paths.empty()) { if (paths.size() > 1) { SPDLOG_WARN("Multiple hwmon directories detected on {}.\nUsing {}", path.c_str(), paths.front().c_str()); } // use the first hwmon[0-*] directory from gpu sysfs/hwmon path return paths.front(); } return {}; } bool isSysFSEntryValid(std::filesystem::path const &path) { if (!isFilePathValid(path)) return false; if (readFileLines(path).empty()) { SPDLOG_WARN("Empty sysfs entry {}", path.c_str()); return false; } return true; } std::vector readQrcFile(std::string_view qrcPath) { QFile file(qrcPath.data()); if (file.open(QFile::ReadOnly)) { auto fileData = file.readAll(); return std::vector(fileData.cbegin(), fileData.cend()); } return {}; } } // namespace Utils::File corectrl-v1.4.2/src/common/fileutils.h000066400000000000000000000053401467225065400177660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include namespace Utils::File { /// Reads the contents of a file. /// @param path path to the file to read /// @returns file contents or no contents on error /// /// @note Reading /sys files will produce more data than expected as /// its file size doesn't match the actual file contents. /// @note Reading /proc files won't produce any data. Those files must /// be readed line by line. Use readFileLines instead. std::vector readFile(std::filesystem::path const &path); /// Writes data to a file. Any previous file contents will be destroyed. /// @param path path to the file to read /// @param data to be written /// @returns true on success bool writeFile(std::filesystem::path const &path, std::vector const &data); /// Read the data of a file line by line. Contents will be splitted in /// lines using a delimiter. /// @param path file to read /// @param delimiter new line character /// @returns lines of data std::vector readFileLines(std::filesystem::path const &path, char delim = '\n'); /// Checks if a path exists and points to a file. /// @param path file to validate /// @returns true if the path points to a valid file bool isFilePathValid(std::filesystem::path const &path); /// Checks if a path exists and points to a directory. /// @param path directory to validate /// @returns true if the path points to a valid directory bool isDirectoryPathValid(std::filesystem::path const &path); /// Search for files or directories whose name matches a regular expression. /// @param regex regular expression to match the directory entries /// @param path target directory to search /// @returns path to the directory entries that match the regular expression std::vector search(std::regex const ®ex, std::filesystem::path const &path); /// Find the hwmon[0-*] directory in a path. /// @param path directory to seach for hwmon[0-*] directory /// @returns path to hwmon[0-*] directory std::optional findHWMonXDirectory(std::filesystem::path const &path); /// Checks if a path points to an existing and non empty sysfs entry file. /// @param path file to validate /// @return true if the path points to a valid sysfs entry bool isSysFSEntryValid(std::filesystem::path const &path); /// Read file data from a Qt qrc path. /// @param path rcc file path /// @return file contents or no contents on error std::vector readQrcFile(std::string_view qrcPath); } // namespace Utils::File corectrl-v1.4.2/src/common/icryptolayer.h000066400000000000000000000014141467225065400205120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class ICryptoLayer { public: /// Initialization. virtual void init() = 0; /// @return subject public key. virtual QByteArray publicKey() = 0; /// Set the key that will be used in public key operations (as verify). /// This key is generated by other subject. virtual void usePublicKey(QByteArray const &publicKey) = 0; /// Compute and validates the data signature against the provided signature. virtual bool verify(QByteArray const &data, QByteArray const &signature) = 0; /// Generates the signature of the data. virtual QByteArray signature(QByteArray const &data) = 0; virtual ~ICryptoLayer() = default; }; corectrl-v1.4.2/src/common/logger.h000066400000000000000000000021561467225065400172470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include void setupLogger(std::filesystem::path const &logFilePath) { try { auto console_sink = std::make_shared(); console_sink->set_pattern("[%d-%m-%C %H:%M:%S.%e][%L] %v"); console_sink->set_level(spdlog::level::info); auto file_sink = std::make_shared(logFilePath); file_sink->set_pattern("[%d-%m-%C %H:%M:%S.%e][%L][%s:%#] %v"); file_sink->set_level(spdlog::level::trace); auto logger = std::make_shared( "logger", spdlog::sinks_init_list({console_sink, file_sink})); logger->set_level(spdlog::level::trace); logger->flush_on(spdlog::level::debug); spdlog::set_default_logger(logger); } catch (spdlog::spdlog_ex const &e) { std::cout << "Logger initialization failed: " << e.what() << std::endl; } } corectrl-v1.4.2/src/common/mathutils.h000066400000000000000000000040621467225065400200000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include namespace Utils::Math { /// Performs a linear normalization to a collection of values from an old range /// to a new range. /// /// @note Only works with regular numeric types. /// /// @param values collection of values to normalize /// @param oldRange old range of the values of the collection /// @param newRange new range for the result of the normalization template void linearNorm(std::vector &values, std::pair const &oldRange, std::pair const &newRange) { std::transform(values.cbegin(), values.cend(), values.begin(), [&](T value) { return static_cast( (value - oldRange.first) * (static_cast(newRange.second - newRange.first) / (oldRange.second - oldRange.first)) + newRange.first); }); } /// Performs a lineal interpolation between two points resolving the y value at /// the supplied x value. /// /// @note Only works with regular numeric types. /// /// @param value x value to be evaluated /// @param p1 first point /// @param p2 second point /// @return resolved y value template Y lerpX(X value, std::pair const &p1, std::pair const &p2) { return static_cast( (static_cast(p2.second - p1.second) / (p2.first - p1.first)) * (value - p1.first) + p1.second); } /// Performs a lineal interpolation between two points resolving the x value at /// the supplied y value. /// /// @note Only works with regular numeric types. /// /// @param value y value to be evaluated /// @param p1 first point /// @param p2 second point /// @return resolved x value template X lerpY(Y value, std::pair const &p1, std::pair const &p2) { return static_cast( (static_cast(p2.first - p1.first) / (p2.second - p1.second)) * (value - p1.second) + p1.first); } } // namespace Utils::Math corectrl-v1.4.2/src/common/stringutils.cpp000066400000000000000000000043031467225065400207060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "stringutils.h" #include #include #include #include namespace Utils::String { std::string cleanPrefix(std::string const &str, std::string const &prefix) { auto it = std::search(str.cbegin(), str.cend(), prefix.cbegin(), prefix.cend()); if (it != str.cend()) { size_t const pos = prefix.size(); return str.substr(pos, str.size() - pos); } return str; } std::tuple parseVersion(std::string const &version) { try { if (std::count(version.cbegin(), version.cend(), '.') == 2) { auto firstDot = version.find("."); auto secondDot = version.find(".", firstDot + 1); if (firstDot > 0 && // mayor version exists firstDot + 1 < secondDot && // minor version exists secondDot < version.length() - 1) // patch version exists return {std::stoi(version.substr(0, firstDot)), std::stoi(version.substr(firstDot + 1, secondDot)), std::stoi(version.substr(secondDot + 1, std::string::npos))}; } SPDLOG_DEBUG("'{}' is not a valid version string", version); } catch (std::exception const &e) { SPDLOG_DEBUG("Cannot parse version string '{}'. Error: {}", version, e.what()); } return {0, 0, 0}; } std::vector split(std::string const &src, char delim) { std::vector result; std::istringstream istream(src); for (std::string part; std::getline(istream, part, delim);) if (!part.empty()) // skip empty parts result.push_back(part); return result; } std::optional parseKernelProcVersion(std::string const &data) { std::regex const regex(R"(^Linux\s*version\s*(\d+\.\d+(?:\.\d+){0,1}).*)"); std::smatch result; if (!std::regex_search(data, result, regex)) { SPDLOG_DEBUG("Cannot parse kernel version"); return {}; } // Append .0 when the patch version number is missing, see #254 std::string version = result[1]; if (std::count(version.cbegin(), version.cend(), '.') == 1) version.append(".0"); return version; } } // namespace Utils::String corectrl-v1.4.2/src/common/stringutils.h000066400000000000000000000061041467225065400203540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include #include namespace Utils::String { /// Cleans a prefix from a string. /// /// @returns substring of the input string without prefix std::string cleanPrefix(std::string const &str, std::string const &prefix); /// Converts a string in 'mayor.minor.patch' format into numeric value. /// /// @param version string in 'mayor.minor.patch' format /// @returns version [mayor, minor, patch] as integers or [0, 0, 0] on error std::tuple parseVersion(std::string const &version); /// Converts a string containing a number representation into its numerical value. /// @param value will store the result of the conversion /// @param rep representation of the number to convert /// @param base numerical base of the representation to convert from (for integers) /// @returns true on a successful conversion template bool toNumber(T &value, std::string const &rep, int base = 10) { try { if constexpr (std::is_same_v) { value = static_cast(std::stoi(rep, nullptr, base)); } else if constexpr (std::is_same_v) { value = static_cast(std::stoi(rep, nullptr, base)); } else if constexpr (std::is_same_v) value = std::stoi(rep, nullptr, base); else if constexpr (std::is_same_v) value = std::stol(rep, nullptr, base); else if constexpr (std::is_same_v) value = std::stoll(rep, nullptr, base); else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) value = static_cast(std::stoul(rep, nullptr, base)); else if constexpr (std::is_same_v) value = std::stoull(rep, nullptr, base); else if constexpr (std::is_same_v) value = std::stof(rep, nullptr); else if constexpr (std::is_same_v) value = std::stod(rep, nullptr); else if constexpr (std::is_same_v) value = std::stold(rep, nullptr); return true; } catch (std::exception const &e) { SPDLOG_DEBUG("Cannot parse a number from the string '{}'. Error: {}", rep, e.what()); } return false; } /// Splits a string into substrings using a delimiter. /// @param src string to be splitted /// @param delim delimiter to cut into substrings /// @returns collection of substrings std::vector split(std::string const &src, char delim = ' '); /// Parse kernel version from a string following the format used by the kernel /// on /proc/version. /// @param data string to parse the kernel version from /// @returns a string containing the kernel version following semver format std::optional parseKernelProcVersion(std::string const &data); } // namespace Utils::String corectrl-v1.4.2/src/config.h.in000066400000000000000000000004341467225065400163470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #define PROJECT_NAME "${PROJECT_NAME}" #define PROJECT_VERSION "${PROJECT_VERSION}" #define PROJECT_FQDN "${PROJECT_FQDN}" #define PCI_IDS_PATH "${WITH_PCI_IDS_PATH}" corectrl-v1.4.2/src/core/000077500000000000000000000000001467225065400152535ustar00rootroot00000000000000corectrl-v1.4.2/src/core/ccpro/000077500000000000000000000000001467225065400163615ustar00rootroot00000000000000corectrl-v1.4.2/src/core/ccpro/ccproparser.cpp000066400000000000000000000020201467225065400214020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "ccproparser.h" #include "zipdatasink.h" #include "zipdatasource.h" #include #include std::string CCPROParser::fileExtension() const { return "ccpro"; } std::optional> CCPROParser::load(std::filesystem::path const &path, std::string const &internalDataName) { ZipDataSource dataSource(path); if (!internalDataName.empty()) { try { std::vector fileData; if (dataSource.read(internalDataName, fileData)) return {fileData}; } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } return {}; } bool CCPROParser::save( std::filesystem::path const &path, std::vector>> const &data) { ZipDataSink dataSink(path); try { return dataSink.write(data); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } corectrl-v1.4.2/src/core/ccpro/ccproparser.h000066400000000000000000000010371467225065400210560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/iprofilefileparser.h" class CCPROParser final : public IProfileFileParser { public: std::string fileExtension() const override; std::optional> load(std::filesystem::path const &path, std::string const &internalDataName) override; bool save(std::filesystem::path const &path, std::vector>> const &data) override; }; corectrl-v1.4.2/src/core/ccpro/zipdatasink.cpp000066400000000000000000000051471467225065400214150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "zipdatasink.h" #include #include #include #include #include #include #include #include #include #include namespace fs = std::filesystem; ZipDataSink::ZipDataSink(std::filesystem::path const &path) noexcept : path_(path) { backupFile(); } ZipDataSink::~ZipDataSink() { removeBackupFile(); } std::string ZipDataSink::sink() const { return path_.string(); } bool ZipDataSink::write( std::vector>> const &data) { if (!data.empty()) { QuaZip zip(QString::fromStdString(sink())); if (zip.open(QuaZip::mdCreate)) { for (auto &[dataFilePath, fileData] : data) { if (!dataFilePath.empty() && !fileData.empty()) { QuaZipFile file(&zip); if (!(file.open(QIODevice::WriteOnly, QuaZipNewInfo(QString::fromStdString(dataFilePath))) && file.write(QByteArray::fromRawData(fileData.data(), fileData.size())) >= 0)) { if (file.isOpen()) file.close(); zip.close(); restorePreWriteFileState(); throw std::runtime_error( std::format("Failed to write {} data to file {}", dataFilePath.data(), sink().data())); } file.close(); } } zip.close(); return true; } else { throw std::runtime_error( std::format("Failed to open file {}", sink().data())); } } return false; } void ZipDataSink::backupFile() const { try { if (fs::exists(path_) && fs::is_regular_file(path_)) fs::copy_file(path_, sink() + ".bak", fs::copy_options::overwrite_existing); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } void ZipDataSink::removeBackupFile() const { try { fs::remove(sink() + ".bak"); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } void ZipDataSink::restorePreWriteFileState() const { // remove the current file try { fs::remove(path_.string()); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } // restore the backup file try { if (fs::exists(sink() + ".bak") && fs::is_regular_file(sink() + ".bak")) fs::copy_file(sink() + ".bak", path_, fs::copy_options::overwrite_existing); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } corectrl-v1.4.2/src/core/ccpro/zipdatasink.h000066400000000000000000000012721467225065400210550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasink.h" #include #include #include #include class ZipDataSink final : public IDataSink>>> { public: ZipDataSink(std::filesystem::path const &path) noexcept; ~ZipDataSink(); std::string sink() const override; bool write(std::vector>> const &data) override; private: void backupFile() const; void removeBackupFile() const; void restorePreWriteFileState() const; std::filesystem::path const path_; }; corectrl-v1.4.2/src/core/ccpro/zipdatasource.cpp000066400000000000000000000023501467225065400217420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "zipdatasource.h" #include #include #include #include #include #include #include #include #include ZipDataSource::ZipDataSource(std::filesystem::path const &path) noexcept : path_(path) { } std::string ZipDataSource::source() const { return path_.string(); } bool ZipDataSource::read(std::string const &internalDataPath, std::vector &data) { if (!internalDataPath.empty()) { QuaZip zip(QString::fromStdString(source())); if (zip.open(QuaZip::mdUnzip)) { if (zip.setCurrentFile(QString::fromStdString(internalDataPath))) { QuaZipFile file(&zip); if (file.open(QIODevice::ReadOnly)) { data.clear(); auto fileData = file.readAll(); std::copy(fileData.cbegin(), fileData.cend(), std::back_inserter(data)); file.close(); zip.close(); return true; } } zip.close(); } else { throw std::runtime_error(std::format("Failed to open file {}", source())); } } return false; } corectrl-v1.4.2/src/core/ccpro/zipdatasource.h000066400000000000000000000010541467225065400214070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include #include #include class ZipDataSource final : public IDataSource> { public: ZipDataSource(std::filesystem::path const &path) noexcept; std::string source() const override; bool read(std::string const &internalBundleDataPath, std::vector &data) override; private: std::filesystem::path const path_; }; corectrl-v1.4.2/src/core/commandqueue.cpp000066400000000000000000000043711467225065400204470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "commandqueue.h" #include #include #include #include CommandQueue::CommandQueue() noexcept : packIndex_(std::nullopt) { commands().reserve(50); } void CommandQueue::pack(bool activate) { if (activate) { // do not overwrite a previous index if (!packIndex_.has_value()) packIndex_ = commands_.size(); } else { packIndex_ = std::nullopt; } } std::optional CommandQueue::packWritesTo(std::string const &file) { if (packIndex_.has_value()) { // find the last queued command that touch the same file auto it = std::find_if(commands().crbegin(), commands().crend(), [&](auto const &v) { return v.first == file; }); if (it != commands().crend()) { auto index = std::distance(commands().cbegin(), it.base()) - 1; return index >= *packIndex(); } else { return false; } } return std::nullopt; } void CommandQueue::add(std::pair &&cmd) { // find the last queued command that touch the same file auto lastIt = std::find_if(commands().crbegin(), commands().crend(), [&](auto const &v) { return v.first == cmd.first; }); if (lastIt != commands().crend() && lastIt->second == cmd.second) return; // command already queued // insert command at the end by default auto insertIt = commands().cend(); // update insertIt when lastIt is in pack range if (lastIt != commands().crend() && packIndex().has_value()) { auto index = std::distance(commands().cbegin(), lastIt.base()) - 1; if (index >= *packIndex()) insertIt = lastIt.base(); } commands().emplace(insertIt, std::move(cmd)); } QByteArray CommandQueue::toRawData() { QByteArray data; for (auto const &[path, value] : commands()) { data += path.c_str(); data += '\0'; data += value.c_str(); data += '\0'; } commands().clear(); packIndex_ = std::nullopt; return data; } std::vector> &CommandQueue::commands() { return commands_; } std::optional const &CommandQueue::packIndex() const { return packIndex_; } corectrl-v1.4.2/src/core/commandqueue.h000066400000000000000000000013421467225065400201070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icommandqueue.h" #include #include #include class CommandQueue : public ICommandQueue { public: CommandQueue() noexcept; void pack(bool activate) override; std::optional packWritesTo(std::string const &file) override; void add(std::pair &&cmd) override; QByteArray toRawData() override; protected: std::vector> &commands(); std::optional const &packIndex() const; private: std::optional packIndex_; std::vector> commands_; }; corectrl-v1.4.2/src/core/components/000077500000000000000000000000001467225065400174405ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/amdutils.cpp000066400000000000000000000731251467225065400217760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "amdutils.h" #include "common/stringutils.h" #include #include #include #include #include #include #include namespace Utils::AMD { bool readAMDGPUVRamSize(int deviceFD, units::data::megabyte_t *size) { #if defined(DRM_IOCTL_AMDGPU_INFO) && defined(AMDGPU_INFO_MEMORY) struct drm_amdgpu_memory_info drm_info = {}; struct drm_amdgpu_info buffer = {}; buffer.query = AMDGPU_INFO_MEMORY; buffer.return_pointer = reinterpret_cast(&drm_info); buffer.return_size = sizeof(drm_info); if (ioctl(deviceFD, DRM_IOCTL_AMDGPU_INFO, &buffer) >= 0) { *size = units::make_unit( drm_info.vram.total_heap_size / (1024 * 1024)); return true; } else return false; #else return false; #endif } bool readRadeonVRamSize(int deviceFD, units::data::megabyte_t *size) { #if defined(DRM_IOCTL_RADEON_GEM_INFO) struct drm_radeon_gem_info buffer = {}; if (ioctl(deviceFD, DRM_IOCTL_RADEON_GEM_INFO, &buffer) >= 0) { *size = units::make_unit(buffer.vram_size / (1024 * 1024)); return true; } else return false; #else return false; #endif } std::optional>> parseDPMStates(std::vector const &ppDpmLines) { // Relevant lines format (kernel 4.6+) // 0: 300Mhz * // ... // N: 1303Mhz std::regex const regex(R"(^(\d+)\s*:\s*(\d+)\s*Mhz\s*\*?\s*$)", std::regex::icase); std::vector> states; for (auto const &line : ppDpmLines) { std::smatch result; if (!std::regex_search(line, result, regex)) return {}; unsigned int index{0}, freq{0}; if (!(Utils::String::toNumber(index, result[1]) && Utils::String::toNumber(freq, result[2]))) return {}; states.emplace_back(index, units::frequency::megahertz_t(freq)); } if (states.empty()) return {}; return std::move(states); } std::optional parseDPMCurrentStateIndex(std::vector const &ppDpmLines) { // Relevant lines format (kernel 4.6+) // 0: 300Mhz * // ... // N: 1303Mhz // // '*' marks the current state std::regex const regex(R"(^(\d+)\s*:\s*\d+\s*Mhz\s*\*\s*$)", std::regex::icase); for (auto const &line : ppDpmLines) { std::smatch result; if (std::regex_search(line, result, regex)) { unsigned int index{0}; if (!Utils::String::toNumber(index, result[1])) return {}; return index; } } return {}; } std::optional>> parsePowerProfileModeModes(std::vector const &ppPowerProfileModeLines) { // Relevant lines format: // 1 3D_FULL_SCREEN *: ... // 1 3D_FULL_SCREEN: ... // 1 3D_FULL_SCREEN*: ... // 1 3D_FULL_SCREEN : ... // 1 3D_FULL_SCREEN* // 1 3D_FULL_SCREEN std::regex const regex(R"(^\s*(\d+)\s+([^\*\(\s:]+))"); std::vector> modes; for (auto const &line : ppPowerProfileModeLines) { std::smatch result; if (!std::regex_search(line, result, regex)) continue; // skip BOOT and CUSTOM modes std::string const mode(result[2]); if (mode.find("BOOT") != std::string::npos || mode.find("CUSTOM") != std::string::npos) continue; int index{0}; if (!Utils::String::toNumber(index, result[1])) continue; modes.emplace_back(std::move(mode), index); } if (!modes.empty()) return std::move(modes); return {}; } std::optional parsePowerProfileModeCurrentModeIndex( std::vector const &ppPowerProfileModeLines) { // Relevant lines format: // 1 3D_FULL_SCREEN *: ... // 1 3D_FULL_SCREEN*: ... // 1 3D_FULL_SCREEN* std::regex const regex(R"(^\s*(\d+)\s+(?:[^\*\(\s]+)\s*\*)"); for (auto const &line : ppPowerProfileModeLines) { std::smatch result; if (!std::regex_search(line, result, regex)) continue; int index{0}; if (!Utils::String::toNumber(index, result[1])) break; return index; } return {}; } std::optional>> parsePowerProfileModeModesColumnar( std::vector const &ppPowerProfileModeLines) { // Format of the first line: // 0 BOOTUP_DEFAULT* 1 3D_FULL_SCREEN 2 POWER_SAVING 3 VIDEO ... if (ppPowerProfileModeLines.empty()) return {}; auto const &data = ppPowerProfileModeLines.front(); std::regex const regex(R"(\s*(\d+)\s+(\w+)\s*\*{0,1})", std::regex::icase); std::vector> modes; auto targetIt = std::sregex_iterator(data.cbegin(), data.cend(), regex); while (targetIt != std::sregex_iterator()) { std::smatch match = *targetIt; // skip BOOT and CUSTOM modes std::string const mode(match[2]); if (mode.find("BOOT") != std::string::npos || mode.find("CUSTOM") != std::string::npos) { targetIt = std::next(targetIt); continue; } int index{0}; if (!Utils::String::toNumber(index, match[1])) { targetIt = std::next(targetIt); continue; } modes.emplace_back(std::move(mode), index); targetIt = std::next(targetIt); } if (!modes.empty()) return std::move(modes); return {}; } std::optional parsePowerProfileModeCurrentModeIndexColumnar( std::vector const &ppPowerProfileModeLines) { // Format of the first line: // 0 BOOTUP_DEFAULT* 1 3D_FULL_SCREEN 2 POWER_SAVING 3 VIDEO ... if (ppPowerProfileModeLines.empty()) return {}; auto const &data = ppPowerProfileModeLines.front(); std::regex const regex(R"(\s*(\d+)\s+\w+\s*\*)", std::regex::icase); std::smatch result; if (!std::regex_search(data, result, regex)) return {}; int index{0}; if (!Utils::String::toNumber(index, result[1])) return {}; return index; } std::optional> parseOverdriveClkVoltLine(std::string const &line) { // Relevant lines format (kernel 4.17+): // ... // 0: 300MHz 800mV // // On Navi ASICs: // ... // 0: 300MHz @ 800mV // ... std::regex const regex(R"((\d+)\s*:\s*(\d+)\s*MHz[\s@]*(\d+)\s*mV\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { unsigned int index{0}, freq{0}, volt{0}; if (Utils::String::toNumber(index, result[1]) && Utils::String::toNumber(freq, result[2]) && Utils::String::toNumber(volt, result[3])) return std::make_tuple(index, units::frequency::megahertz_t(freq), units::voltage::millivolt_t(volt)); } return {}; } std::optional>> parseOverdriveClksVolts(std::string_view controlName, std::vector const &ppOdClkVoltageLines) { // Relevant lines format (kernel 4.17+): // ... // OD_controlName: // ... // OD_otherLbl: // ... auto targetIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_" + std::string(controlName) + ":") != std::string::npos; }); if (targetIt != ppOdClkVoltageLines.cend() && std::next(targetIt) != ppOdClkVoltageLines.cend()) { targetIt = std::next(targetIt); auto endIt = std::find_if(targetIt, ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_") != std::string::npos; }); std::vector> states; while (targetIt != endIt) { auto state = parseOverdriveClkVoltLine(*targetIt); if (state.has_value()) states.emplace_back(std::move(*state)); targetIt = std::next(targetIt); } return std::move(states); } return {}; } std::optional> parseOverdriveClkRange(std::string const &line) { // Relevant lines format (kernel 4.18+): // ... // Lbl...: 400MHz 500MHz // ... std::regex const regex(R"(^(?:[^\:\s]+)\s*:\s*(\d+)\s*MHz\s*(\d+)\s*MHz\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { int min{0}, max{0}; if (Utils::String::toNumber(min, result[1]) && Utils::String::toNumber(max, result[2])) return std::make_pair(units::make_unit(min), units::make_unit(max)); } return {}; } std::optional> parseOverdriveClkRange(std::string_view controlName, std::vector const &ppOdClkVoltageLines) { // Relevant lines format (kernel 4.18+): // ... // OD_RANGE: // ... // controlName: min max // ... auto rangeIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_RANGE:") != std::string::npos; }); if (rangeIt != ppOdClkVoltageLines.cend()) { auto targetIt = std::find_if( rangeIt, ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find(std::string(controlName) + ":") != std::string::npos; }); if (targetIt != ppOdClkVoltageLines.cend()) return parseOverdriveClkRange(*targetIt); } return {}; } std::optional> parseOverdriveVoltRangeLine(std::string const &line) { // Relevant lines format (kernel 4.18+): // ... // Lbl...: 400mV 500mV // ... std::regex const regex(R"(^(?:[^\:\s]+)\s*:\s*(\d+)\s*mV\s*(\d+)\s*mV\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { int min{0}, max{0}; if (Utils::String::toNumber(min, result[1]) && Utils::String::toNumber(max, result[2])) return std::make_pair(units::make_unit(min), units::make_unit(max)); } return {}; } std::optional> parseOverdriveVoltRange(std::vector const &ppOdClkVoltageLines) { // Relevant lines format (kernel 4.18+): // ... // OD_RANGE: // ... // VDDC: min max // ... auto rangeIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_RANGE:") != std::string::npos; }); if (rangeIt != ppOdClkVoltageLines.cend()) { auto targetIt = std::find_if( rangeIt, ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("VDDC:") != std::string::npos; }); if (targetIt != ppOdClkVoltageLines.cend()) return parseOverdriveVoltRangeLine(*targetIt); } return {}; } std::optional> parseOverdriveClksLine(std::string const &line) { // Relevant lines format (kernel 4.20+): // ... // 0: 300MHz // ... std::regex const regex(R"(^(\d+)\s*:\s*(\d+)\s*MHz\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { unsigned int index{0}, freq{0}; if (Utils::String::toNumber(index, result[1]) && Utils::String::toNumber(freq, result[2])) return std::make_pair(index, units::frequency::megahertz_t(freq)); } return {}; } std::optional>> parseOverdriveClks(std::string_view controlName, std::vector const &ppOdClkVoltageLines) { // Relevant lines format (kernel 4.17+): // ... // OD_controlName: // ... // OD_otherLbl: // ... auto targetIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_" + std::string(controlName) + ":") != std::string::npos; }); if (targetIt != ppOdClkVoltageLines.cend() && std::next(targetIt) != ppOdClkVoltageLines.cend()) { targetIt = std::next(targetIt); auto endIt = std::find_if(targetIt, ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_") != std::string::npos; }); std::vector> states; while (targetIt != endIt) { auto state = parseOverdriveClksLine(*targetIt); if (state.has_value()) states.emplace_back(std::move(*state)); targetIt = std::next(targetIt); } return std::move(states); } return {}; } std::optional>> parseOverdriveVoltCurve(std::vector const &ppOdClkVoltageLines) { // Relevant lines format (kernel 4.20+): // ... // OD_VDDC_CURVE: // 0: 700Mhz 800mV // ... // OD_RANGE: auto targetIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_VDDC_CURVE:") != std::string::npos; }); if (targetIt != ppOdClkVoltageLines.cend() && std::next(targetIt) != ppOdClkVoltageLines.cend()) { targetIt = std::next(targetIt); auto endIt = std::find_if(targetIt, ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_") != std::string::npos; }); std::vector> points; while (targetIt != endIt) { auto state = parseOverdriveClkVoltLine(*targetIt); if (state.has_value()) { auto &[_, freq, volt] = *state; points.emplace_back(std::make_pair(freq, volt)); } targetIt = std::next(targetIt); } if (!points.empty()) return std::move(points); } return {}; } std::optional, std::pair>>> parseOverdriveVoltCurveRange(std::vector const &ppOdClkVoltageLines) { // Relevant lines format (kernel 4.20+): // ... // OD_RANGE: // ... // VDDC_CURVE_SCLK[0]: 808Mhz 2200Mhz // VDDC_CURVE_VOLT[0]: 738mV 1218mV // ... // VDDC_CURVE_SCLK[N]: 808Mhz 2200Mhz // VDDC_CURVE_VOLT[N]: 738mV 1218mV // ... auto rangeIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_RANGE:") != std::string::npos; }); if (rangeIt != ppOdClkVoltageLines.cend()) { std::vector, std::pair>> ranges; auto freqIt = std::next(rangeIt); // skip lines not starting with VDDC_CURVE_ freqIt = std::find_if( freqIt, ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("VDDC_CURVE_") != std::string::npos; }); while (freqIt != ppOdClkVoltageLines.cend() && (*freqIt).find("VDDC_CURVE_SCLK[") != std::string::npos) { auto voltIt = std::next(freqIt); if (voltIt != ppOdClkVoltageLines.cend() && (*voltIt).find("VDDC_CURVE_VOLT[") != std::string::npos) { auto freqRange = parseOverdriveClkRange(*freqIt); auto voltRange = parseOverdriveVoltRangeLine(*voltIt); if (freqRange.has_value() && voltRange.has_value()) ranges.emplace_back( std::make_pair(std::move(*freqRange), std::move(*voltRange))); else return {}; // invalid data format } else return {}; // invalid data format freqIt = std::next(voltIt); } if (!ranges.empty()) return std::move(ranges); } return {}; } std::optional parseOverdriveVoltOffset(std::vector const &ppOdClkVoltageLines) { auto targetIt = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("OD_VDDGFX_OFFSET:") != std::string::npos; }); if (targetIt != ppOdClkVoltageLines.cend() && std::next(targetIt) != ppOdClkVoltageLines.cend()) { std::regex const regex(R"(^(-?\d+)\s*mV\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(*std::next(targetIt), result, regex)) { int value; if (Utils::String::toNumber(value, result[1])) return units::voltage::millivolt_t(value); } } return {}; } std::optional> parseOverdriveClkControls(std::vector const &ppOdClkVoltageLines) { std::regex const regex(R"(^OD_(\wCLK):\s*$)", std::regex::icase); std::vector controlNames; for (auto const &line : ppOdClkVoltageLines) { std::smatch result; if (!std::regex_search(line, result, regex)) continue; controlNames.emplace_back(result[1]); } if (!controlNames.empty()) return controlNames; return {}; } std::optional getOverdriveClkControlCmdId(std::string_view controlName) { static std::unordered_map const nameCmdIdMap{ {"SCLK", "s"}, {"MCLK", "m"}}; if (nameCmdIdMap.count(controlName) > 0) return nameCmdIdMap.at(controlName); return {}; } std::optional> ppOdClkVoltageFreqRangeOutOfRangeStates( std::string const &controlName, std::vector const &ppOdClkVoltageLines) { // Search for out of range frequency clocks (RX6X00 XT) // ... // "OD_MCLK:", // "0: 97Mhz", // ... // "OD_RANGE:", // ... // "MCLK: 674Mhz 1200Mhz", auto clks = parseOverdriveClks(controlName, ppOdClkVoltageLines); auto range = parseOverdriveClkRange(controlName, ppOdClkVoltageLines); if (!(clks.has_value() && range.has_value())) return std::nullopt; std::vector states; auto [min, max] = *range; for (auto const &[index, clk] : *clks) { if (!(clk >= min && clk <= max)) states.push_back(index); } if (!states.empty()) return states; return std::nullopt; } bool ppOdClkVoltageHasKnownFreqVoltQuirks( std::string const &, std::vector const &ppOdClkVoltageLines) { // Check for missing range section (kernel < 4.18) auto odRangeIter = std::find_if( ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line == "OD_RANGE:"; }); if (odRangeIter == ppOdClkVoltageLines.cend()) return true; return false; } bool ppOdClkVoltageHasKnownVoltCurveQuirks( std::vector const &ppOdClkVoltageLines) { // Check for voltage incomplete curve points (navi on kernel < 5.6) // "OD_VDDC_CURVE:", // "0: 700Mhz @ 0mV", auto atIter = std::find_if(ppOdClkVoltageLines.cbegin(), ppOdClkVoltageLines.cend(), [&](std::string const &line) { return line.find("@") != std::string::npos; }); if (atIter != ppOdClkVoltageLines.cend()) { auto points = parseOverdriveVoltCurve(ppOdClkVoltageLines); if (!points.has_value()) return true; return points->at(0).second == units::voltage::millivolt_t(0); } return false; } std::optional> parseOverdriveFanCurveLine(std::string const &line) { // Relevant lines format (kernel 6.7+): // ... // 0: 45C 15% // ... std::regex const regex(R"((\d+)\s*:\s*(\d+)\s*C\s*(\d+)\s*%\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { unsigned int index{0}, temp{0}, speed{0}; if (Utils::String::toNumber(index, result[1]) && Utils::String::toNumber(temp, result[2]) && Utils::String::toNumber(speed, result[3])) return std::make_tuple(index, units::temperature::celsius_t(temp), units::concentration::percent_t(speed)); } return {}; } std::optional>> parseOverdriveFanCurve(std::vector const &fanCurveLines) { // Relevant lines format (kernel 6.7+): // OD_FAN_CURVE: // 0: 0C 0% // 1: 45C 15% // 2: 50C 30% // 3: 55C 70% // 4: 65C 100% // OD_RANGE: auto targetIt = std::find_if( fanCurveLines.cbegin(), fanCurveLines.cend(), [&](std::string const &line) { return line.find("OD_FAN_CURVE:") != std::string::npos; }); if (targetIt != fanCurveLines.cend() && std::next(targetIt) != fanCurveLines.cend()) { targetIt = std::next(targetIt); auto endIt = std::find_if(targetIt, fanCurveLines.cend(), [&](std::string const &line) { return line.find("OD_") != std::string::npos; }); bool invalidPointData = false; std::vector> points; while (targetIt != endIt) { auto point = parseOverdriveFanCurveLine(*targetIt); if (point.has_value()) { points.emplace_back(std::move(*point)); } else { invalidPointData = true; break; } targetIt = std::next(targetIt); } if (!points.empty() && !invalidPointData) return std::move(points); } return {}; } std::optional> parseOverdriveFanCurveTempRangeLine(std::string const &line) { // Relevant lines format (kernel 6.7+): // ... // FAN_CURVE(hotspot temp): 25C 100C // ... std::regex const regex(R"(^.+\s*:\s*(\d+)\s*C\s*(\d+)\s*C\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { int min{0}, max{0}; if (Utils::String::toNumber(min, result[1]) && Utils::String::toNumber(max, result[2])) return std::make_pair(units::make_unit(min), units::make_unit(max)); } return {}; } std::optional> parseOverdriveFanCurveTempRange(std::vector const &fanCurveLines) { // Relevant lines format (kernel 6.7+): // ... // OD_RANGE: // ... // FAN_CURVE(hotspot temp): 25C 100C // ... auto rangeIt = std::find_if( fanCurveLines.cbegin(), fanCurveLines.cend(), [&](std::string const &line) { return line.find("OD_RANGE:") != std::string::npos; }); if (rangeIt != fanCurveLines.cend()) { std::regex const regex(R"(^FAN_CURVE\s*\(\w+\s+temp\)\s*:)", std::regex::icase); auto targetIt = std::find_if( rangeIt, fanCurveLines.cend(), [&](std::string const &line) { std::smatch result; return std::regex_search(line, result, regex); }); if (targetIt != fanCurveLines.cend()) return parseOverdriveFanCurveTempRangeLine(*targetIt); } return {}; } std::optional< std::pair> parseOverdriveFanCurveSpeedRangeLine(std::string const &line) { // Relevant lines format (kernel 6.7+): // ... // FAN_CURVE(fan speed): 0% 100% // ... std::regex const regex(R"(^.+\s*:\s*(\d+)\s*%\s*(\d+)\s*%\s*$)", std::regex::icase); std::smatch result; if (std::regex_search(line, result, regex)) { int min{0}, max{0}; if (Utils::String::toNumber(min, result[1]) && Utils::String::toNumber(max, result[2])) return std::make_pair( units::make_unit(min), units::make_unit(max)); } return {}; } std::optional< std::pair> parseOverdriveFanCurveSpeedRange(std::vector const &fanCurveLines) { // Relevant lines format (kernel 6.7+): // ... // OD_RANGE: // ... // FAN_CURVE(fan speed): 0% 100% // ... auto rangeIt = std::find_if( fanCurveLines.cbegin(), fanCurveLines.cend(), [&](std::string const &line) { return line.find("OD_RANGE:") != std::string::npos; }); if (rangeIt != fanCurveLines.cend()) { std::regex const regex(R"(^FAN_CURVE\s*\(\w+\s+speed\)\s*:)", std::regex::icase); auto targetIt = std::find_if( rangeIt, fanCurveLines.cend(), [&](std::string const &line) { std::smatch result; return std::regex_search(line, result, regex); }); if (targetIt != fanCurveLines.cend()) return parseOverdriveFanCurveSpeedRangeLine(*targetIt); } return {}; } bool isPowerProfileModeDataColumnar(std::vector const &data) { if (data.empty()) return false; // The first line of the data contains the profile names and their indices: // 0 BOOTUP_DEFAULT* 1 3D_FULL_SCREEN 2 POWER_SAVING 3 VIDEO ... auto const &firstLine = data.front(); // Try to match at least two (index power_profile_name) pairs std::regex const regex(R"(^\s*\d+\s+\w+\s*\*{0,1}\s*\d+\s+\w+\*{0,1})", std::regex::icase); std::smatch result; return std::regex_search(firstLine, result, regex); } bool hasOverdriveClkVoltControl(std::vector const &data) { std::regex const clkRegex(R"(^OD_\wCLK:)", std::regex::icase); std::smatch result; auto clkIt = std::find_if(data.cbegin(), data.cend(), [&](std::string const &line) { return std::regex_match(line, result, clkRegex); }); if (clkIt != data.cend() && std::next(clkIt) != data.cend()) { auto state = parseOverdriveClkVoltLine(*std::next(clkIt)); return state.has_value(); } return false; } bool hasOverdriveClkControl(std::vector const &data) { std::regex const clkRegex(R"(^OD_\wCLK:)", std::regex::icase); std::smatch result; auto clkIt = std::find_if(data.cbegin(), data.cend(), [&](std::string const &line) { return std::regex_match(line, result, clkRegex); }); if (clkIt != data.cend() && std::next(clkIt) != data.cend()) { auto state = parseOverdriveClksLine(*std::next(clkIt)); return state.has_value(); } return false; } bool hasOverdriveVoltCurveControl(std::vector const &data) { auto curveIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("OD_VDDC_CURVE:") != std::string::npos; }); if (curveIt != data.cend() && std::next(curveIt) != data.cend()) { auto point = parseOverdriveClkVoltLine(*std::next(curveIt)); return point.has_value(); } return false; } bool hasOverdriveVoltOffsetControl(std::vector const &data) { auto offsetIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("OD_VDDGFX_OFFSET:") != std::string::npos; }); return offsetIt != data.cend(); } bool hasOverdriveFanTargetTempControl(std::vector const &data) { auto offsetIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("FAN_TARGET_TEMPERATURE:") != std::string::npos; }); return offsetIt != data.cend(); } bool hasOverdriveFanMinimumPWMControl(std::vector const &data) { auto offsetIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("FAN_MINIMUM_PWM:") != std::string::npos; }); return offsetIt != data.cend(); } bool hasOverdriveFanAcousticTargetControl(std::vector const &data) { auto offsetIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("OD_ACOUSTIC_TARGET:") != std::string::npos; }); return offsetIt != data.cend(); } bool hasOverdriveFanAcousticLimitControl(std::vector const &data) { auto offsetIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("OD_ACOUSTIC_LIMIT:") != std::string::npos; }); return offsetIt != data.cend(); } bool hasOverdriveFanCurveControl(std::vector const &data) { auto offsetIt = std::find_if( data.cbegin(), data.cend(), [&](std::string const &line) { return line.find("OD_FAN_CURVE:") != std::string::npos; }); return offsetIt != data.cend(); } } // namespace Utils::AMD corectrl-v1.4.2/src/core/components/amdutils.h000066400000000000000000000233751467225065400214450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace Utils::AMD { template bool readAMDGPUInfoSensor(int deviceFD, Data *value, std::uint32_t sensor) { #if defined(AMDGPU_INFO_SENSOR) && defined(DRM_IOCTL_AMDGPU_INFO) struct drm_amdgpu_info buffer = {}; buffer.query = AMDGPU_INFO_SENSOR; buffer.return_pointer = reinterpret_cast(value); buffer.return_size = sizeof(*value); buffer.sensor_info.type = sensor; return ioctl(deviceFD, DRM_IOCTL_AMDGPU_INFO, &buffer) >= 0; #else return false; #endif } template bool readAMDGPUInfo(int deviceFD, Data *value, std::uint32_t query) { #if defined(DRM_IOCTL_AMDGPU_INFO) struct drm_amdgpu_info buffer = {}; buffer.query = query; buffer.return_pointer = reinterpret_cast(value); buffer.return_size = sizeof(*value); return ioctl(deviceFD, DRM_IOCTL_AMDGPU_INFO, &buffer) >= 0; #else return false; #endif } bool readAMDGPUVRamSize(int deviceFD, units::data::megabyte_t *size); template bool readRadeonInfoSensor(int deviceFD, Data *value, std::uint32_t sensor) { #if defined(DRM_IOCTL_RADEON_INFO) struct drm_radeon_info buffer = {}; buffer.request = sensor; buffer.value = reinterpret_cast(value); return ioctl(deviceFD, DRM_IOCTL_RADEON_INFO, &buffer) >= 0; #else return false; #endif } bool readRadeonVRamSize(int deviceFD, units::data::megabyte_t *size); /// Returns DPM states clocks. (4.6+) /// @param ppDpmLines pp_dpm_sclk / pp_dpm_mclk data source contents std::optional>> parseDPMStates(std::vector const &ppDpmLines); /// Returns the current state index from pp_dpm_sclk / pp_dpm_mclk. (4.6+) /// @param ppDpmLines pp_dpm_sclk / pp_dpm_mclk data source contents std::optional parseDPMCurrentStateIndex(std::vector const &ppDpmLines); /// Returns power profile modes. (4.17+) /// NOTE For use with non-columnar data only. /// @param ppPowerProfileModeLines pp_power_profile_mode data source contents std::optional>> parsePowerProfileModeModes(std::vector const &ppPowerProfileModeLines); /// Returns current power profile mode index. (4.17+) /// NOTE For use with non-columnar data only. /// @param ppPowerProfileModeLines pp_power_profile_mode data source contents std::optional parsePowerProfileModeCurrentModeIndex( std::vector const &ppPowerProfileModeLines); /// Returns power profile modes on ASICs with columnar data. (6.11+) /// @param ppPowerProfileModeLines pp_power_profile_mode data source contents std::optional>> parsePowerProfileModeModesColumnar( std::vector const &ppPowerProfileModeLines); /// Returns current power profile mode index on ASICs with columnar data. (6.11+) /// @param ppPowerProfileModeLines pp_power_profile_mode data source contents std::optional parsePowerProfileModeCurrentModeIndexColumnar( std::vector const &ppPowerProfileModeLines); /// Returns the available clock + voltage states for a control. (4.17+) /// @param controlName name of the control /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional>> parseOverdriveClksVolts(std::string_view controlName, std::vector const &ppOdClkVoltageLines); /// Returns the state's clock range for a control. (4.18+) /// @param controlName name of the control /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional> parseOverdriveClkRange(std::string_view controlName, std::vector const &ppOdClkVoltageLines); /// Returns the state's voltage range. (4.18+) /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional> parseOverdriveVoltRange(std::vector const &ppOdClkVoltageLines); /// Returns the available clock states for a control. (4.20+, vega20+) /// @param controlName name of the control /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional>> parseOverdriveClks(std::string_view controlName, std::vector const &ppOdClkVoltageLines); /// Returns the voltage curve points for curve voltage ASICs. (4.20+, vega20+) /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional>> parseOverdriveVoltCurve(std::vector const &ppOdClkVoltageLines); /// Returns voltage range of curve points for curve voltage ASICs. (4.20+, vega20+) /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional, std::pair>>> parseOverdriveVoltCurveRange(std::vector const &ppOdClkVoltageLines); /// Returns the voltage offset. /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional parseOverdriveVoltOffset(std::vector const &ppOdClkVoltageLines); /// Returns a list containing the name of the available CLK controls. /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional> parseOverdriveClkControls(std::vector const &ppOdClkVoltageLines); /// Translates a CLK control name to the control commit command id. /// @param controlName name of the control /// @returns commit command id std::optional getOverdriveClkControlCmdId(std::string_view controlName); /// Returns a list containing the indices of all out of range states present on /// pp_od_clk_voltage for the given control name. /// @param controlName name of the control /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents std::optional> ppOdClkVoltageFreqRangeOutOfRangeStates( std::string const &controlName, std::vector const &ppOdClkVoltageLines); /// Returns whether pp_od_clk_voltage has known frequency + voltage control quirks. /// @param controlName name of the control /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents bool ppOdClkVoltageHasKnownFreqVoltQuirks( std::string const &controlName, std::vector const &ppOdClkVoltageLines); /// Returns whether pp_od_clk_voltage has known voltage curve control quirks. /// @param ppOdClkVoltageLines pp_od_clk_voltage data source contents bool ppOdClkVoltageHasKnownVoltCurveQuirks( std::vector const &ppOdClkVoltageLines); /// Returns the fan curve points for the overdrive based fan control. (6.7+, RDNA3+) /// @param fanCurveLines fan_curve data source contents std::optional>> parseOverdriveFanCurve(std::vector const &fanCurveLines); /// Returns the fan curve temperature range for the overdrive based fan control. (6.7+, RDNA3+) /// @param fanCurveLines fan_curve data source contents std::optional> parseOverdriveFanCurveTempRange(std::vector const &fanCurveLines); /// Returns the fan curve speed range for the overdrive based fan control. (6.7+, RDNA3+) /// @param fanCurveLines fan_curve data source contents std::optional< std::pair> parseOverdriveFanCurveSpeedRange(std::vector const &fanCurveLines); /// Returns true when pp_power_profile_mode data has columnar format. bool isPowerProfileModeDataColumnar(std::vector const &data); /// Returns true when overdrive clock + voltage state control is available. bool hasOverdriveClkVoltControl(std::vector const &data); /// Returns true when overdrive clock control is available. bool hasOverdriveClkControl(std::vector const &data); /// Returns true when overdrive voltage curve control is available. bool hasOverdriveVoltCurveControl(std::vector const &data); /// Returns true when overdrive voltage offset control is available. bool hasOverdriveVoltOffsetControl(std::vector const &data); /// Returns true when overdrive fan target temperature control is available. bool hasOverdriveFanTargetTempControl(std::vector const &data); /// Returns true when overdrive fan minimum pwm control is available. bool hasOverdriveFanMinimumPWMControl(std::vector const &data); /// Returns true when overdrive fan acoustic target rpm threshold control is /// available. bool hasOverdriveFanAcousticTargetControl(std::vector const &data); /// Returns true when overdrive fan acoustic limit rpm threshold control is /// available. bool hasOverdriveFanAcousticLimitControl(std::vector const &data); /// Returns true when overdrive fan curve control is available. bool hasOverdriveFanCurveControl(std::vector const &data); } // namespace Utils::AMD corectrl-v1.4.2/src/core/components/commonutils.cpp000066400000000000000000000032541467225065400225210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "commonutils.h" #include "common/mathutils.h" #include #include #include namespace Utils::Common { void normalizePoints( std::vector> &points, std::pair tempRange, std::pair speedRange) { std::vector temps; if (std::any_of(points.cbegin(), points.cend(), [&](auto const &point) { return point.first < tempRange.first || point.first > tempRange.second; })) { std::transform( points.cbegin(), points.cend(), std::back_inserter(temps), [](auto const &point) { return point.first.template to(); }); auto [minTemp, maxTemp] = std::minmax_element(temps.cbegin(), temps.cend()); Utils::Math::linearNorm( temps, std::make_pair(std::min(0.0, *minTemp), std::max(90.0, *maxTemp)), std::make_pair(tempRange.first.to(), tempRange.second.to())); } for (size_t i = 0; i < points.size(); ++i) { auto &[temp, pwm] = points.at(i); pwm = std::clamp(pwm, speedRange.first, speedRange.second); // ensure that point.pwm >= prevPoint.pwm if (points.size() > 1 && i > 0) { auto const &[_, prevPwm] = points.at(i - 1); if (pwm < prevPwm) pwm = prevPwm; } if (!temps.empty()) temp = units::temperature::celsius_t(temps[i]); } } } // namespace Utils::Common corectrl-v1.4.2/src/core/components/commonutils.h000066400000000000000000000016161467225065400221660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include namespace Utils::Common { /// Normalizes points into temperature and percentage ranges. /// @note Temperature normalization is only performed when needed. /// @param tempRange target temperature range /// @param speedRange target speed range void normalizePoints( std::vector> &points, std::pair tempRange, std::pair speedRange = std::make_pair(units::concentration::percent_t(0), units::concentration::percent_t(100))); } // namespace Utils::Common corectrl-v1.4.2/src/core/components/controls/000077500000000000000000000000001467225065400213035ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/000077500000000000000000000000001467225065400220445ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/000077500000000000000000000000001467225065400226105ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/000077500000000000000000000000001467225065400235605ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanauto.cpp000066400000000000000000000016041467225065400257220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanauto.h" #include "core/icommandqueue.h" #include AMD::FanAuto::FanAuto(std::unique_ptr> &&dataSource) noexcept : Control(true) , id_(AMD::FanAuto::ItemID) , dataSource_(std::move(dataSource)) { } void AMD::FanAuto::preInit(ICommandQueue &) { } void AMD::FanAuto::postInit(ICommandQueue &) { } void AMD::FanAuto::init() { } std::string const &AMD::FanAuto::ID() const { return id_; } void AMD::FanAuto::importControl(IControl::Importer &) { } void AMD::FanAuto::exportControl(IControl::Exporter &) const { } void AMD::FanAuto::cleanControl(ICommandQueue &) { } void AMD::FanAuto::syncControl(ICommandQueue &ctlCmds) { if (dataSource_->read(pwmEnable_)) { if (pwmEnable_ != 2) ctlCmds.add({dataSource_->source(), "2"}); } } corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanauto.h000066400000000000000000000020331467225065400253640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include namespace AMD { class FanAuto : public Control { public: static constexpr std::string_view ItemID{"AMD_FAN_AUTO"}; FanAuto(std::unique_ptr> &&dataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: std::string const id_; std::unique_ptr> const dataSource_; unsigned int pwmEnable_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoprofilepart.cpp000066400000000000000000000034371467225065400302000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanautoprofilepart.h" #include "core/profilepartprovider.h" #include class AMD::FanAutoProfilePart::Initializer final : public AMD::FanAuto::Exporter { public: Initializer(AMD::FanAutoProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::FanAutoProfilePart &outer_; }; void AMD::FanAutoProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } AMD::FanAutoProfilePart::FanAutoProfilePart() noexcept : id_(AMD::FanAuto::ItemID) { } std::unique_ptr AMD::FanAutoProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::FanAutoProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::FanAutoProfilePart::ID() const { return id_; } std::optional> AMD::FanAutoProfilePart::provideImporter(Item const &) { return {}; } bool AMD::FanAutoProfilePart::provideActive() const { return active(); } void AMD::FanAutoProfilePart::importProfilePart(IProfilePart::Importer &) { } void AMD::FanAutoProfilePart::exportProfilePart(IProfilePart::Exporter &) const { } std::unique_ptr AMD::FanAutoProfilePart::cloneProfilePart() const { return std::make_unique(); } bool const AMD::FanAutoProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::FanAuto::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoprofilepart.h000066400000000000000000000021621467225065400276370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "fanauto.h" #include namespace AMD { class FanAutoProfilePart final : public ProfilePart , public AMD::FanAuto::Importer { public: class Importer : public IProfilePart::Importer { }; class Exporter : public IProfilePart::Exporter { }; FanAutoProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: class Initializer; std::string const id_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoprovider.cpp000066400000000000000000000025531467225065400275010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanautoprovider.h" #include "../fanmodeprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/amd/gpuinfoodfanctrl.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "fanauto.h" #include #include std::vector> AMD::FanAutoProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && !gpuInfo.hasCapability(GPUInfoOdFanCtrl::ID))) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; auto pwmEnable = path.value() / "pwm1_enable"; if (!Utils::File::isSysFSEntryValid(pwmEnable)) return {}; std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>( pwmEnable, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }))); return controls; } bool const AMD::FanAutoProvider::registered_ = AMD::FanModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoprovider.h000066400000000000000000000007461467225065400271500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class FanAutoProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoqmlitem.cpp000066400000000000000000000052201467225065400273110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanautoqmlitem.h" #include "core/qmlcomponentregistry.h" #include "fanauto.h" #include #include #include #include #include #include char const *const AMD::FanAutoQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_FAN_AUTO"), }; class AMD::FanAutoQMLItem::Initializer final : public QMLItem::Initializer , public IControl::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::FanAutoQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::FanAutoQMLItem &outer_; }; void AMD::FanAutoQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } AMD::FanAutoQMLItem::FanAutoQMLItem() noexcept { setName(tr(FanAuto::ItemID.data())); } void AMD::FanAutoQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::FanAutoQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::FanAutoQMLItem::provideExporter(Item const &) { return {}; } bool AMD::FanAutoQMLItem::provideActive() const { return active_; } void AMD::FanAutoQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } std::unique_ptr AMD::FanAutoQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } bool AMD::FanAutoQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::FanAuto::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::FanAuto::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDFanAutoForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::FanAutoQMLItem::registered_ = AMD::FanAutoQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoqmlitem.h000066400000000000000000000020521467225065400267560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "fanautoprofilepart.h" #include namespace AMD { class FanAutoQMLItem : public QMLItem , public AMD::FanAutoProfilePart::Importer , public AMD::FanAutoProfilePart::Exporter { Q_OBJECT public: explicit FanAutoQMLItem() noexcept; void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; bool active_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoxmlparser.cpp000066400000000000000000000043321467225065400276610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanautoxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "fanauto.h" #include class AMD::FanAutoXMLParser::Initializer final : public AMD::FanAutoProfilePart::Exporter { public: Initializer(AMD::FanAutoXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::FanAutoXMLParser &outer_; }; void AMD::FanAutoXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } AMD::FanAutoXMLParser::FanAutoXMLParser() noexcept : ProfilePartXMLParser(AMD::FanAuto::ItemID, *this, *this) { } std::unique_ptr AMD::FanAutoXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::FanAutoXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::FanAutoXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::FanAutoXMLParser::provideImporter(Item const &) { return {}; } void AMD::FanAutoXMLParser::takeActive(bool active) { active_ = active; } bool AMD::FanAutoXMLParser::provideActive() const { return active_; } void AMD::FanAutoXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; } void AMD::FanAutoXMLParser::resetAttributes() { active_ = activeDefault_; } void AMD::FanAutoXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); } bool const AMD::FanAutoXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::FanAuto::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/auto/fanautoxmlparser.h000066400000000000000000000022511467225065400273240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "fanautoprofilepart.h" #include namespace AMD { class FanAutoXMLParser final : public ProfilePartXMLParser , public AMD::FanAutoProfilePart::Exporter , public AMD::FanAutoProfilePart::Importer { public: FanAutoXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/000077500000000000000000000000001467225065400237345ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurve.cpp000066400000000000000000000171061467225065400262560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fancurve.h" #include "common/mathutils.h" #include "core/components/commonutils.h" #include "core/icommandqueue.h" #include #include #include #include AMD::FanCurve::FanCurve( std::unique_ptr> &&pwmEnableDataSource, std::unique_ptr> &&pwmDataSource, std::unique_ptr> &&tempInputDataSource, units::temperature::celsius_t tempMin, units::temperature::celsius_t tempMax) noexcept : Control(false) , id_(AMD::FanCurve::ItemID) , pwmEnableDataSource_(std::move(pwmEnableDataSource)) , pwmDataSource_(std::move(pwmDataSource)) , tempInputDataSource_(std::move(tempInputDataSource)) , tempRange_(std::make_pair(tempMin, tempMax)) , fanStop_(false) , fanStartValue_(54) , hysteresis_(5) , lastPwmValue_(std::numeric_limits::max()) , lastFanStop_(false) { // default curve points_.emplace_back(units::temperature::celsius_t(35), units::make_unit(20)); points_.emplace_back(units::temperature::celsius_t(52), units::make_unit(22)); points_.emplace_back(units::temperature::celsius_t(67), units::make_unit(30)); points_.emplace_back(units::temperature::celsius_t(78), units::make_unit(50)); points_.emplace_back(units::temperature::celsius_t(85), units::make_unit(82)); Utils::Common::normalizePoints(points_, tempRange_); // compute fan start temperature fanStartTemp_ = evaluatePwm(std::round(fanStartValue_ / 2.55)); } void AMD::FanCurve::preInit(ICommandQueue &) { } void AMD::FanCurve::postInit(ICommandQueue &) { } void AMD::FanCurve::init() { } std::string const &AMD::FanCurve::ID() const { return id_; } void AMD::FanCurve::importControl(IControl::Importer &i) { auto &fanCurveImporter = dynamic_cast(i); curve(fanCurveImporter.provideFanCurvePoints()); fanStop(fanCurveImporter.provideFanCurveFanStop()); fanStartValue(static_cast(std::round( fanCurveImporter.provideFanCurveFanStartValue().to() * 255))); } void AMD::FanCurve::exportControl(IControl::Exporter &e) const { auto &fanCurveExporter = dynamic_cast(e); fanCurveExporter.takeFanCurveTemperatureRange(tempRange_.first, tempRange_.second); fanCurveExporter.takeFanCurvePoints(curve()); fanCurveExporter.takeFanCurveFanStop(fanStop()); fanCurveExporter.takeFanCurveFanStartValue(std::round(fanStartValue() / 2.55)); } void AMD::FanCurve::cleanControl(ICommandQueue &) { lastPwmValue_ = std::numeric_limits::max(); lastFanStop_ = false; } void AMD::FanCurve::syncControl(ICommandQueue &ctlCmds) { if (pwmEnableDataSource_->read(pwmEnable_) && pwmDataSource_->read(pwm_) && tempInputDataSource_->read(tempInput_)) { unsigned int pwmValue; if (fanStop() && ((pwm_ > 0 && tempInput_ < fanStartTemp_ - hysteresis_) || // stop it (pwm_ == 0 && tempInput_ < fanStartTemp_))) { // don't start it pwmValue = 0; } else { if (fanStop() && pwm_ > 0 && tempInput_ < fanStartTemp_) pwmValue = fanStartValue_; // cap it to fan start value else pwmValue = evaluateTemp(units::temperature::celsius_t(tempInput_)); } if (pwmEnable_ != 1) { ctlCmds.add({pwmEnableDataSource_->source(), "1"}); ctlCmds.add({pwmDataSource_->source(), std::to_string(pwmValue)}); } // NOTE pwm_ must be checked as well. The value that the hardware uses // doesn't have to match the assigned value through pwm1. // See: https://bugs.freedesktop.org/show_bug.cgi?id=110213 else if ((pwm_ != pwmValue && lastPwmValue_ != pwmValue) || lastFanStop_ != fanStop()) { // force sync ctlCmds.add({pwmDataSource_->source(), std::to_string(pwmValue)}); } lastPwmValue_ = pwmValue; lastFanStop_ = fanStop(); } } std::vector const &AMD::FanCurve::curve() const { return points_; } void AMD::FanCurve::curve(std::vector const &points) { points_ = points; Utils::Common::normalizePoints(points_, tempRange_); fanStartTemp_ = evaluatePwm(std::round(fanStartValue_ / 2.55)); } bool AMD::FanCurve::fanStop() const { return fanStop_; } void AMD::FanCurve::fanStop(bool enable) { fanStop_ = enable; } unsigned int AMD::FanCurve::fanStartValue() const { return fanStartValue_; } void AMD::FanCurve::fanStartValue(unsigned int value) { fanStartValue_ = static_cast(std::clamp(value, 0u, 255u)); fanStartTemp_ = evaluatePwm(std::round(fanStartValue_ / 2.55)); } int AMD::FanCurve::hysteresis() const { return hysteresis_; } int AMD::FanCurve::evaluatePwm(units::concentration::percent_t input) const { if (points_.size() > 1) { auto pIt = std::find_if(points_.cbegin(), points_.cend(), [=](auto const &p) { return p.second > input; }); auto &p1 = (pIt == points_.cbegin() ? *pIt : (pIt == points_.cend() ? *std::prev(std::prev(pIt)) : *std::prev(pIt))); auto &p2 = (pIt == points_.cend() ? *std::prev(pIt) : (pIt == points_.cbegin() ? *std::next(pIt) : *pIt)); return lerpFromPwm(input, p1, p2); } else if (points_.size() == 1) return static_cast(std::round(points_.front().first.to())); else return 0; } int AMD::FanCurve::lerpFromPwm(units::concentration::percent_t input, AMD::FanCurve::Point const &p1, AMD::FanCurve::Point const &p2) const { input = std::clamp(input, p1.second, p2.second); return static_cast(std::round(Utils::Math::lerpY( input.to(), std::make_pair(p1.first.to(), p1.second.to()), std::make_pair(p2.first.to(), p2.second.to())))); } unsigned int AMD::FanCurve::evaluateTemp(units::temperature::celsius_t input) const { if (points_.size() > 1) { auto pIt = std::find_if(points_.cbegin(), points_.cend(), [=](auto const &p) { return p.first > input; }); auto &p1 = (pIt == points_.cbegin() ? *pIt : (pIt == points_.cend() ? *std::prev(std::prev(pIt)) : *std::prev(pIt))); auto &p2 = (pIt == points_.cend() ? *std::prev(pIt) : (pIt == points_.cbegin() ? *std::next(pIt) : *pIt)); return lerpFromTemp(input, p1, p2); } else if (points_.size() == 1) return static_cast( std::round(points_.front().second.to() * 255)); else return 0; } unsigned int AMD::FanCurve::lerpFromTemp(units::temperature::celsius_t input, AMD::FanCurve::Point const &p1, AMD::FanCurve::Point const &p2) const { input = std::clamp(input, p1.first, p2.first); return static_cast(std::round( Utils::Math::lerpX( input.to(), std::make_pair(p1.first.to(), p1.second.to()), std::make_pair(p2.first.to(), p2.second.to())) * 255)); // scale to [0, 255] range of pwm1 } corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurve.h000066400000000000000000000065141467225065400257240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include namespace AMD { class FanCurve : public Control { public: static constexpr std::string_view ItemID{"AMD_FAN_CURVE"}; using Point = std::pair; class Importer : public IControl::Importer { public: virtual std::vector const &provideFanCurvePoints() const = 0; virtual bool provideFanCurveFanStop() const = 0; virtual units::concentration::percent_t provideFanCurveFanStartValue() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takeFanCurvePoints(std::vector const &points) = 0; virtual void takeFanCurveFanStop(bool enabled) = 0; virtual void takeFanCurveFanStartValue(units::concentration::percent_t value) = 0; virtual void takeFanCurveTemperatureRange(units::temperature::celsius_t min, units::temperature::celsius_t max) = 0; }; FanCurve(std::unique_ptr> &&pwmEnableDataSource, std::unique_ptr> &&pwmDataSource, std::unique_ptr> &&tempInputDataSource, units::temperature::celsius_t tempMin, units::temperature::celsius_t tempMax) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::vector const &curve() const; void curve(std::vector const &points); bool fanStop() const; void fanStop(bool active); unsigned int fanStartValue() const; void fanStartValue(unsigned int value); int hysteresis() const; int evaluatePwm(units::concentration::percent_t input) const; int lerpFromPwm(units::concentration::percent_t input, FanCurve::Point const &p1, FanCurve::Point const &p2) const; unsigned int evaluateTemp(units::temperature::celsius_t input) const; unsigned int lerpFromTemp(units::temperature::celsius_t input, FanCurve::Point const &p1, FanCurve::Point const &p2) const; private: std::string const id_; std::unique_ptr> const pwmEnableDataSource_; std::unique_ptr> const pwmDataSource_; std::unique_ptr> const tempInputDataSource_; std::pair const tempRange_; unsigned int pwmEnable_; unsigned int pwm_; int tempInput_; bool fanStop_; unsigned int fanStartValue_; int fanStartTemp_; int const hysteresis_; unsigned int lastPwmValue_; bool lastFanStop_; std::vector points_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurveprofilepart.cpp000066400000000000000000000102201467225065400305140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fancurveprofilepart.h" #include "core/components/commonutils.h" #include "core/profilepartprovider.h" #include #include class AMD::FanCurveProfilePart::Initializer final : public AMD::FanCurve::Exporter { public: Initializer(AMD::FanCurveProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanCurvePoints(std::vector const &points) override; void takeFanCurveFanStop(bool enabled) override; void takeFanCurveFanStartValue(units::concentration::percent_t value) override; void takeFanCurveTemperatureRange(units::temperature::celsius_t min, units::temperature::celsius_t max) override; private: AMD::FanCurveProfilePart &outer_; }; void AMD::FanCurveProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::FanCurveProfilePart::Initializer::takeFanCurvePoints( std::vector const &points) { outer_.points_ = points; } void AMD::FanCurveProfilePart::Initializer::takeFanCurveFanStop(bool enabled) { outer_.fanStop_ = enabled; } void AMD::FanCurveProfilePart::Initializer::takeFanCurveFanStartValue( units::concentration::percent_t value) { outer_.fanStartValue_ = value; } void AMD::FanCurveProfilePart::Initializer::takeFanCurveTemperatureRange( units::temperature::celsius_t min, units::temperature::celsius_t max) { outer_.tempRange_ = std::make_pair(min, max); } AMD::FanCurveProfilePart::FanCurveProfilePart() noexcept : id_(AMD::FanCurve::ItemID) { } std::unique_ptr AMD::FanCurveProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::FanCurveProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::FanCurveProfilePart::ID() const { return id_; } std::optional> AMD::FanCurveProfilePart::provideImporter(Item const &) { return {}; } bool AMD::FanCurveProfilePart::provideActive() const { return active(); } std::vector const & AMD::FanCurveProfilePart::provideFanCurvePoints() const { return points_; } bool AMD::FanCurveProfilePart::provideFanCurveFanStop() const { return fanStop_; } units::concentration::percent_t AMD::FanCurveProfilePart::provideFanCurveFanStartValue() const { return fanStartValue_; } void AMD::FanCurveProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmfImporter = dynamic_cast(i); points(pmfImporter.provideFanCurvePoints()); fanStop_ = pmfImporter.provideFanCurveFanStop(); startValue(pmfImporter.provideFanCurveFanStartValue()); } void AMD::FanCurveProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmfExporter = dynamic_cast(e); pmfExporter.takeFanCurvePoints(points_); pmfExporter.takeFanCurveFanStop(fanStop_); pmfExporter.takeFanCurveFanStartValue(fanStartValue_); } std::unique_ptr AMD::FanCurveProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->tempRange_ = tempRange_; clone->points_ = points_; clone->fanStop_ = fanStop_; clone->fanStartValue_ = fanStartValue_; return std::move(clone); } void AMD::FanCurveProfilePart::points(std::vector const &points) { points_ = points; Utils::Common::normalizePoints(points_, tempRange_); } void AMD::FanCurveProfilePart::startValue(units::concentration::percent_t value) { fanStartValue_ = std::clamp(value, units::concentration::percent_t(0), units::concentration::percent_t(100)); } bool const AMD::FanCurveProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::FanCurve::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurveprofilepart.h000066400000000000000000000042061467225065400301700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "fancurve.h" #include #include #include namespace AMD { class FanCurveProfilePart final : public ProfilePart , public AMD::FanCurve::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::vector const &provideFanCurvePoints() const = 0; virtual bool provideFanCurveFanStop() const = 0; virtual units::concentration::percent_t provideFanCurveFanStartValue() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeFanCurvePoints(std::vector const &points) = 0; virtual void takeFanCurveFanStop(bool enabled) = 0; virtual void takeFanCurveFanStartValue(units::concentration::percent_t value) = 0; }; FanCurveProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::vector const &provideFanCurvePoints() const override; bool provideFanCurveFanStop() const override; units::concentration::percent_t provideFanCurveFanStartValue() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void points(std::vector const &points); void startValue(units::concentration::percent_t value); class Initializer; std::string const id_; std::vector points_; std::pair tempRange_; bool fanStop_; units::concentration::percent_t fanStartValue_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurveprovider.cpp000066400000000000000000000065561467225065400300400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fancurveprovider.h" #include "../fanmodeprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/amd/gpuinfoodfanctrl.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "fancurve.h" #include #include #include #include std::vector> AMD::FanCurveProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { std::vector> controls; if (!(gpuInfo.vendor() == Vendor::AMD && !gpuInfo.hasCapability(GPUInfoOdFanCtrl::ID))) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; auto pwmEnable = path.value() / "pwm1_enable"; auto pwm = path.value() / "pwm1"; auto tempInput = path.value() / "temp1_input"; auto tempCrit = path.value() / "temp1_crit"; if (!(Utils::File::isSysFSEntryValid(pwm) && Utils::File::isSysFSEntryValid(pwmEnable) && Utils::File::isSysFSEntryValid(tempInput) && Utils::File::isSysFSEntryValid(tempCrit))) return {}; int tempCritValue{0}; Utils::String::toNumber(tempCritValue, Utils::File::readFileLines(tempCrit).front()); tempCritValue = (tempCritValue > 0 && tempCritValue < 150000) // check bogus values, see #103 ? tempCritValue / 1000 : 90; unsigned int value; auto pwmEnableLines = Utils::File::readFileLines(pwmEnable); if (!Utils::String::toNumber(value, pwmEnableLines.front())) { SPDLOG_WARN("Unknown data format on {}", pwmEnable.string()); SPDLOG_DEBUG(pwmEnableLines.front()); return {}; } auto pwmLines = Utils::File::readFileLines(pwm); if (!Utils::String::toNumber(value, pwmLines.front())) { SPDLOG_WARN("Unknown data format on {}", pwm.string()); SPDLOG_DEBUG(pwmLines.front()); return {}; } int tempInputValue; auto tempInputLines = Utils::File::readFileLines(tempInput); if (!Utils::String::toNumber(tempInputValue, tempInputLines.front())) { SPDLOG_WARN("Unknown data format on {}", tempInput.string()); SPDLOG_DEBUG(tempInputLines.front()); return {}; } controls.emplace_back(std::make_unique( std::make_unique>( pwmEnable, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }), std::make_unique>( pwm, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }), std::make_unique>( tempInput, [](std::string const &data, int &output) { int value; Utils::String::toNumber(value, data); output = value / 1000; }), units::temperature::celsius_t(0), units::temperature::celsius_t(tempCritValue))); return controls; } bool const AMD::FanCurveProvider::registered_ = AMD::FanModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurveprovider.h000066400000000000000000000007471467225065400275010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class FanCurveProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurveqmlitem.cpp000066400000000000000000000150741467225065400276510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fancurveqmlitem.h" #include "core/qmlcomponentregistry.h" #include "fancurve.h" #include #include #include #include #include #include #include #include #include char const *const AMD::FanCurveQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_FAN_CURVE"), }; class AMD::FanCurveQMLItem::Initializer final : public QMLItem::Initializer , public AMD::FanCurve::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::FanCurveQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanCurvePoints(std::vector const &points) override; void takeFanCurveFanStop(bool enabled) override; void takeFanCurveFanStartValue(units::concentration::percent_t value) override; void takeFanCurveTemperatureRange(units::temperature::celsius_t min, units::temperature::celsius_t max) override; private: AMD::FanCurveQMLItem &outer_; }; void AMD::FanCurveQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::FanCurveQMLItem::Initializer::takeFanCurvePoints( std::vector const &points) { outer_.takeFanCurvePoints(points); } void AMD::FanCurveQMLItem::Initializer::takeFanCurveFanStop(bool enabled) { outer_.takeFanCurveFanStop(enabled); } void AMD::FanCurveQMLItem::Initializer::takeFanCurveFanStartValue( units::concentration::percent_t value) { outer_.takeFanCurveFanStartValue(value); } void AMD::FanCurveQMLItem::Initializer::takeFanCurveTemperatureRange( units::temperature::celsius_t min, units::temperature::celsius_t max) { outer_.temperatureRange(min, max); } AMD::FanCurveQMLItem::FanCurveQMLItem() noexcept { setName(tr(AMD::FanCurve::ItemID.data())); } void AMD::FanCurveQMLItem::enableFanStop(bool enabled) { if (fanStop_ != enabled) { fanStop_ = enabled; emit fanStopChanged(fanStop_); emit settingsChanged(); } } void AMD::FanCurveQMLItem::changeFanStartValue(qreal value) { auto newValue = static_cast(std::round(value)); if (fanStartValue_ != newValue) { fanStartValue_ = newValue; emit fanStartValueChanged(fanStartValue_); emit settingsChanged(); } } void AMD::FanCurveQMLItem::updateCurvePoint(QPointF const &oldPoint, QPointF const &newPoint) { if (oldPoint != newPoint) { auto oPoint = std::make_pair( units::temperature::celsius_t(std::round(oldPoint.x())), units::concentration::percent_t(std::round(oldPoint.y()))); auto nPoint = std::make_pair( units::temperature::celsius_t(std::round(newPoint.x())), units::concentration::percent_t(std::round(newPoint.y()))); for (size_t i = 0; i < points_.size(); ++i) { if (points_[i] == oPoint) { points_[i] = nPoint; qPoints_.replace(static_cast(i), newPoint); emit curveChanged(qPoints_); emit settingsChanged(); break; } } } } void AMD::FanCurveQMLItem::activate(bool active) { takeActive(active); } QVariantList const &AMD::FanCurveQMLItem::curve() const { return qPoints_; } bool AMD::FanCurveQMLItem::fanStop() const { return fanStop_; } qreal AMD::FanCurveQMLItem::fanStartValue() const { return static_cast(fanStartValue_); } qreal AMD::FanCurveQMLItem::minTemp() const { return minTemp_; } qreal AMD::FanCurveQMLItem::maxTemp() const { return maxTemp_; } std::optional> AMD::FanCurveQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::FanCurveQMLItem::provideExporter(Item const &) { return {}; } bool AMD::FanCurveQMLItem::provideActive() const { return active_; } std::vector const & AMD::FanCurveQMLItem::provideFanCurvePoints() const { return points_; } bool AMD::FanCurveQMLItem::provideFanCurveFanStop() const { return fanStop_; } units::concentration::percent_t AMD::FanCurveQMLItem::provideFanCurveFanStartValue() const { return fanStartValue_; } void AMD::FanCurveQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::FanCurveQMLItem::takeFanCurvePoints( std::vector const &points) { if (points_ != points) { points_ = points; qPoints_.clear(); for (auto const &[temp, pwm] : points_) qPoints_.push_back(QPointF(temp.to(), pwm.to() * 100)); emit curveChanged(qPoints_); } } void AMD::FanCurveQMLItem::takeFanCurveFanStop(bool active) { if (fanStop_ != active) { fanStop_ = active; emit fanStopChanged(fanStop_); } } void AMD::FanCurveQMLItem::takeFanCurveFanStartValue( units::concentration::percent_t value) { auto newValue = static_cast(value * 100); if (fanStartValue_ != newValue) { fanStartValue_ = newValue; emit fanStartValueChanged(fanStartValue_); } } std::unique_ptr AMD::FanCurveQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::FanCurveQMLItem::temperatureRange(units::temperature::celsius_t min, units::temperature::celsius_t max) { minTemp_ = min.to(); maxTemp_ = max.to(); emit temperatureRangeChanged(minTemp_, maxTemp_); } bool AMD::FanCurveQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::FanCurve::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::FanCurve::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDFanCurveForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::FanCurveQMLItem::registered_ = AMD::FanCurveQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurveqmlitem.h000066400000000000000000000051221467225065400273070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "fancurveprofilepart.h" #include #include #include #include #include namespace AMD { class FanCurveQMLItem : public QMLItem , public AMD::FanCurveProfilePart::Importer , public AMD::FanCurveProfilePart::Exporter { Q_OBJECT Q_PROPERTY(bool fanStop READ fanStop WRITE enableFanStop NOTIFY fanStopChanged) Q_PROPERTY(qreal fanStartValue READ fanStartValue WRITE changeFanStartValue NOTIFY fanStartValueChanged) Q_PROPERTY(qreal minTemp READ minTemp) Q_PROPERTY(qreal maxTemp READ maxTemp) public: explicit FanCurveQMLItem() noexcept; signals: void curveChanged(QVariantList const &points); void fanStopChanged(bool enabled); void fanStartValueChanged(qreal value); void temperatureRangeChanged(qreal min, qreal max); public slots: void enableFanStop(bool enabled); void changeFanStartValue(qreal value); void updateCurvePoint(QPointF const &oldPoint, QPointF const &newPoint); public: void activate(bool active) override; QVariantList const &curve() const; bool fanStop() const; qreal fanStartValue() const; qreal minTemp() const; qreal maxTemp() const; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; std::vector const &provideFanCurvePoints() const override; bool provideFanCurveFanStop() const override; units::concentration::percent_t provideFanCurveFanStartValue() const override; void takeActive(bool active) override; void takeFanCurvePoints(std::vector const &points) override; void takeFanCurveFanStop(bool enabled) override; void takeFanCurveFanStartValue(units::concentration::percent_t value) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: void temperatureRange(units::temperature::celsius_t min, units::temperature::celsius_t max); class Initializer; bool active_; std::vector points_; QVariantList qPoints_; bool fanStop_; unsigned int fanStartValue_; qreal minTemp_; qreal maxTemp_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurvexmlparser.cpp000066400000000000000000000121631467225065400302120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fancurvexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "fancurve.h" #include #include class AMD::FanCurveXMLParser::Initializer final : public AMD::FanCurveProfilePart::Exporter { public: Initializer(AMD::FanCurveXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanCurvePoints(std::vector const &points) override; void takeFanCurveFanStop(bool enabled) override; void takeFanCurveFanStartValue(units::concentration::percent_t value) override; private: AMD::FanCurveXMLParser &outer_; }; void AMD::FanCurveXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::FanCurveXMLParser::Initializer::takeFanCurvePoints( std::vector const &points) { outer_.points_ = outer_.pointsDefault_ = points; } void AMD::FanCurveXMLParser::Initializer::takeFanCurveFanStop(bool enabled) { outer_.fanStop_ = outer_.fanStopDefault_ = enabled; } void AMD::FanCurveXMLParser::Initializer::takeFanCurveFanStartValue( units::concentration::percent_t value) { outer_.fanStartValue_ = outer_.fanStartValueDefault_ = value * 100; } AMD::FanCurveXMLParser::FanCurveXMLParser() noexcept : ProfilePartXMLParser(AMD::FanCurve::ItemID, *this, *this) { } std::unique_ptr AMD::FanCurveXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::FanCurveXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::FanCurveXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::FanCurveXMLParser::provideImporter(Item const &) { return {}; } void AMD::FanCurveXMLParser::takeActive(bool active) { active_ = active; } bool AMD::FanCurveXMLParser::provideActive() const { return active_; } void AMD::FanCurveXMLParser::takeFanCurvePoints( std::vector const &points) { points_ = points; } std::vector const & AMD::FanCurveXMLParser::provideFanCurvePoints() const { return points_; } void AMD::FanCurveXMLParser::takeFanCurveFanStop(bool enabled) { fanStop_ = enabled; } bool AMD::FanCurveXMLParser::provideFanCurveFanStop() const { return fanStop_; } void AMD::FanCurveXMLParser::takeFanCurveFanStartValue( units::concentration::percent_t value) { fanStartValue_ = value * 100; } units::concentration::percent_t AMD::FanCurveXMLParser::provideFanCurveFanStartValue() const { return fanStartValue_; } void AMD::FanCurveXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; pmFixedNode.append_attribute("fanStop") = fanStop_; pmFixedNode.append_attribute("fanStartValue") = fanStartValue_; auto curveNode = pmFixedNode.append_child(CurveNodeName.data()); for (auto const &[temp, pwm] : points_) { auto pointNode = curveNode.append_child(PointNodeName.data()); pointNode.append_attribute("temp") = temp.to(); pointNode.append_attribute("pwm") = static_cast(std::round(pwm.to() * 100)); } } void AMD::FanCurveXMLParser::resetAttributes() { active_ = activeDefault_; points_ = pointsDefault_; fanStop_ = fanStopDefault_; fanStartValue_ = fanStartValueDefault_; } void AMD::FanCurveXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); fanStop_ = pmFixedNode.attribute("fanStop").as_bool(fanStopDefault_); fanStartValue_ = pmFixedNode.attribute("fanStartValue").as_uint(fanStartValueDefault_); auto curveNode = pmFixedNode.find_child( [&](pugi::xml_node const &node) { return node.name() == CurveNodeName; }); if (!curveNode) { points_ = pointsDefault_; } else { points_.clear(); for (auto pointNode : curveNode.children(PointNodeName.data())) { auto tempAttr = pointNode.attribute("temp"); auto pwmAttr = pointNode.attribute("pwm"); if (tempAttr && pwmAttr) { points_.emplace_back(units::temperature::celsius_t(tempAttr.as_int()), units::concentration::percent_t(pwmAttr.as_uint())); } else { // malformed point data -> restore defaults points_ = pointsDefault_; break; } } if (points_.size() < 2) // two or more points are needed points_ = pointsDefault_; } } bool const AMD::FanCurveXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::FanCurve::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/curve/fancurvexmlparser.h000066400000000000000000000036771467225065400276710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "fancurveprofilepart.h" #include #include #include namespace AMD { class FanCurveXMLParser final : public ProfilePartXMLParser , public AMD::FanCurveProfilePart::Exporter , public AMD::FanCurveProfilePart::Importer { public: FanCurveXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takeFanCurvePoints(std::vector const &points) override; std::vector const &provideFanCurvePoints() const override; void takeFanCurveFanStop(bool enabled) override; bool provideFanCurveFanStop() const override; void takeFanCurveFanStartValue(units::concentration::percent_t value) override; units::concentration::percent_t provideFanCurveFanStartValue() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: static constexpr std::string_view CurveNodeName{"CURVE"}; static constexpr std::string_view PointNodeName{"POINT"}; class Initializer; bool active_; bool activeDefault_; std::vector points_; std::vector pointsDefault_; bool fanStop_; bool fanStopDefault_; unsigned int fanStartValue_; unsigned int fanStartValueDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmode.h000066400000000000000000000010231467225065400243660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmode.h" #include #include #include #include namespace AMD { class FanMode : public ControlMode { public: static constexpr std::string_view ItemID{"AMD_FAN_MODE"}; FanMode(std::vector> &&controls) noexcept : ControlMode(FanMode::ItemID, std::move(controls), true) { } }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodeprofilepart.cpp000066400000000000000000000012111467225065400271700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanmodeprofilepart.h" #include "core/profilepartprovider.h" #include "fanmode.h" #include AMD::FanModeProfilePart::FanModeProfilePart() noexcept : ControlModeProfilePart(AMD::FanMode::ItemID) { } std::unique_ptr AMD::FanModeProfilePart::instance() const { return std::make_unique(); } bool const AMD::FanModeProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::FanMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodeprofilepart.h000066400000000000000000000007041467225065400266430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodeprofilepart.h" namespace AMD { class FanModeProfilePart final : public ControlModeProfilePart { public: FanModeProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodeprovider.cpp000066400000000000000000000035261467225065400265060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanmodeprovider.h" #include "core/components/controls/gpucontrolprovider.h" #include "core/components/controls/noop.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "fanmode.h" #include #include std::vector> AMD::FanModeProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::vector> modeControls; for (auto const &provider : gpuControlProviders()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); modeControls.insert(modeControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (modeControls.empty()) return {}; modeControls.emplace_back(std::make_unique()); std::vector> controls; controls.emplace_back(std::make_unique(std::move(modeControls))); return controls; } std::vector> const & AMD::FanModeProvider::gpuControlProviders() const { return providers_(); } bool AMD::FanModeProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::FanModeProvider::providers_() { static std::vector> providers; return providers; } bool const AMD::FanModeProvider::registered_ = GPUControlProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodeprovider.h000066400000000000000000000015251467225065400261500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class FanModeProvider final : public IGPUControlProvider::IProvider , public IGPUControlProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; std::vector> const & gpuControlProviders() const final override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodeqmlitem.cpp000066400000000000000000000020211467225065400263110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanmodeqmlitem.h" #include "core/qmlcomponentregistry.h" #include "fanmode.h" #include #include #include #include #include AMD::FanModeQMLItem::FanModeQMLItem() noexcept : ControlModeQMLItem(AMD::FanMode::ItemID) { } bool AMD::FanModeQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::FanMode::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::FanMode::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDFanModeForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::FanModeQMLItem::registered_ = AMD::FanModeQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodeqmlitem.h000066400000000000000000000006001467225065400257570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodeqmlitem.h" namespace AMD { class FanModeQMLItem : public ControlModeQMLItem { public: explicit FanModeQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodexmlparser.cpp000066400000000000000000000010021467225065400266540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanmodexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "fanmode.h" #include AMD::FanModeXMLParser::FanModeXMLParser() noexcept : ControlModeXMLParser(AMD::FanMode::ItemID) { } bool const AMD::FanModeXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::FanMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/fanmodexmlparser.h000066400000000000000000000005521467225065400263320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodexmlparser.h" namespace AMD { class FanModeXMLParser final : public ControlModeXMLParser { public: FanModeXMLParser() noexcept; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/000077500000000000000000000000001467225065400237075ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixed.cpp000066400000000000000000000057011467225065400262020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanfixed.h" #include "core/icommandqueue.h" #include #include #include #include AMD::FanFixed::FanFixed( std::unique_ptr> &&pwmEnableDataSource, std::unique_ptr> &&pwmDataSource) noexcept : Control(false) , id_(AMD::FanFixed::ItemID) , pwmEnableDataSource_(std::move(pwmEnableDataSource)) , pwmDataSource_(std::move(pwmDataSource)) , value_(64) , lastValue_(std::numeric_limits::max()) , fanStop_(false) , fanStartValue_(54) { } void AMD::FanFixed::preInit(ICommandQueue &) { } void AMD::FanFixed::postInit(ICommandQueue &) { } void AMD::FanFixed::init() { } std::string const &AMD::FanFixed::ID() const { return id_; } void AMD::FanFixed::importControl(IControl::Importer &i) { auto &fanFixedImporter = dynamic_cast(i); value(static_cast( std::round(fanFixedImporter.provideFanFixedValue().to() * 255))); fanStop(fanFixedImporter.provideFanFixedFanStop()); fanStartValue(static_cast(std::round( fanFixedImporter.provideFanFixedFanStartValue().to() * 255))); } void AMD::FanFixed::exportControl(IControl::Exporter &e) const { auto &fanFixedExporter = dynamic_cast(e); fanFixedExporter.takeFanFixedValue(std::round(value() / 2.55)); fanFixedExporter.takeFanFixedFanStop(fanStop()); fanFixedExporter.takeFanFixedFanStartValue(std::round(fanStartValue() / 2.55)); } void AMD::FanFixed::cleanControl(ICommandQueue &) { lastValue_ = std::numeric_limits::max(); } void AMD::FanFixed::syncControl(ICommandQueue &ctlCmds) { if (pwmEnableDataSource_->read(pwmEnable_) && pwmDataSource_->read(pwm_)) { auto pwmValue = (fanStop() && value() < fanStartValue()) ? 0 : value(); if (pwmEnable_ != 1) { ctlCmds.add({pwmEnableDataSource_->source(), "1"}); ctlCmds.add({pwmDataSource_->source(), std::to_string(pwmValue)}); } // NOTE pwm_ must be checked as well. The value that the hardware uses // doesn't have to match the assigned value through pwm1. // See: https://bugs.freedesktop.org/show_bug.cgi?id=110213 else if (pwm_ != pwmValue && lastValue_ != pwmValue) { ctlCmds.add({pwmDataSource_->source(), std::to_string(pwmValue)}); } lastValue_ = pwmValue; } } unsigned int AMD::FanFixed::value() const { return value_; } void AMD::FanFixed::value(unsigned int value) { value_ = static_cast(std::clamp(value, 0u, 255u)); } bool AMD::FanFixed::fanStop() const { return fanStop_; } void AMD::FanFixed::fanStop(bool enable) { fanStop_ = enable; } unsigned int AMD::FanFixed::fanStartValue() const { return fanStartValue_; } void AMD::FanFixed::fanStartValue(unsigned int value) { fanStartValue_ = static_cast(std::clamp(value, 0u, 255u)); } corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixed.h000066400000000000000000000041221467225065400256430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include namespace AMD { class FanFixed : public Control { public: static constexpr std::string_view ItemID{"AMD_FAN_FIXED"}; class Importer : public IControl::Importer { public: virtual units::concentration::percent_t provideFanFixedValue() const = 0; virtual bool provideFanFixedFanStop() const = 0; virtual units::concentration::percent_t provideFanFixedFanStartValue() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takeFanFixedValue(units::concentration::percent_t value) = 0; virtual void takeFanFixedFanStop(bool enabled) = 0; virtual void takeFanFixedFanStartValue(units::concentration::percent_t value) = 0; }; FanFixed(std::unique_ptr> &&pwmEnableDataSource, std::unique_ptr> &&pwmDataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; unsigned int value() const; void value(unsigned int value); bool fanStop() const; void fanStop(bool active); unsigned int fanStartValue() const; void fanStartValue(unsigned int value); private: std::string const id_; std::unique_ptr> const pwmEnableDataSource_; std::unique_ptr> const pwmDataSource_; unsigned int pwmEnable_; unsigned int pwm_; unsigned int value_; unsigned int lastValue_; bool fanStop_; unsigned int fanStartValue_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedprofilepart.cpp000066400000000000000000000073711467225065400304570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanfixedprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class AMD::FanFixedProfilePart::Initializer final : public AMD::FanFixed::Exporter { public: Initializer(AMD::FanFixedProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanFixedValue(units::concentration::percent_t value) override; void takeFanFixedFanStop(bool enabled) override; void takeFanFixedFanStartValue(units::concentration::percent_t value) override; private: AMD::FanFixedProfilePart &outer_; }; void AMD::FanFixedProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::FanFixedProfilePart::Initializer::takeFanFixedValue( units::concentration::percent_t value) { outer_.value_ = value; } void AMD::FanFixedProfilePart::Initializer::takeFanFixedFanStop(bool enabled) { outer_.fanStop_ = enabled; } void AMD::FanFixedProfilePart::Initializer::takeFanFixedFanStartValue( units::concentration::percent_t value) { outer_.fanStartValue_ = value; } AMD::FanFixedProfilePart::FanFixedProfilePart() noexcept : id_(AMD::FanFixed::ItemID) { } std::unique_ptr AMD::FanFixedProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::FanFixedProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::FanFixedProfilePart::ID() const { return id_; } std::optional> AMD::FanFixedProfilePart::provideImporter(Item const &) { return {}; } bool AMD::FanFixedProfilePart::provideActive() const { return active(); } units::concentration::percent_t AMD::FanFixedProfilePart::provideFanFixedValue() const { return value_; } bool AMD::FanFixedProfilePart::provideFanFixedFanStop() const { return fanStop_; } units::concentration::percent_t AMD::FanFixedProfilePart::provideFanFixedFanStartValue() const { return fanStartValue_; } void AMD::FanFixedProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmfImporter = dynamic_cast(i); value(pmfImporter.provideFanFixedValue()); fanStop_ = pmfImporter.provideFanFixedFanStop(); startValue(pmfImporter.provideFanFixedFanStartValue()); } void AMD::FanFixedProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmfExporter = dynamic_cast(e); pmfExporter.takeFanFixedValue(value_); pmfExporter.takeFanFixedFanStop(fanStop_); pmfExporter.takeFanFixedFanStartValue(fanStartValue_); } std::unique_ptr AMD::FanFixedProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->value_ = value_; clone->fanStop_ = fanStop_; clone->fanStartValue_ = fanStartValue_; return std::move(clone); } void AMD::FanFixedProfilePart::value(units::concentration::percent_t value) { value_ = std::clamp(value, units::concentration::percent_t(0), units::concentration::percent_t(100)); } void AMD::FanFixedProfilePart::startValue(units::concentration::percent_t value) { fanStartValue_ = std::clamp(value, units::concentration::percent_t(0), units::concentration::percent_t(100)); } bool const AMD::FanFixedProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::FanFixed::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedprofilepart.h000066400000000000000000000037641467225065400301260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "fanfixed.h" #include namespace AMD { class FanFixedProfilePart final : public ProfilePart , public AMD::FanFixed::Importer { public: class Importer : public IProfilePart::Importer { public: virtual units::concentration::percent_t provideFanFixedValue() const = 0; virtual bool provideFanFixedFanStop() const = 0; virtual units::concentration::percent_t provideFanFixedFanStartValue() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeFanFixedValue(units::concentration::percent_t value) = 0; virtual void takeFanFixedFanStop(bool enabled) = 0; virtual void takeFanFixedFanStartValue(units::concentration::percent_t value) = 0; }; FanFixedProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; units::concentration::percent_t provideFanFixedValue() const override; bool provideFanFixedFanStop() const override; units::concentration::percent_t provideFanFixedFanStartValue() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void value(units::concentration::percent_t value); void startValue(units::concentration::percent_t value); class Initializer; std::string const id_; units::concentration::percent_t value_; bool fanStop_; units::concentration::percent_t fanStartValue_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedprovider.cpp000066400000000000000000000043731467225065400277610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanfixedprovider.h" #include "../fanmodeprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/amd/gpuinfoodfanctrl.h" #include "core/info/igpuinfo.h" #include "core/info/iswinfo.h" #include "core/sysfsdatasource.h" #include "fanfixed.h" #include #include #include #include std::vector> AMD::FanFixedProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && !gpuInfo.hasCapability(GPUInfoOdFanCtrl::ID))) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; auto pwmEnable = path.value() / "pwm1_enable"; auto pwm = path.value() / "pwm1"; if (!(Utils::File::isSysFSEntryValid(pwm) && Utils::File::isSysFSEntryValid(pwmEnable))) return {}; unsigned int value; auto pwmEnableLines = Utils::File::readFileLines(pwmEnable); if (!Utils::String::toNumber(value, pwmEnableLines.front())) { SPDLOG_WARN("Unknown data format on {}", pwmEnable.string()); SPDLOG_DEBUG(pwmEnableLines.front()); return {}; } auto pwmLines = Utils::File::readFileLines(pwm); if (!Utils::String::toNumber(value, pwmLines.front())) { SPDLOG_WARN("Unknown data format on {}", pwm.string()); SPDLOG_DEBUG(pwmLines.front()); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>( pwmEnable, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }), std::make_unique>( pwm, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }))); return controls; } bool const AMD::FanFixedProvider::registered_ = AMD::FanModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedprovider.h000066400000000000000000000007471467225065400274270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class FanFixedProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedqmlitem.cpp000066400000000000000000000112211467225065400275650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanfixedqmlitem.h" #include "core/qmlcomponentregistry.h" #include "fanfixed.h" #include #include #include char const *const AMD::FanFixedQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_FAN_FIXED"), }; class AMD::FanFixedQMLItem::Initializer final : public QMLItem::Initializer , public AMD::FanFixed::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::FanFixedQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanFixedValue(units::concentration::percent_t value) override; void takeFanFixedFanStop(bool enabled) override; void takeFanFixedFanStartValue(units::concentration::percent_t value) override; private: AMD::FanFixedQMLItem &outer_; }; void AMD::FanFixedQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::FanFixedQMLItem::Initializer::takeFanFixedValue( units::concentration::percent_t value) { outer_.takeFanFixedValue(value); } void AMD::FanFixedQMLItem::Initializer::takeFanFixedFanStop(bool enabled) { outer_.takeFanFixedFanStop(enabled); } void AMD::FanFixedQMLItem::Initializer::takeFanFixedFanStartValue( units::concentration::percent_t value) { outer_.takeFanFixedFanStartValue(value); } AMD::FanFixedQMLItem::FanFixedQMLItem() noexcept { setName(tr(AMD::FanFixed::ItemID.data())); } void AMD::FanFixedQMLItem::changeValue(int value) { if (value_ != value) { value_ = value; emit valueChanged(value_); emit settingsChanged(); } } void AMD::FanFixedQMLItem::enableFanStop(bool enabled) { if (fanStop_ != enabled) { fanStop_ = enabled; emit fanStopChanged(fanStop_); emit settingsChanged(); } } void AMD::FanFixedQMLItem::changeFanStartValue(int value) { if (fanStartValue_ != value) { fanStartValue_ = value; emit fanStartValueChanged(fanStartValue_); emit settingsChanged(); } } void AMD::FanFixedQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::FanFixedQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::FanFixedQMLItem::provideExporter(Item const &) { return {}; } bool AMD::FanFixedQMLItem::provideActive() const { return active_; } units::concentration::percent_t AMD::FanFixedQMLItem::provideFanFixedValue() const { return value_; } bool AMD::FanFixedQMLItem::provideFanFixedFanStop() const { return fanStop_; } units::concentration::percent_t AMD::FanFixedQMLItem::provideFanFixedFanStartValue() const { return fanStartValue_; } void AMD::FanFixedQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::FanFixedQMLItem::takeFanFixedValue(units::concentration::percent_t value) { auto newValue = static_cast(value * 100); if (value_ != newValue) { value_ = newValue; emit valueChanged(value_); } } void AMD::FanFixedQMLItem::takeFanFixedFanStop(bool active) { if (fanStop_ != active) { fanStop_ = active; emit fanStopChanged(fanStop_); } } void AMD::FanFixedQMLItem::takeFanFixedFanStartValue( units::concentration::percent_t value) { auto newValue = static_cast(value * 100); if (fanStartValue_ != newValue) { fanStartValue_ = newValue; emit fanStartValueChanged(fanStartValue_); } } std::unique_ptr AMD::FanFixedQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } bool AMD::FanFixedQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::FanFixed::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::FanFixed::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDFanFixedForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::FanFixedQMLItem::registered_ = AMD::FanFixedQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedqmlitem.h000066400000000000000000000033711467225065400272410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "fanfixedprofilepart.h" #include namespace AMD { class FanFixedQMLItem : public QMLItem , public AMD::FanFixedProfilePart::Importer , public AMD::FanFixedProfilePart::Exporter { Q_OBJECT public: explicit FanFixedQMLItem() noexcept; signals: void valueChanged(int value); void fanStopChanged(bool enabled); void fanStartValueChanged(int value); public slots: void changeValue(int value); void enableFanStop(bool enabled); void changeFanStartValue(int value); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; units::concentration::percent_t provideFanFixedValue() const override; bool provideFanFixedFanStop() const override; units::concentration::percent_t provideFanFixedFanStartValue() const override; void takeActive(bool active) override; void takeFanFixedValue(units::concentration::percent_t value) override; void takeFanFixedFanStop(bool enabled) override; void takeFanFixedFanStartValue(units::concentration::percent_t value) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; bool active_; int value_; bool fanStop_; int fanStartValue_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedxmlparser.cpp000066400000000000000000000100501467225065400301310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanfixedxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "fanfixed.h" #include class AMD::FanFixedXMLParser::Initializer final : public AMD::FanFixedProfilePart::Exporter { public: Initializer(AMD::FanFixedXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanFixedValue(units::concentration::percent_t value) override; void takeFanFixedFanStop(bool enabled) override; void takeFanFixedFanStartValue(units::concentration::percent_t value) override; private: AMD::FanFixedXMLParser &outer_; }; void AMD::FanFixedXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::FanFixedXMLParser::Initializer::takeFanFixedValue( units::concentration::percent_t value) { outer_.value_ = outer_.valueDefault_ = value * 100; } void AMD::FanFixedXMLParser::Initializer::takeFanFixedFanStop(bool enabled) { outer_.fanStop_ = outer_.fanStopDefault_ = enabled; } void AMD::FanFixedXMLParser::Initializer::takeFanFixedFanStartValue( units::concentration::percent_t value) { outer_.fanStartValue_ = outer_.fanStartValueDefault_ = value * 100; } AMD::FanFixedXMLParser::FanFixedXMLParser() noexcept : ProfilePartXMLParser(AMD::FanFixed::ItemID, *this, *this) { } std::unique_ptr AMD::FanFixedXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::FanFixedXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::FanFixedXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::FanFixedXMLParser::provideImporter(Item const &) { return {}; } void AMD::FanFixedXMLParser::takeActive(bool active) { active_ = active; } bool AMD::FanFixedXMLParser::provideActive() const { return active_; } void AMD::FanFixedXMLParser::takeFanFixedValue(units::concentration::percent_t value) { value_ = value * 100; } units::concentration::percent_t AMD::FanFixedXMLParser::provideFanFixedValue() const { return value_; } void AMD::FanFixedXMLParser::takeFanFixedFanStop(bool enabled) { fanStop_ = enabled; } bool AMD::FanFixedXMLParser::provideFanFixedFanStop() const { return fanStop_; } void AMD::FanFixedXMLParser::takeFanFixedFanStartValue( units::concentration::percent_t value) { fanStartValue_ = value * 100; } units::concentration::percent_t AMD::FanFixedXMLParser::provideFanFixedFanStartValue() const { return fanStartValue_; } void AMD::FanFixedXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; pmFixedNode.append_attribute("value") = value_; pmFixedNode.append_attribute("fanStop") = fanStop_; pmFixedNode.append_attribute("fanStartValue") = fanStartValue_; } void AMD::FanFixedXMLParser::resetAttributes() { active_ = activeDefault_; value_ = valueDefault_; fanStop_ = fanStopDefault_; fanStartValue_ = fanStartValueDefault_; } void AMD::FanFixedXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); value_ = pmFixedNode.attribute("value").as_int(valueDefault_); fanStop_ = pmFixedNode.attribute("fanStop").as_bool(fanStopDefault_); fanStartValue_ = pmFixedNode.attribute("fanStartValue").as_int(fanStartValueDefault_); } bool const AMD::FanFixedXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::FanFixed::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/fixed/fanfixedxmlparser.h000066400000000000000000000033601467225065400276040ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "fanfixedprofilepart.h" #include namespace AMD { class FanFixedXMLParser final : public ProfilePartXMLParser , public AMD::FanFixedProfilePart::Exporter , public AMD::FanFixedProfilePart::Importer { public: FanFixedXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takeFanFixedValue(units::concentration::percent_t value) override; units::concentration::percent_t provideFanFixedValue() const override; void takeFanFixedFanStop(bool enabled) override; bool provideFanFixedFanStop() const override; void takeFanFixedFanStartValue(units::concentration::percent_t value) override; units::concentration::percent_t provideFanFixedFanStartValue() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; unsigned int value_; unsigned int valueDefault_; bool fanStop_; bool fanStopDefault_; unsigned int fanStartValue_; unsigned int fanStartValueDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/000077500000000000000000000000001467225065400246155ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/000077500000000000000000000000001467225065400255655ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanauto.cpp000066400000000000000000000031751467225065400302570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfanauto.h" #include "core/icommandqueue.h" #include AMD::OdFanAuto::OdFanAuto( std::unique_ptr>> &&dataSource) noexcept : Control(true) , id_(AMD::OdFanAuto::ItemID) , triggerAutoOpMode_(true) , dataSource_(std::move(dataSource)) { } void AMD::OdFanAuto::preInit(ICommandQueue &) { } void AMD::OdFanAuto::postInit(ICommandQueue &) { } void AMD::OdFanAuto::init() { } std::string const &AMD::OdFanAuto::ID() const { return id_; } void AMD::OdFanAuto::importControl(IControl::Importer &) { } void AMD::OdFanAuto::exportControl(IControl::Exporter &) const { } void AMD::OdFanAuto::cleanControl(ICommandQueue &) { triggerAutoOpMode_ = true; } void AMD::OdFanAuto::syncControl(ICommandQueue &ctlCmds) { if (triggerAutoOpMode_) { addResetCmds(ctlCmds); triggerAutoOpMode_ = false; } } void AMD::OdFanAuto::addResetCmds(ICommandQueue &ctlCmds) const { ctlCmds.add({dataSource_->source(), "r"}); // NOTE Apparently, there is no need to submit the commit command after the // reset one on the new fan overdrive interfaces [1]. This interaction model // digress from the overdrive clock-voltage interface model, where the reset // command only restores the default values without actually committing them. // // Submit a commit command just in case this is changed to align with the // original overdrive interface interaction model. // // [1] https://gitlab.freedesktop.org/drm/amd/-/issues/2402#note_2211197 ctlCmds.add({dataSource_->source(), "c"}); } corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanauto.h000066400000000000000000000022171467225065400277200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include namespace AMD { class OdFanAuto : public Control { public: static constexpr std::string_view ItemID{"AMD_OD_FAN_AUTO"}; OdFanAuto(std::unique_ptr>> &&dataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: void addResetCmds(ICommandQueue &ctlCmds) const; std::string const id_; bool triggerAutoOpMode_; std::unique_ptr>> const dataSource_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoprofilepart.cpp000066400000000000000000000035131467225065400325230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfanautoprofilepart.h" #include "core/profilepartprovider.h" #include class AMD::OdFanAutoProfilePart::Initializer final : public AMD::OdFanAuto::Exporter { public: Initializer(AMD::OdFanAutoProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::OdFanAutoProfilePart &outer_; }; void AMD::OdFanAutoProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } AMD::OdFanAutoProfilePart::OdFanAutoProfilePart() noexcept : id_(AMD::OdFanAuto::ItemID) { } std::unique_ptr AMD::OdFanAutoProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::OdFanAutoProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::OdFanAutoProfilePart::ID() const { return id_; } std::optional> AMD::OdFanAutoProfilePart::provideImporter(Item const &) { return {}; } bool AMD::OdFanAutoProfilePart::provideActive() const { return active(); } void AMD::OdFanAutoProfilePart::importProfilePart(IProfilePart::Importer &) { } void AMD::OdFanAutoProfilePart::exportProfilePart(IProfilePart::Exporter &) const { } std::unique_ptr AMD::OdFanAutoProfilePart::cloneProfilePart() const { return std::make_unique(); } bool const AMD::OdFanAutoProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::OdFanAuto::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoprofilepart.h000066400000000000000000000021721467225065400321700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/profilepart.h" #include "odfanauto.h" #include namespace AMD { class OdFanAutoProfilePart final : public ProfilePart , public AMD::OdFanAuto::Importer { public: class Importer : public IProfilePart::Importer { }; class Exporter : public IProfilePart::Exporter { }; OdFanAutoProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: class Initializer; std::string const id_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoprovider.cpp000066400000000000000000000077201467225065400320320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfanautoprovider.h" #include "../../fanmodeprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/amd/gpuinfoodfanctrl.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "odfanauto.h" #include #include std::vector> AMD::OdFanAutoProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { std::vector> controls; if (!(gpuInfo.vendor() == Vendor::AMD && gpuInfo.hasCapability(GPUInfoOdFanCtrl::ID))) return {}; // Attempt to create a data source from one of the overdrive fan controls that // triggers the auto fan mode. auto dataSource = createOdFanTargetTempDataSource(gpuInfo); if (!dataSource) dataSource = createOdFanMinPWMDataSource(gpuInfo); if (!dataSource) dataSource = createOdFanAcousticTargetDataSource(gpuInfo); if (!dataSource) dataSource = createOdFanAcousticLimitDataSource(gpuInfo); if (dataSource) controls.emplace_back( std::make_unique(std::move(*dataSource))); return controls; } std::optional>>> AMD::OdFanAutoProvider::createOdFanTargetTempDataSource(IGPUInfo const &gpuInfo) const { auto path = gpuInfo.path().sys / "gpu_od" / "fan_ctrl" / "fan_target_temperature"; if (!Utils::File::isSysFSEntryValid(path)) return {}; auto data = Utils::File::readFileLines(path); if (!Utils::AMD::hasOverdriveFanTargetTempControl(data)) { SPDLOG_WARN("Unknown data format on {}", path.string()); SPDLOG_DEBUG(data.front()); return {}; } return createDataSource(std::move(path)); } std::optional>>> AMD::OdFanAutoProvider::createOdFanMinPWMDataSource(IGPUInfo const &gpuInfo) const { auto path = gpuInfo.path().sys / "gpu_od" / "fan_ctrl" / "fan_minimum_pwm"; if (!Utils::File::isSysFSEntryValid(path)) return {}; auto data = Utils::File::readFileLines(path); if (!Utils::AMD::hasOverdriveFanMinimumPWMControl(data)) { SPDLOG_WARN("Unknown data format on {}", path.string()); SPDLOG_DEBUG(data.front()); return {}; } return createDataSource(std::move(path)); } std::optional>>> AMD::OdFanAutoProvider::createOdFanAcousticTargetDataSource( IGPUInfo const &gpuInfo) const { auto path = gpuInfo.path().sys / "gpu_od" / "fan_ctrl" / "acoustic_target_rpm_threshold"; if (!Utils::File::isSysFSEntryValid(path)) return {}; auto data = Utils::File::readFileLines(path); if (!Utils::AMD::hasOverdriveFanAcousticTargetControl(data)) { SPDLOG_WARN("Unknown data format on {}", path.string()); SPDLOG_DEBUG(data.front()); return {}; } return createDataSource(std::move(path)); } std::optional>>> AMD::OdFanAutoProvider::createOdFanAcousticLimitDataSource( IGPUInfo const &gpuInfo) const { auto path = gpuInfo.path().sys / "gpu_od" / "fan_ctrl" / "acoustic_limit_rpm_threshold"; if (!Utils::File::isSysFSEntryValid(path)) return {}; auto data = Utils::File::readFileLines(path); if (!Utils::AMD::hasOverdriveFanAcousticLimitControl(data)) { SPDLOG_WARN("Unknown data format on {}", path.string()); SPDLOG_DEBUG(data.front()); return {}; } return createDataSource(std::move(path)); } std::unique_ptr>> AMD::OdFanAutoProvider::createDataSource(std::filesystem::path &&path) const { return std::make_unique>>( std::move(path)); } bool const AMD::OdFanAutoProvider::registered_ = AMD::FanModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoprovider.h000066400000000000000000000024031467225065400314700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include "core/idatasource.h" #include #include #include #include #include namespace AMD { class OdFanAutoProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: std::optional>>> createOdFanTargetTempDataSource(IGPUInfo const &gpuInfo) const; std::optional>>> createOdFanMinPWMDataSource(IGPUInfo const &gpuInfo) const; std::optional>>> createOdFanAcousticTargetDataSource(IGPUInfo const &gpuInfo) const; std::optional>>> createOdFanAcousticLimitDataSource(IGPUInfo const &gpuInfo) const; std::unique_ptr>> createDataSource(std::filesystem::path &&path) const; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoqmlitem.cpp000066400000000000000000000051511467225065400316440ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfanautoqmlitem.h" #include "core/qmlcomponentregistry.h" #include "odfanauto.h" #include #include #include #include #include #include char const *const AMD::OdFanAutoQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_OD_FAN_AUTO"), }; class AMD::OdFanAutoQMLItem::Initializer final : public QMLItem::Initializer , public IControl::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::OdFanAutoQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::OdFanAutoQMLItem &outer_; }; void AMD::OdFanAutoQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } AMD::OdFanAutoQMLItem::OdFanAutoQMLItem() noexcept { setName(tr(OdFanAuto::ItemID.data())); } void AMD::OdFanAutoQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::OdFanAutoQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::OdFanAutoQMLItem::provideExporter(Item const &) { return {}; } bool AMD::OdFanAutoQMLItem::provideActive() const { return active_; } void AMD::OdFanAutoQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } std::unique_ptr AMD::OdFanAutoQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } bool AMD::OdFanAutoQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::OdFanAuto::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::OdFanAuto::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDOdFanAutoForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::OdFanAutoQMLItem::registered_ = AMD::OdFanAutoQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoqmlitem.h000066400000000000000000000020641467225065400313110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/qmlitem.h" #include "odfanautoprofilepart.h" #include namespace AMD { class OdFanAutoQMLItem : public QMLItem , public AMD::OdFanAutoProfilePart::Importer , public AMD::OdFanAutoProfilePart::Exporter { Q_OBJECT public: explicit OdFanAutoQMLItem() noexcept; void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; bool active_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoxmlparser.cpp000066400000000000000000000044101467225065400322060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfanautoxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "odfanauto.h" #include class AMD::OdFanAutoXMLParser::Initializer final : public AMD::OdFanAutoProfilePart::Exporter { public: Initializer(AMD::OdFanAutoXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::OdFanAutoXMLParser &outer_; }; void AMD::OdFanAutoXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } AMD::OdFanAutoXMLParser::OdFanAutoXMLParser() noexcept : ProfilePartXMLParser(AMD::OdFanAuto::ItemID, *this, *this) { } std::unique_ptr AMD::OdFanAutoXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::OdFanAutoXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::OdFanAutoXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::OdFanAutoXMLParser::provideImporter(Item const &) { return {}; } void AMD::OdFanAutoXMLParser::takeActive(bool active) { active_ = active; } bool AMD::OdFanAutoXMLParser::provideActive() const { return active_; } void AMD::OdFanAutoXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; } void AMD::OdFanAutoXMLParser::resetAttributes() { active_ = activeDefault_; } void AMD::OdFanAutoXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); } bool const AMD::OdFanAutoXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::OdFanAuto::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/auto/odfanautoxmlparser.h000066400000000000000000000022631467225065400316570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "odfanautoprofilepart.h" #include namespace AMD { class OdFanAutoXMLParser final : public ProfilePartXMLParser , public AMD::OdFanAutoProfilePart::Exporter , public AMD::OdFanAutoProfilePart::Importer { public: OdFanAutoXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/000077500000000000000000000000001467225065400257415ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurve.cpp000066400000000000000000000172371467225065400306130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfancurve.h" #include "core/components/amdutils.h" #include "core/components/commonutils.h" #include "core/icommandqueue.h" #include #include #include AMD::OdFanCurve::OdFanCurve( std::unique_ptr>> &&dataSource) noexcept : Control(false) , id_(AMD::OdFanCurve::ItemID) , dataSource_(std::move(dataSource)) , triggerManualOpMode_(true) { } void AMD::OdFanCurve::preInit(ICommandQueue &ctlCmds) { if (!dataSource_->read(fanCurveLines_)) return; preInitControlPoints_ = Utils::AMD::parseOverdriveFanCurve(fanCurveLines_).value(); addResetCmds(ctlCmds); } void AMD::OdFanCurve::postInit(ICommandQueue &ctlCmds) { if (isZeroCurve(preInitControlPoints_)) return; // Restore pre-init points. normalizeCurve(preInitControlPoints_, tempRange(), speedRange()); for (auto const &point : preInitControlPoints_) ctlCmds.add({dataSource_->source(), controlPointCmd(point)}); ctlCmds.add({dataSource_->source(), "c"}); } void AMD::OdFanCurve::init() { if (!dataSource_->read(fanCurveLines_)) return; tempRange_ = Utils::AMD::parseOverdriveFanCurveTempRange(fanCurveLines_).value(); speedRange_ = Utils::AMD::parseOverdriveFanCurveSpeedRange(fanCurveLines_).value(); controlPoints_ = Utils::AMD::parseOverdriveFanCurve(fanCurveLines_).value(); if (isZeroCurve(controlPoints_)) setPointCoordinatesFrom(controlPoints_, defaultCurve()); normalizeCurve(controlPoints_, tempRange_, speedRange_); } std::string const &AMD::OdFanCurve::ID() const { return id_; } void AMD::OdFanCurve::importControl(IControl::Importer &i) { auto &fanCurveImporter = dynamic_cast(i); fanCurve(fanCurveImporter.provideFanCurve()); } void AMD::OdFanCurve::exportControl(IControl::Exporter &e) const { auto &fanCurveExporter = dynamic_cast(e); fanCurveExporter.takeFanCurveRange(tempRange(), speedRange()); fanCurveExporter.takeFanCurve(fanCurve()); } void AMD::OdFanCurve::cleanControl(ICommandQueue &ctlCmds) { addResetCmds(ctlCmds); triggerManualOpMode_ = true; } void AMD::OdFanCurve::syncControl(ICommandQueue &ctlCmds) { if (!dataSource_->read(fanCurveLines_)) return; bool outOfSync = addSyncCmds(ctlCmds); if (triggerManualOpMode_ && !outOfSync) { // NOTE The new fan overdrive interfaces has an implicit operation mode [1] // (auto or manual, used for the fan_curve interface) that is selected by // the last interface the user interacts with. However, a change to the // curve must be submitted to actually trigger the operation mode (either // different points or a reset command) [2]. // // Trigger the manual operation mode by sending a reset command when the // curve is already in sync. // // [1] https://www.kernel.org/doc/html/v6.7/gpu/amdgpu/thermal.html#fan-curve // [2] https://gitlab.freedesktop.org/drm/amd/-/issues/2402#note_2211197 addResetCmds(ctlCmds); triggerManualOpMode_ = false; } } std::vector AMD::OdFanCurve::defaultCurve() const { // clang-format off std::vector> defaultCurve = { {units::temperature::celsius_t(35), units::concentration::percent_t(20)}, {units::temperature::celsius_t(52), units::concentration::percent_t(22)}, {units::temperature::celsius_t(67), units::concentration::percent_t(30)}, {units::temperature::celsius_t(78), units::concentration::percent_t(50)}, {units::temperature::celsius_t(85), units::concentration::percent_t(82)} }; // clang-format on return defaultCurve; } std::vector AMD::OdFanCurve::fanCurve() const { return toCurvePoints(controlPoints()); } void AMD::OdFanCurve::fanCurve(std::vector points) { Utils::Common::normalizePoints(points, tempRange(), speedRange()); setPointCoordinatesFrom(controlPoints_, points); } std::vector const & AMD::OdFanCurve::controlPoints() const { return controlPoints_; } AMD::OdFanCurve::TempRange const &AMD::OdFanCurve::tempRange() const { return tempRange_; } AMD::OdFanCurve::SpeedRange const &AMD::OdFanCurve::speedRange() const { return speedRange_; } std::vector AMD::OdFanCurve::toCurvePoints( std::vector const &curve) const { std::vector points; std::transform(curve.cbegin(), curve.cend(), std::back_inserter(points), [](auto const &point) { return std::make_pair(std::get<1>(point), std::get<2>(point)); }); return points; } void AMD::OdFanCurve::setPointCoordinatesFrom( std::vector &curve, std::vector const &values) const { if (values.empty()) return; size_t i = 0; for (auto &point : curve) { auto value = values[i++]; std::get<1>(point) = value.first; std::get<2>(point) = value.second; if (i == values.size()) break; } } bool AMD::OdFanCurve::isZeroCurve( std::vector const &curve) const { // NOTE The overdrive curve interface reports all default device curve points // as zero point coordinates [1]. // // [1] https://gitlab.freedesktop.org/drm/amd/-/issues/2402#note_2210868 return std::all_of(curve.cbegin(), curve.cend(), [](auto const &point) { return std::get<1>(point) == units::temperature::celsius_t(0) && std::get<2>(point) == units::concentration::percent_t(0); }); } std::string AMD::OdFanCurve::controlPointCmd(ControlPoint const &point) const { std::string cmd; cmd.reserve(10); cmd.append(std::to_string(std::get<0>(point))) .append(" ") .append(std::to_string(std::get<1>(point).to())) .append(" ") .append(std::to_string(std::lround(std::get<2>(point).to() * 100))); return cmd; } void AMD::OdFanCurve::normalizeCurve( std::vector &curve, AMD::OdFanCurve::TempRange const &tempRange, AMD::OdFanCurve::SpeedRange const &speedRange) const { auto normalizedPoints = toCurvePoints(curve); Utils::Common::normalizePoints(normalizedPoints, tempRange, speedRange); setPointCoordinatesFrom(curve, normalizedPoints); } bool AMD::OdFanCurve::addSyncCmds(ICommandQueue &ctlCmds) const { bool commit = false; auto const curve = Utils::AMD::parseOverdriveFanCurve(fanCurveLines_).value(); size_t curveIndex = 0; for (auto const &point : controlPoints()) { auto const [_, temp, speed] = curve[curveIndex++]; if (temp != std::get<1>(point) || speed != std::get<2>(point)) { ctlCmds.add({dataSource_->source(), controlPointCmd(point)}); commit = true; } } if (commit) ctlCmds.add({dataSource_->source(), "c"}); return commit; } void AMD::OdFanCurve::addResetCmds(ICommandQueue &ctlCmds) const { ctlCmds.add({dataSource_->source(), "r"}); // NOTE Apparently, there is no need to submit the commit command after the // reset one on the new fan overdrive interfaces [1]. This interaction model // digress from the overdrive clock-voltage interface model, where the reset // command only restores the default values without actually committing them. // // Submit a commit command just in case this is changed to align with the // original overdrive interface interaction model. // // [1] https://gitlab.freedesktop.org/drm/amd/-/issues/2402#note_2211197 ctlCmds.add({dataSource_->source(), "c"}); } corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurve.h000066400000000000000000000061711467225065400302530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include #include namespace AMD { class OdFanCurve : public Control { public: static constexpr std::string_view ItemID{"AMD_OD_FAN_CURVE"}; using CurvePoint = std::pair; using TempRange = std::pair; using SpeedRange = std::pair; class Importer : public IControl::Importer { public: virtual std::vector const & provideFanCurve() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takeFanCurve(std::vector const &curve) = 0; virtual void takeFanCurveRange(AMD::OdFanCurve::TempRange temp, AMD::OdFanCurve::SpeedRange speed) = 0; }; OdFanCurve(std::unique_ptr>> &&dataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::vector defaultCurve() const; std::vector fanCurve() const; void fanCurve(std::vector points); using ControlPoint = std::tuple; std::vector const &controlPoints() const; TempRange const &tempRange() const; SpeedRange const &speedRange() const; std::vector toCurvePoints(std::vector const &curve) const; void setPointCoordinatesFrom(std::vector &curve, std::vector const &values) const; bool isZeroCurve(std::vector const &curve) const; std::string controlPointCmd(ControlPoint const &point) const; private: void normalizeCurve(std::vector &curve, TempRange const &tempRange, SpeedRange const &speedRange) const; bool addSyncCmds(ICommandQueue &ctlCmds) const; void addResetCmds(ICommandQueue &ctlCmds) const; std::string const id_; std::unique_ptr>> const dataSource_; TempRange tempRange_; SpeedRange speedRange_; std::vector preInitControlPoints_; std::vector controlPoints_; std::vector fanCurveLines_; bool triggerManualOpMode_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurveprofilepart.cpp000066400000000000000000000062011467225065400330500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfancurveprofilepart.h" #include "core/components/commonutils.h" #include "core/profilepartprovider.h" #include class AMD::OdFanCurveProfilePart::Initializer final : public AMD::OdFanCurve::Exporter { public: Initializer(AMD::OdFanCurveProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanCurve(std::vector const &curve) override; void takeFanCurveRange(AMD::OdFanCurve::TempRange temp, AMD::OdFanCurve::SpeedRange speed) override; private: AMD::OdFanCurveProfilePart &outer_; }; void AMD::OdFanCurveProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::OdFanCurveProfilePart::Initializer::takeFanCurve( std::vector const &curve) { outer_.curve_ = curve; } void AMD::OdFanCurveProfilePart::Initializer::takeFanCurveRange( AMD::OdFanCurve::TempRange temp, AMD::OdFanCurve::SpeedRange speed) { outer_.tempRange_ = temp; outer_.speedRange_ = speed; } AMD::OdFanCurveProfilePart::OdFanCurveProfilePart() noexcept : id_(AMD::OdFanCurve::ItemID) { } std::unique_ptr AMD::OdFanCurveProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::OdFanCurveProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::OdFanCurveProfilePart::ID() const { return id_; } std::optional> AMD::OdFanCurveProfilePart::provideImporter(Item const &) { return {}; } bool AMD::OdFanCurveProfilePart::provideActive() const { return active(); } std::vector const & AMD::OdFanCurveProfilePart::provideFanCurve() const { return curve_; } void AMD::OdFanCurveProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmfImporter = dynamic_cast(i); curve(pmfImporter.provideFanCurve()); } void AMD::OdFanCurveProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmfExporter = dynamic_cast(e); pmfExporter.takeFanCurve(curve_); } std::unique_ptr AMD::OdFanCurveProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->tempRange_ = tempRange_; clone->curve_ = curve_; clone->tempRange_ = tempRange_; clone->speedRange_ = speedRange_; return std::move(clone); } void AMD::OdFanCurveProfilePart::curve( std::vector const &curve) { curve_ = curve; Utils::Common::normalizePoints(curve_, tempRange_, speedRange_); } bool const AMD::OdFanCurveProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::OdFanCurve::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurveprofilepart.h000066400000000000000000000031751467225065400325240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/profilepart.h" #include "odfancurve.h" #include #include #include namespace AMD { class OdFanCurveProfilePart final : public ProfilePart , public AMD::OdFanCurve::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::vector const & provideFanCurve() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeFanCurve(std::vector const &curve) = 0; }; OdFanCurveProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::vector const &provideFanCurve() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void curve(std::vector const &points); class Initializer; std::string const id_; std::vector curve_; OdFanCurve::TempRange tempRange_; OdFanCurve::SpeedRange speedRange_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurveprovider.cpp000066400000000000000000000027271467225065400323640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfancurveprovider.h" #include "../../fanmodeprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/amd/gpuinfoodfanctrl.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "odfancurve.h" #include #include #include #include #include std::vector> AMD::OdFanCurveProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && gpuInfo.hasCapability(GPUInfoOdFanCtrl::ID))) return {}; auto path = gpuInfo.path().sys / "gpu_od" / "fan_ctrl" / "fan_curve"; if (!Utils::File::isSysFSEntryValid(path)) return {}; auto data = Utils::File::readFileLines(path); if (!Utils::AMD::hasOverdriveFanCurveControl(data)) { SPDLOG_WARN("Unknown data format on {}", path.string()); SPDLOG_DEBUG(data.front()); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>>( std::move(path)))); return controls; } bool const AMD::OdFanCurveProvider::registered_ = AMD::FanModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurveprovider.h000066400000000000000000000007511467225065400320240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class OdFanCurveProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurveqmlitem.cpp000066400000000000000000000124531467225065400321770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfancurveqmlitem.h" #include "core/qmlcomponentregistry.h" #include "odfancurve.h" #include #include #include #include #include #include #include #include char const *const AMD::OdFanCurveQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_OD_FAN_CURVE"), }; class AMD::OdFanCurveQMLItem::Initializer final : public QMLItem::Initializer , public AMD::OdFanCurve::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::OdFanCurveQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanCurve(std::vector const &curve) override; void takeFanCurveRange(AMD::OdFanCurve::TempRange temp, AMD::OdFanCurve::SpeedRange speed) override; private: AMD::OdFanCurveQMLItem &outer_; }; void AMD::OdFanCurveQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::OdFanCurveQMLItem::Initializer::takeFanCurve( std::vector const &curve) { outer_.takeFanCurve(curve); } void AMD::OdFanCurveQMLItem::Initializer::takeFanCurveRange( std::pair temp, std::pair speed) { outer_.curveRange(temp, speed); } AMD::OdFanCurveQMLItem::OdFanCurveQMLItem() noexcept { setName(tr(AMD::OdFanCurve::ItemID.data())); } void AMD::OdFanCurveQMLItem::updateCurvePoint(QPointF const &oldPoint, QPointF const &newPoint) { if (oldPoint != newPoint) { auto oPoint = std::make_pair( units::temperature::celsius_t(std::round(oldPoint.x())), units::concentration::percent_t(std::round(oldPoint.y()))); auto nPoint = std::make_pair( units::temperature::celsius_t(std::round(newPoint.x())), units::concentration::percent_t(std::round(newPoint.y()))); for (size_t i = 0; i < curve_.size(); ++i) { if (curve_[i] == oPoint) { curve_[i] = nPoint; qCurve_.replace(static_cast(i), newPoint); emit curveChanged(qCurve_); emit settingsChanged(); break; } } } } void AMD::OdFanCurveQMLItem::activate(bool active) { takeActive(active); } QVariantList const &AMD::OdFanCurveQMLItem::curve() const { return qCurve_; } qreal AMD::OdFanCurveQMLItem::minTemp() const { return minTemp_; } qreal AMD::OdFanCurveQMLItem::maxTemp() const { return maxTemp_; } qreal AMD::OdFanCurveQMLItem::minSpeed() const { return minSpeed_; } qreal AMD::OdFanCurveQMLItem::maxSpeed() const { return maxSpeed_; } std::optional> AMD::OdFanCurveQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::OdFanCurveQMLItem::provideExporter(Item const &) { return {}; } bool AMD::OdFanCurveQMLItem::provideActive() const { return active_; } std::vector const & AMD::OdFanCurveQMLItem::provideFanCurve() const { return curve_; } void AMD::OdFanCurveQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::OdFanCurveQMLItem::takeFanCurve( std::vector const &curve) { if (curve_ != curve) { curve_ = curve; qCurve_.clear(); for (auto const &[temp, speed] : curve_) qCurve_.push_back(QPointF(temp.to(), speed.to() * 100)); emit curveChanged(qCurve_); } } std::unique_ptr AMD::OdFanCurveQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::OdFanCurveQMLItem::curveRange( std::pair temp, std::pair speed) { minTemp_ = temp.first.to(); maxTemp_ = temp.second.to(); minSpeed_ = speed.first.to() * 100; maxSpeed_ = speed.second.to() * 100; emit curveRangeChanged(minTemp_, maxTemp_, minSpeed_, maxSpeed_); } bool AMD::OdFanCurveQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::OdFanCurve::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::OdFanCurve::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDOdFanCurveForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::OdFanCurveQMLItem::registered_ = AMD::OdFanCurveQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurveqmlitem.h000066400000000000000000000043111467225065400316360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/qmlitem.h" #include "odfancurveprofilepart.h" #include #include #include #include #include namespace AMD { class OdFanCurveQMLItem : public QMLItem , public AMD::OdFanCurveProfilePart::Importer , public AMD::OdFanCurveProfilePart::Exporter { Q_OBJECT Q_PROPERTY(qreal minTemp READ minTemp) Q_PROPERTY(qreal maxTemp READ maxTemp) Q_PROPERTY(qreal minSpeed READ minSpeed) Q_PROPERTY(qreal maxSpeed READ maxSpeed) public: explicit OdFanCurveQMLItem() noexcept; signals: void curveChanged(QVariantList const &curve); void curveRangeChanged(qreal tempMin, qreal tempMax, qreal speedMin, qreal speedMax); public slots: void updateCurvePoint(QPointF const &oldPoint, QPointF const &newPoint); public: void activate(bool active) override; QVariantList const &curve() const; qreal minTemp() const; qreal maxTemp() const; qreal minSpeed() const; qreal maxSpeed() const; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; std::vector const &provideFanCurve() const override; void takeActive(bool active) override; void takeFanCurve(std::vector const &curve) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: void curveRange( std::pair temp, std::pair speed); class Initializer; bool active_; std::vector curve_; QVariantList qCurve_; qreal minTemp_; qreal maxTemp_; qreal minSpeed_; qreal maxSpeed_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurvexmlparser.cpp000066400000000000000000000076411467225065400325470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "odfancurvexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "odfancurve.h" #include #include class AMD::OdFanCurveXMLParser::Initializer final : public AMD::OdFanCurveProfilePart::Exporter { public: Initializer(AMD::OdFanCurveXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeFanCurve(std::vector const &curve) override; private: AMD::OdFanCurveXMLParser &outer_; }; void AMD::OdFanCurveXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::OdFanCurveXMLParser::Initializer::takeFanCurve( std::vector const &curve) { outer_.curve_ = outer_.curveDefault_ = curve; } AMD::OdFanCurveXMLParser::OdFanCurveXMLParser() noexcept : ProfilePartXMLParser(AMD::OdFanCurve::ItemID, *this, *this) { } std::unique_ptr AMD::OdFanCurveXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::OdFanCurveXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::OdFanCurveXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::OdFanCurveXMLParser::provideImporter(Item const &) { return {}; } void AMD::OdFanCurveXMLParser::takeActive(bool active) { active_ = active; } bool AMD::OdFanCurveXMLParser::provideActive() const { return active_; } void AMD::OdFanCurveXMLParser::takeFanCurve( std::vector const &curve) { curve_ = curve; } std::vector const & AMD::OdFanCurveXMLParser::provideFanCurve() const { return curve_; } void AMD::OdFanCurveXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; auto curveNode = pmFixedNode.append_child(CurveNodeName.data()); for (auto const &[temp, speed] : curve_) { auto pointNode = curveNode.append_child(PointNodeName.data()); pointNode.append_attribute("temp") = temp.to(); pointNode.append_attribute("speed") = std::lround(speed.to() * 100); } } void AMD::OdFanCurveXMLParser::resetAttributes() { active_ = activeDefault_; curve_ = curveDefault_; } void AMD::OdFanCurveXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); auto curveNode = pmFixedNode.find_child( [&](pugi::xml_node const &node) { return node.name() == CurveNodeName; }); if (!curveNode) { curve_ = curveDefault_; } else { curve_.clear(); for (auto pointNode : curveNode.children(PointNodeName.data())) { auto tempAttr = pointNode.attribute("temp"); auto speedAttr = pointNode.attribute("speed"); if (tempAttr && speedAttr) { curve_.emplace_back(units::temperature::celsius_t(tempAttr.as_int()), units::concentration::percent_t(speedAttr.as_uint())); } else { // malformed point data -> restore defaults curve_ = curveDefault_; break; } } if (curve_.size() < 2) // two or more points are needed curve_ = curveDefault_; } } bool const AMD::OdFanCurveXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::OdFanCurve::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/fan/overdrive/curve/odfancurvexmlparser.h000066400000000000000000000031361467225065400322070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "odfancurveprofilepart.h" #include #include #include namespace AMD { class OdFanCurveXMLParser final : public ProfilePartXMLParser , public AMD::OdFanCurveProfilePart::Exporter , public AMD::OdFanCurveProfilePart::Importer { public: OdFanCurveXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takeFanCurve(std::vector const &curve) override; std::vector const &provideFanCurve() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: static constexpr std::string_view CurveNodeName{"CURVE"}; static constexpr std::string_view PointNodeName{"POINT"}; class Initializer; bool active_; bool activeDefault_; std::vector curve_; std::vector curveDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/000077500000000000000000000000001467225065400224605ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/000077500000000000000000000000001467225065400242255ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/000077500000000000000000000000001467225065400265275ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreq.cpp000066400000000000000000000020221467225065400320660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmdynamicfreq.h" #include "core/icommandqueue.h" #include AMD::PMDynamicFreq::PMDynamicFreq( std::unique_ptr> &&perfLevelDataSource) noexcept : Control(false) , id_(AMD::PMDynamicFreq::ItemID) , perfLevelDataSource_(std::move(perfLevelDataSource)) { } void AMD::PMDynamicFreq::preInit(ICommandQueue &) { } void AMD::PMDynamicFreq::postInit(ICommandQueue &) { } void AMD::PMDynamicFreq::init() { } std::string const &AMD::PMDynamicFreq::ID() const { return id_; } void AMD::PMDynamicFreq::importControl(IControl::Importer &) { } void AMD::PMDynamicFreq::exportControl(IControl::Exporter &) const { } void AMD::PMDynamicFreq::cleanControl(ICommandQueue &) { } void AMD::PMDynamicFreq::syncControl(ICommandQueue &ctlCmds) { if (perfLevelDataSource_->read(dataSourceEntry_)) { if (dataSourceEntry_ != "auto") ctlCmds.add({perfLevelDataSource_->source(), "auto"}); } } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreq.h000066400000000000000000000021121467225065400315330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include namespace AMD { class PMDynamicFreq : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_DYNAMIC_FREQ"}; PMDynamicFreq( std::unique_ptr> &&perfLevelDataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: std::string const id_; std::unique_ptr> const perfLevelDataSource_; std::string dataSourceEntry_; }; } // namespace AMD pmdynamicfreqprofilepart.cpp000066400000000000000000000036361467225065400342730ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmdynamicfreqprofilepart.h" #include "core/profilepartprovider.h" #include class AMD::PMDynamicFreqProfilePart::Initializer final : public PMDynamicFreq::Exporter { public: Initializer(AMD::PMDynamicFreqProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::PMDynamicFreqProfilePart &outer_; }; void AMD::PMDynamicFreqProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } AMD::PMDynamicFreqProfilePart::PMDynamicFreqProfilePart() noexcept : id_(AMD::PMDynamicFreq::ItemID) { } std::unique_ptr AMD::PMDynamicFreqProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMDynamicFreqProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMDynamicFreqProfilePart::ID() const { return id_; } std::optional> AMD::PMDynamicFreqProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMDynamicFreqProfilePart::provideActive() const { return active(); } void AMD::PMDynamicFreqProfilePart::importProfilePart(IProfilePart::Importer &) { } void AMD::PMDynamicFreqProfilePart::exportProfilePart(IProfilePart::Exporter &) const { } std::unique_ptr AMD::PMDynamicFreqProfilePart::cloneProfilePart() const { return std::make_unique(); } bool const AMD::PMDynamicFreqProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMDynamicFreq::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqprofilepart.h000066400000000000000000000022041467225065400340050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmdynamicfreq.h" #include namespace AMD { class PMDynamicFreqProfilePart final : public ProfilePart , public PMDynamicFreq::Importer { public: class Importer : public IProfilePart::Importer { }; class Exporter : public IProfilePart::Exporter { }; PMDynamicFreqProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: class Initializer; std::string const id_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqprovider.cpp000066400000000000000000000024351467225065400336510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmdynamicfreqprovider.h" #include "../freqmode/pmfreqmodeprovider.h" #include "common/fileutils.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmdynamicfreq.h" #include #include #include std::vector> AMD::PMDynamicFreqProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver != "amdgpu") return {}; auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; if (!Utils::File::isSysFSEntryValid(perfLevel)) return {}; std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>(perfLevel))); return controls; } bool AMD::PMDynamicFreqProvider::register_() { AMD::PMFreqModeProvider::registerProvider( std::make_unique()); return true; } bool const AMD::PMDynamicFreqProvider::registered_ = AMD::PMDynamicFreqProvider::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqprovider.h000066400000000000000000000010071467225065400333100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMDynamicFreqProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqqmlitem.cpp000066400000000000000000000052531467225065400334700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmdynamicfreqqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmdynamicfreq.h" #include #include #include #include #include #include char const *const AMD::PMDynamicFreqQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_PM_DYNAMIC_FREQ"), }; class AMD::PMDynamicFreqQMLItem::Initializer final : public QMLItem::Initializer , public IControl::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMDynamicFreqQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::PMDynamicFreqQMLItem &outer_; }; void AMD::PMDynamicFreqQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } AMD::PMDynamicFreqQMLItem::PMDynamicFreqQMLItem() noexcept { setName(tr(PMDynamicFreq::ItemID.data())); } void AMD::PMDynamicFreqQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMDynamicFreqQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMDynamicFreqQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMDynamicFreqQMLItem::provideActive() const { return active_; } void AMD::PMDynamicFreqQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } std::unique_ptr AMD::PMDynamicFreqQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } bool AMD::PMDynamicFreqQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType( "CoreCtrl.UIComponents", 1, 0, AMD::PMDynamicFreq::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMDynamicFreq::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMDynamicFreqForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMDynamicFreqQMLItem::registered_ = AMD::PMDynamicFreqQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqqmlitem.h000066400000000000000000000021201467225065400331230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmdynamicfreqprofilepart.h" #include namespace AMD { class PMDynamicFreqQMLItem : public QMLItem , public AMD::PMDynamicFreqProfilePart::Importer , public AMD::PMDynamicFreqProfilePart::Exporter { Q_OBJECT public: explicit PMDynamicFreqQMLItem() noexcept; public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; bool active_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqxmlparser.cpp000066400000000000000000000045731467225065400340410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmdynamicfreqxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmdynamicfreq.h" #include class AMD::PMDynamicFreqXMLParser::Initializer final : public AMD::PMDynamicFreqProfilePart::Exporter { public: Initializer(AMD::PMDynamicFreqXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::PMDynamicFreqXMLParser &outer_; }; void AMD::PMDynamicFreqXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } AMD::PMDynamicFreqXMLParser::PMDynamicFreqXMLParser() noexcept : ProfilePartXMLParser(AMD::PMDynamicFreq::ItemID, *this, *this) { } std::unique_ptr AMD::PMDynamicFreqXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMDynamicFreqXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMDynamicFreqXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMDynamicFreqXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMDynamicFreqXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMDynamicFreqXMLParser::provideActive() const { return active_; } void AMD::PMDynamicFreqXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFrequencyNode = parentNode.append_child(ID().c_str()); pmFrequencyNode.append_attribute("active") = active_; } void AMD::PMDynamicFreqXMLParser::resetAttributes() { active_ = activeDefault_; } void AMD::PMDynamicFreqXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFrequencyNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFrequencyNode.attribute("active").as_bool(activeDefault_); } bool const AMD::PMDynamicFreqXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMDynamicFreq::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreqxmlparser.h000066400000000000000000000023071467225065400334770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmdynamicfreqprofilepart.h" #include namespace AMD { class PMDynamicFreqXMLParser final : public ProfilePartXMLParser , public AMD::PMDynamicFreqProfilePart::Exporter , public AMD::PMDynamicFreqProfilePart::Importer { public: PMDynamicFreqXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/000077500000000000000000000000001467225065400262025ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreq.cpp000066400000000000000000000041171467225065400312230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedfreq.h" #include "core/components/controls/amd/pm/handlers/ippdpmhandler.h" #include "core/icommandqueue.h" AMD::PMFixedFreq::PMFixedFreq(std::unique_ptr &&ppDpmSclkHandler, std::unique_ptr &&ppDpmMclkHandler) noexcept : Control(true) , id_(AMD::PMFixedFreq::ItemID) , ppDpmSclkHandler_(std::move(ppDpmSclkHandler)) , ppDpmMclkHandler_(std::move(ppDpmMclkHandler)) { auto &sclkStates = ppDpmSclkHandler_->states(); if (!sclkStates.empty()) ppDpmSclkHandler_->activate({sclkStates.front().first}); auto &mclkStates = ppDpmMclkHandler_->states(); if (!mclkStates.empty()) ppDpmMclkHandler_->activate({mclkStates.front().first}); } void AMD::PMFixedFreq::preInit(ICommandQueue &) { } void AMD::PMFixedFreq::postInit(ICommandQueue &) { } void AMD::PMFixedFreq::init() { } std::string const &AMD::PMFixedFreq::ID() const { return id_; } void AMD::PMFixedFreq::importControl(IControl::Importer &i) { auto &pmFixedFreqImporter = dynamic_cast(i); ppDpmSclkHandler_->activate( {pmFixedFreqImporter.providePMFixedFreqSclkIndex()}); ppDpmMclkHandler_->activate( {pmFixedFreqImporter.providePMFixedFreqMclkIndex()}); } void AMD::PMFixedFreq::exportControl(IControl::Exporter &e) const { auto &pmFixedFreqExporter = dynamic_cast(e); pmFixedFreqExporter.takePMFixedFreqSclkStates(ppDpmSclkHandler_->states()); pmFixedFreqExporter.takePMFixedFreqSclkIndex( ppDpmSclkHandler_->active().front()); pmFixedFreqExporter.takePMFixedFreqMclkStates(ppDpmMclkHandler_->states()); pmFixedFreqExporter.takePMFixedFreqMclkIndex( ppDpmMclkHandler_->active().front()); } void AMD::PMFixedFreq::cleanControl(ICommandQueue &ctlCmds) { ppDpmSclkHandler_->reset(ctlCmds); ppDpmMclkHandler_->reset(ctlCmds); } void AMD::PMFixedFreq::syncControl(ICommandQueue &ctlCmds) { ppDpmSclkHandler_->sync(ctlCmds); ppDpmMclkHandler_->sync(ctlCmds); } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreq.h000066400000000000000000000036711467225065400306740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include #include #include #include #include #include namespace AMD { class IPpDpmHandler; class PMFixedFreq : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_FIXED_FREQ"}; class Importer : public IControl::Importer { public: virtual unsigned int providePMFixedFreqSclkIndex() const = 0; virtual unsigned int providePMFixedFreqMclkIndex() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMFixedFreqSclkIndex(unsigned int index) = 0; virtual void takePMFixedFreqMclkIndex(unsigned int index) = 0; virtual void takePMFixedFreqSclkStates( std::vector> const &states) = 0; virtual void takePMFixedFreqMclkStates( std::vector> const &states) = 0; }; PMFixedFreq(std::unique_ptr &&ppDpmSclkHandler, std::unique_ptr &&ppDpmMclkHandler) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: std::string const id_; std::unique_ptr ppDpmSclkHandler_; std::unique_ptr ppDpmMclkHandler_; std::vector sclkSourceLines_; std::vector mclkSourceLines_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqadvprovider.cpp000066400000000000000000000055661467225065400335020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedfreqadvprovider.h" #include "../pmadvancedprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/components/amdutils.h" #include "core/components/controls/amd/pm/handlers/ppdpmhandler.h" #include "core/info/igpuinfo.h" #include "core/info/iswinfo.h" #include "core/sysfsdatasource.h" #include "pmfixedfreq.h" #include #include #include #include #include #include std::vector> AMD::PMFixedFreqAdvProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver != "amdgpu") return {}; auto ppOdClkVolt = gpuInfo.path().sys / "pp_od_clk_voltage"; auto kernel = Utils::String::parseVersion(swInfo.info(ISWInfo::Keys::kernelVersion)); if (!((kernel >= std::make_tuple(4, 6, 0) && kernel < std::make_tuple(4, 8, 0)) || (kernel >= std::make_tuple(4, 17, 0) && kernel < std::make_tuple(4, 18, 0)) || (kernel >= std::make_tuple(4, 18, 0) && !Utils::File::isSysFSEntryValid(ppOdClkVolt)))) return {}; auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; auto dpmSclk = gpuInfo.path().sys / "pp_dpm_sclk"; auto dpmMclk = gpuInfo.path().sys / "pp_dpm_mclk"; if (!(Utils::File::isSysFSEntryValid(perfLevel) && Utils::File::isSysFSEntryValid(dpmSclk) && Utils::File::isSysFSEntryValid(dpmMclk))) return {}; auto dpmSclkLines = Utils::File::readFileLines(dpmSclk); if (!Utils::AMD::parseDPMStates(dpmSclkLines)) { SPDLOG_WARN("Unknown data format on {}", dpmSclk.string()); for (auto const &line : dpmSclkLines) SPDLOG_DEBUG(line); return {}; } auto dpmMclkLines = Utils::File::readFileLines(dpmMclk); if (!Utils::AMD::parseDPMStates(dpmMclkLines)) { SPDLOG_WARN("Unknown data format on {}", dpmMclk.string()); for (auto const &line : dpmMclkLines) SPDLOG_DEBUG(line); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique( std::make_unique>(perfLevel), std::make_unique>>(dpmSclk)), std::make_unique( std::make_unique>(perfLevel), std::make_unique>>(dpmMclk)))); return controls; } bool const AMD::PMFixedFreqAdvProvider::registered_ = AMD::PMAdvancedProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqadvprovider.h000066400000000000000000000007551467225065400331420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMFixedFreqAdvProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqprofilepart.cpp000066400000000000000000000112271467225065400334730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedfreqprofilepart.h" #include "core/profilepartprovider.h" #include #include #include #include class AMD::PMFixedFreqProfilePart::Initializer final : public PMFixedFreq::Exporter { public: Initializer(AMD::PMFixedFreqProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFixedFreqSclkIndex(unsigned int index) override; void takePMFixedFreqMclkIndex(unsigned int index) override; void takePMFixedFreqSclkStates( std::vector> const &states) override; void takePMFixedFreqMclkStates( std::vector> const &states) override; private: AMD::PMFixedFreqProfilePart &outer_; }; void AMD::PMFixedFreqProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMFixedFreqProfilePart::Initializer::takePMFixedFreqSclkIndex( unsigned int index) { outer_.sclkIndex_ = index; } void AMD::PMFixedFreqProfilePart::Initializer::takePMFixedFreqMclkIndex( unsigned int index) { outer_.mclkIndex_ = index; } void AMD::PMFixedFreqProfilePart::Initializer::takePMFixedFreqSclkStates( std::vector> const &states) { outer_.sclkIndices_.reserve(states.size()); std::transform(states.cbegin(), states.cend(), std::back_inserter(outer_.sclkIndices_), [](auto const &kv) { return kv.first; }); } void AMD::PMFixedFreqProfilePart::Initializer::takePMFixedFreqMclkStates( std::vector> const &states) { outer_.mclkIndices_.reserve(states.size()); std::transform(states.cbegin(), states.cend(), std::back_inserter(outer_.mclkIndices_), [](auto const &kv) { return kv.first; }); } AMD::PMFixedFreqProfilePart::PMFixedFreqProfilePart() noexcept : id_(AMD::PMFixedFreq::ItemID) { } std::unique_ptr AMD::PMFixedFreqProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMFixedFreqProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMFixedFreqProfilePart::ID() const { return id_; } std::optional> AMD::PMFixedFreqProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMFixedFreqProfilePart::provideActive() const { return active(); } unsigned int AMD::PMFixedFreqProfilePart::providePMFixedFreqSclkIndex() const { return sclkIndex_; } unsigned int AMD::PMFixedFreqProfilePart::providePMFixedFreqMclkIndex() const { return mclkIndex_; } void AMD::PMFixedFreqProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmFreqImporter = dynamic_cast(i); sclkIndex(pmFreqImporter.providePMFixedFreqSclkIndex()); mclkIndex(pmFreqImporter.providePMFixedFreqMclkIndex()); } void AMD::PMFixedFreqProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmFreqExporter = dynamic_cast(e); pmFreqExporter.takePMFixedFreqSclkIndex(sclkIndex_); pmFreqExporter.takePMFixedFreqMclkIndex(mclkIndex_); } std::unique_ptr AMD::PMFixedFreqProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->sclkIndices_ = sclkIndices_; clone->mclkIndices_ = mclkIndices_; clone->sclkIndex_ = sclkIndex_; clone->mclkIndex_ = mclkIndex_; return std::move(clone); } void AMD::PMFixedFreqProfilePart::sclkIndex(unsigned int index) { clkIndex(sclkIndex_, index, sclkIndices_); } void AMD::PMFixedFreqProfilePart::mclkIndex(unsigned int index) { clkIndex(mclkIndex_, index, mclkIndices_); } void AMD::PMFixedFreqProfilePart::clkIndex( unsigned int &targetIndex, unsigned int newIndex, std::vector const &availableIndices) const { auto indexIt = std::find(availableIndices.cbegin(), availableIndices.cend(), newIndex); if (indexIt != availableIndices.cend()) targetIndex = newIndex; } bool const AMD::PMFixedFreqProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMFixedFreq::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqprofilepart.h000066400000000000000000000036161467225065400331430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmfixedfreq.h" #include #include namespace AMD { class PMFixedFreqProfilePart final : public ProfilePart , public PMFixedFreq::Importer { public: class Importer : public IProfilePart::Importer { public: virtual unsigned int providePMFixedFreqSclkIndex() const = 0; virtual unsigned int providePMFixedFreqMclkIndex() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMFixedFreqSclkIndex(unsigned int index) = 0; virtual void takePMFixedFreqMclkIndex(unsigned int index) = 0; }; PMFixedFreqProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; unsigned int providePMFixedFreqSclkIndex() const override; unsigned int providePMFixedFreqMclkIndex() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void sclkIndex(unsigned int index); void mclkIndex(unsigned int index); void clkIndex(unsigned int &targetIndex, unsigned int newIndex, std::vector const &availableIndices) const; class Initializer; std::string const id_; unsigned int sclkIndex_; unsigned int mclkIndex_; std::vector sclkIndices_; std::vector mclkIndices_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqprovider.cpp000066400000000000000000000046661467225065400330070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedfreqprovider.h" #include "../freqmode/pmfreqmodeprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/components/controls/amd/pm/handlers/ppdpmhandler.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmfixedfreq.h" #include #include #include #include #include std::vector> AMD::PMFixedFreqProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver != "amdgpu") return {}; auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; auto dpmSclk = gpuInfo.path().sys / "pp_dpm_sclk"; auto dpmMclk = gpuInfo.path().sys / "pp_dpm_mclk"; if (!(Utils::File::isSysFSEntryValid(perfLevel) && Utils::File::isSysFSEntryValid(dpmSclk) && Utils::File::isSysFSEntryValid(dpmMclk))) return {}; auto dpmSclkLines = Utils::File::readFileLines(dpmSclk); if (!Utils::AMD::parseDPMStates(dpmSclkLines)) { SPDLOG_WARN("Unknown data format on {}", dpmSclk.string()); for (auto const &line : dpmSclkLines) SPDLOG_DEBUG(line); return {}; } auto dpmMclkLines = Utils::File::readFileLines(dpmMclk); if (!Utils::AMD::parseDPMStates(dpmMclkLines)) { SPDLOG_WARN("Unknown data format on {}", dpmMclk.string()); for (auto const &line : dpmMclkLines) SPDLOG_DEBUG(line); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique( std::make_unique>(perfLevel), std::make_unique>>(dpmSclk)), std::make_unique( std::make_unique>(perfLevel), std::make_unique>>(dpmMclk)))); return controls; } bool AMD::PMFixedFreqProvider::register_() { AMD::PMFreqModeProvider::registerProvider( std::make_unique()); return true; } bool const AMD::PMFixedFreqProvider::registered_ = AMD::PMFixedFreqProvider::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqprovider.h000066400000000000000000000010051467225065400324340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMFixedFreqProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqqmlitem.cpp000066400000000000000000000135001467225065400326100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedfreqqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmfixedfreq.h" #include #include #include #include #include #include #include char const *const AMD::PMFixedFreqQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_PM_FIXED_FREQ"), }; class AMD::PMFixedFreqQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMFixedFreq::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMFixedFreqQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFixedFreqSclkIndex(unsigned int index) override; void takePMFixedFreqMclkIndex(unsigned int index) override; void takePMFixedFreqSclkStates( std::vector> const &states) override; void takePMFixedFreqMclkStates( std::vector> const &states) override; private: AMD::PMFixedFreqQMLItem &outer_; }; void AMD::PMFixedFreqQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMFixedFreqQMLItem::Initializer::takePMFixedFreqSclkIndex( unsigned int index) { outer_.takePMFixedFreqSclkIndex(index); } void AMD::PMFixedFreqQMLItem::Initializer::takePMFixedFreqMclkIndex( unsigned int index) { outer_.takePMFixedFreqMclkIndex(index); } void AMD::PMFixedFreqQMLItem::Initializer::takePMFixedFreqSclkStates( std::vector> const &states) { outer_.takePMFixedFreqSclkStates(states); } void AMD::PMFixedFreqQMLItem::Initializer::takePMFixedFreqMclkStates( std::vector> const &states) { outer_.takePMFixedFreqMclkStates(states); } AMD::PMFixedFreqQMLItem::PMFixedFreqQMLItem() noexcept { setName(tr(AMD::PMFixedFreq::ItemID.data())); } void AMD::PMFixedFreqQMLItem::changeSclkIndex(unsigned int index) { if (sclkIndex() != index) { sclkIndex(index); emit settingsChanged(); } } void AMD::PMFixedFreqQMLItem::changeMclkIndex(unsigned int index) { if (mclkIndex() != index) { mclkIndex(index); emit settingsChanged(); } } void AMD::PMFixedFreqQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMFixedFreqQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMFixedFreqQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMFixedFreqQMLItem::provideActive() const { return active_; } void AMD::PMFixedFreqQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } unsigned int AMD::PMFixedFreqQMLItem::providePMFixedFreqSclkIndex() const { return sclkIndex(); } unsigned int AMD::PMFixedFreqQMLItem::providePMFixedFreqMclkIndex() const { return mclkIndex(); } void AMD::PMFixedFreqQMLItem::takePMFixedFreqSclkIndex(unsigned int index) { if (sclkIndex() != index) sclkIndex(index); } void AMD::PMFixedFreqQMLItem::takePMFixedFreqMclkIndex(unsigned int index) { if (mclkIndex() != index) mclkIndex(index); } void AMD::PMFixedFreqQMLItem::takePMFixedFreqSclkStates( std::vector> const &states) { QVariantList freqStates; for (auto const &[index, freq] : states) { freqStates.push_back(index); freqStates.push_back(stateLabel(freq.to())); } emit sclkStatesChanged(freqStates); } void AMD::PMFixedFreqQMLItem::takePMFixedFreqMclkStates( std::vector> const &states) { QVariantList freqStates; for (auto const &[index, freq] : states) { freqStates.push_back(index); freqStates.push_back(stateLabel(freq.to())); } emit mclkStatesChanged(freqStates); } QString AMD::PMFixedFreqQMLItem::stateLabel(unsigned int value) { return QString::fromStdString(std::to_string(value)) .append(" ") .append(units::frequency::megahertz_t().abbreviation()); } std::unique_ptr AMD::PMFixedFreqQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } unsigned int AMD::PMFixedFreqQMLItem::sclkIndex() const { return sclkIndex_; } void AMD::PMFixedFreqQMLItem::sclkIndex(unsigned int index) { sclkIndex_ = index; emit sclkIndexChanged(index); } unsigned int AMD::PMFixedFreqQMLItem::mclkIndex() const { return mclkIndex_; } void AMD::PMFixedFreqQMLItem::mclkIndex(unsigned int index) { mclkIndex_ = index; emit mclkIndexChanged(index); } bool AMD::PMFixedFreqQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMFixedFreq::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMFixedFreq::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMFixedFreqForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMFixedFreqQMLItem::registered_ = AMD::PMFixedFreqQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqqmlitem.h000066400000000000000000000043101467225065400322540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmfixedfreqprofilepart.h" #include #include #include #include #include namespace AMD { class PMFixedFreqQMLItem : public QMLItem , public AMD::PMFixedFreqProfilePart::Importer , public AMD::PMFixedFreqProfilePart::Exporter { Q_OBJECT public: explicit PMFixedFreqQMLItem() noexcept; signals: void sclkIndexChanged(unsigned int index); void mclkIndexChanged(unsigned int index); void sclkStatesChanged(QVariantList const &states); void mclkStatesChanged(QVariantList const &states); public slots: void changeSclkIndex(unsigned int index); void changeMclkIndex(unsigned int index); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; unsigned int providePMFixedFreqSclkIndex() const override; unsigned int providePMFixedFreqMclkIndex() const override; void takePMFixedFreqSclkIndex(unsigned int index) override; void takePMFixedFreqMclkIndex(unsigned int index) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void takePMFixedFreqSclkStates( std::vector> const &states); void takePMFixedFreqMclkStates( std::vector> const &states); QString stateLabel(unsigned int value); unsigned int sclkIndex() const; void sclkIndex(unsigned int index); unsigned int mclkIndex() const; void mclkIndex(unsigned int index); bool active_; unsigned int sclkIndex_; unsigned int mclkIndex_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqxmlparser.cpp000066400000000000000000000070011467225065400331540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedfreqxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmfixedfreq.h" #include class AMD::PMFixedFreqXMLParser::Initializer final : public AMD::PMFixedFreqProfilePart::Exporter { public: Initializer(AMD::PMFixedFreqXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFixedFreqSclkIndex(unsigned int index) override; void takePMFixedFreqMclkIndex(unsigned int index) override; private: AMD::PMFixedFreqXMLParser &outer_; }; void AMD::PMFixedFreqXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMFixedFreqXMLParser::Initializer::takePMFixedFreqSclkIndex( unsigned int index) { outer_.sclkIndex_ = outer_.sclkIndexDefault_ = index; } void AMD::PMFixedFreqXMLParser::Initializer::takePMFixedFreqMclkIndex( unsigned int index) { outer_.mclkIndex_ = outer_.mclkIndexDefault_ = index; } AMD::PMFixedFreqXMLParser::PMFixedFreqXMLParser() noexcept : ProfilePartXMLParser(AMD::PMFixedFreq::ItemID, *this, *this) { } std::unique_ptr AMD::PMFixedFreqXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMFixedFreqXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMFixedFreqXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFixedFreqXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMFixedFreqXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMFixedFreqXMLParser::provideActive() const { return active_; } void AMD::PMFixedFreqXMLParser::takePMFixedFreqSclkIndex(unsigned int index) { sclkIndex_ = index; } unsigned int AMD::PMFixedFreqXMLParser::providePMFixedFreqSclkIndex() const { return sclkIndex_; } void AMD::PMFixedFreqXMLParser::takePMFixedFreqMclkIndex(unsigned int index) { mclkIndex_ = index; } unsigned int AMD::PMFixedFreqXMLParser::providePMFixedFreqMclkIndex() const { return mclkIndex_; } void AMD::PMFixedFreqXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFrequencyNode = parentNode.append_child(ID().c_str()); pmFrequencyNode.append_attribute("active") = active_; pmFrequencyNode.append_attribute("sclkState") = sclkIndex_; pmFrequencyNode.append_attribute("mclkState") = mclkIndex_; } void AMD::PMFixedFreqXMLParser::resetAttributes() { active_ = activeDefault_; sclkIndex_ = sclkIndexDefault_; mclkIndex_ = mclkIndexDefault_; } void AMD::PMFixedFreqXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFrequencyNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFrequencyNode.attribute("active").as_bool(activeDefault_); sclkIndex_ = pmFrequencyNode.attribute("sclkState").as_uint(sclkIndexDefault_); mclkIndex_ = pmFrequencyNode.attribute("mclkState").as_uint(mclkIndexDefault_); } bool const AMD::PMFixedFreqXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMFixedFreq::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreqxmlparser.h000066400000000000000000000030611467225065400326230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmfixedfreqprofilepart.h" #include namespace AMD { class PMFixedFreqXMLParser final : public ProfilePartXMLParser , public AMD::PMFixedFreqProfilePart::Exporter , public AMD::PMFixedFreqProfilePart::Importer { public: PMFixedFreqXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMFixedFreqSclkIndex(unsigned int index) override; unsigned int providePMFixedFreqSclkIndex() const override; void takePMFixedFreqMclkIndex(unsigned int index) override; unsigned int providePMFixedFreqMclkIndex() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; unsigned int sclkIndex_; unsigned int sclkIndexDefault_; unsigned int mclkIndex_; unsigned int mclkIndexDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/000077500000000000000000000000001467225065400260275ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmode.h000066400000000000000000000010451467225065400303370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmode.h" #include #include #include #include namespace AMD { class PMFreqMode : public ControlMode { public: static constexpr std::string_view ItemID{"AMD_PM_FREQ_MODE"}; PMFreqMode(std::vector> &&controls) noexcept : ControlMode(AMD::PMFreqMode::ItemID, std::move(controls), true) { } }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeprofilepart.cpp000066400000000000000000000012471467225065400331460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqmodeprofilepart.h" #include "core/profilepartprovider.h" #include "pmfreqmode.h" #include AMD::PMFreqModeProfilePart::PMFreqModeProfilePart() noexcept : ControlModeProfilePart(AMD::PMFreqMode::ItemID) { } std::unique_ptr AMD::PMFreqModeProfilePart::instance() const { return std::make_unique(); } bool const AMD::PMFreqModeProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMFreqMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeprofilepart.h000066400000000000000000000007121467225065400326070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodeprofilepart.h" namespace AMD { class PMFreqModeProfilePart final : public ControlModeProfilePart { public: PMFreqModeProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeprovider.cpp000066400000000000000000000035161467225065400324520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqmodeprovider.h" #include "../overclock/pmoverclockprovider.h" #include "core/info/igpuinfo.h" #include "pmfreqmode.h" #include #include std::vector> AMD::PMFreqModeProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::vector> modeControls; for (auto const &provider : gpuControlProviders()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); modeControls.insert(modeControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (modeControls.empty()) return {}; std::vector> controls; controls.emplace_back(std::make_unique(std::move(modeControls))); return controls; } std::vector> const & AMD::PMFreqModeProvider::gpuControlProviders() const { return providers_(); } bool AMD::PMFreqModeProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::PMFreqModeProvider::providers_() { static std::vector> providers; return providers; } bool AMD::PMFreqModeProvider::register_() { PMOverclockProvider::registerProvider( std::make_unique()); return true; } bool const AMD::PMFreqModeProvider::registered_ = AMD::PMFreqModeProvider::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeprovider.h000066400000000000000000000015631467225065400321170ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class PMFreqModeProvider final : public IGPUControlProvider::IProvider , public IGPUControlProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; std::vector> const & gpuControlProviders() const final override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeqmlitem.cpp000066400000000000000000000020511467225065400322610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqmodeqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmfreqmode.h" #include #include #include #include #include AMD::PMFreqModeQMLItem::PMFreqModeQMLItem() noexcept : ControlModeQMLItem(AMD::PMFreqMode::ItemID) { } bool AMD::PMFreqModeQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMFreqMode::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMFreqMode::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMFreqModeForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMFreqModeQMLItem::registered_ = AMD::PMFreqModeQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodeqmlitem.h000066400000000000000000000006061467225065400317320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodeqmlitem.h" namespace AMD { class PMFreqModeQMLItem : public ControlModeQMLItem { public: explicit PMFreqModeQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodexmlparser.cpp000066400000000000000000000010321467225065400326240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqmodexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmfreqmode.h" #include AMD::PMFreqModeXMLParser::PMFreqModeXMLParser() noexcept : ControlModeXMLParser(AMD::PMFreqMode::ItemID) { } bool const AMD::PMFreqModeXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMFreqMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/freqmode/pmfreqmodexmlparser.h000066400000000000000000000005601467225065400322760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodexmlparser.h" namespace AMD { class PMFreqModeXMLParser final : public ControlModeXMLParser { public: PMFreqModeXMLParser() noexcept; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/000077500000000000000000000000001467225065400262145ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/000077500000000000000000000000001467225065400274745ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqod.cpp000066400000000000000000000062671467225065400320300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqod.h" #include "core/components/amdutils.h" #include "core/icommandqueue.h" #include #include AMD::PMFreqOd::PMFreqOd( std::unique_ptr> &&sclkOdDataSource, std::unique_ptr> &&mclkOdDataSource, std::vector> const &sclkStates, std::vector> const &mclkStates) noexcept : Control(true) , id_(AMD::PMFreqOd::ItemID) , sclkOdDataSource_(std::move(sclkOdDataSource)) , mclkOdDataSource_(std::move(mclkOdDataSource)) , baseSclk_(0) , baseMclk_(0) , sclkOd_(0) , mclkOd_(0) { if (sclkOdDataSource_->read(sclkOdDataSourceEntry_) && mclkOdDataSource_->read(mclkOdDataSourceEntry_)) { baseSclk_ = sclkStates.back().second; if (sclkOdDataSourceEntry_ > 0) { baseSclk_ = units::frequency::megahertz_t(std::round( baseSclk_.to() * (100.0 / (sclkOdDataSourceEntry_ + 100)))); } baseMclk_ = mclkStates.back().second; if (mclkOdDataSourceEntry_ > 0) { baseMclk_ = units::frequency::megahertz_t(std::round( baseMclk_.to() * (100.0 / (mclkOdDataSourceEntry_ + 100)))); } } } void AMD::PMFreqOd::preInit(ICommandQueue &) { } void AMD::PMFreqOd::postInit(ICommandQueue &) { } void AMD::PMFreqOd::init() { } std::string const &AMD::PMFreqOd::ID() const { return id_; } void AMD::PMFreqOd::importControl(IControl::Importer &i) { auto &pmFreqOdImporter = dynamic_cast(i); sclkOd(pmFreqOdImporter.providePMFreqOdSclkOd()); mclkOd(pmFreqOdImporter.providePMFreqOdMclkOd()); } void AMD::PMFreqOd::exportControl(IControl::Exporter &e) const { auto &pmFreqOdExporter = dynamic_cast(e); pmFreqOdExporter.takePMFreqOdBaseSclk(baseSclk()); pmFreqOdExporter.takePMFreqOdBaseMclk(baseMclk()); pmFreqOdExporter.takePMFreqOdSclkOd(sclkOd()); pmFreqOdExporter.takePMFreqOdMclkOd(mclkOd()); } void AMD::PMFreqOd::cleanControl(ICommandQueue &ctlCmds) { ctlCmds.add({sclkOdDataSource_->source(), std::to_string(0)}); ctlCmds.add({mclkOdDataSource_->source(), std::to_string(0)}); } void AMD::PMFreqOd::syncControl(ICommandQueue &ctlCmds) { if (sclkOdDataSource_->read(sclkOdDataSourceEntry_) && mclkOdDataSource_->read(mclkOdDataSourceEntry_)) { if (sclkOdDataSourceEntry_ != sclkOd_) ctlCmds.add({sclkOdDataSource_->source(), std::to_string(sclkOd())}); if (mclkOdDataSourceEntry_ != mclkOd_) ctlCmds.add({mclkOdDataSource_->source(), std::to_string(mclkOd())}); } } unsigned int AMD::PMFreqOd::sclkOd() const { return sclkOd_; } void AMD::PMFreqOd::sclkOd(unsigned int value) { sclkOd_ = std::clamp(value, 0u, 20u); } unsigned int AMD::PMFreqOd::mclkOd() const { return mclkOd_; } void AMD::PMFreqOd::mclkOd(unsigned int value) { mclkOd_ = std::clamp(value, 0u, 20u); } units::frequency::megahertz_t AMD::PMFreqOd::baseSclk() const { return baseSclk_; } units::frequency::megahertz_t AMD::PMFreqOd::baseMclk() const { return baseMclk_; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqod.h000066400000000000000000000046211467225065400314650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include namespace AMD { class PMFreqOd : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_FREQ_OD"}; class Importer : public IControl::Importer { public: virtual unsigned int providePMFreqOdSclkOd() const = 0; virtual unsigned int providePMFreqOdMclkOd() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMFreqOdSclkOd(unsigned int value) = 0; virtual void takePMFreqOdMclkOd(unsigned int value) = 0; virtual void takePMFreqOdBaseSclk(units::frequency::megahertz_t value) = 0; virtual void takePMFreqOdBaseMclk(units::frequency::megahertz_t value) = 0; }; PMFreqOd(std::unique_ptr> &&sclkOdDataSource, std::unique_ptr> &&mclkOdDataSource, std::vector> const &sclkStates, std::vector> const &mclkStates) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; unsigned int sclkOd() const; void sclkOd(unsigned int value); unsigned int mclkOd() const; void mclkOd(unsigned int value); units::frequency::megahertz_t baseSclk() const; units::frequency::megahertz_t baseMclk() const; private: std::string const id_; std::unique_ptr> const sclkOdDataSource_; std::unique_ptr> const mclkOdDataSource_; units::frequency::megahertz_t baseSclk_; units::frequency::megahertz_t baseMclk_; unsigned int sclkOd_; unsigned int mclkOd_; unsigned int sclkOdDataSourceEntry_; unsigned int mclkOdDataSourceEntry_; }; } // namespace AMD pmfreqodprofilepart.cpp000066400000000000000000000062101467225065400342050ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqodprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class AMD::PMFreqOdProfilePart::Initializer final : public PMFreqOd::Exporter { public: Initializer(AMD::PMFreqOdProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqOdBaseSclk(units::frequency::megahertz_t) override { } void takePMFreqOdBaseMclk(units::frequency::megahertz_t) override { } void takePMFreqOdSclkOd(unsigned int value) override; void takePMFreqOdMclkOd(unsigned int value) override; private: AMD::PMFreqOdProfilePart &outer_; }; void AMD::PMFreqOdProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMFreqOdProfilePart::Initializer::takePMFreqOdSclkOd(unsigned int value) { outer_.sclkOd_ = value; } void AMD::PMFreqOdProfilePart::Initializer::takePMFreqOdMclkOd(unsigned int value) { outer_.mclkOd_ = value; } AMD::PMFreqOdProfilePart::PMFreqOdProfilePart() noexcept : id_(AMD::PMFreqOd::ItemID) { } std::unique_ptr AMD::PMFreqOdProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMFreqOdProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMFreqOdProfilePart::ID() const { return id_; } std::optional> AMD::PMFreqOdProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMFreqOdProfilePart::provideActive() const { return active(); } unsigned int AMD::PMFreqOdProfilePart::providePMFreqOdSclkOd() const { return sclkOd_; } unsigned int AMD::PMFreqOdProfilePart::providePMFreqOdMclkOd() const { return mclkOd_; } void AMD::PMFreqOdProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmFreqImporter = dynamic_cast(i); sclkOd(pmFreqImporter.providePMFreqOdSclkOd()); mclkOd(pmFreqImporter.providePMFreqOdMclkOd()); } void AMD::PMFreqOdProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmFreqExporter = dynamic_cast(e); pmFreqExporter.takePMFreqOdSclkOd(sclkOd_); pmFreqExporter.takePMFreqOdMclkOd(mclkOd_); } std::unique_ptr AMD::PMFreqOdProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->sclkOd_ = sclkOd_; clone->mclkOd_ = mclkOd_; return std::move(clone); } void AMD::PMFreqOdProfilePart::sclkOd(unsigned int value) { sclkOd_ = std::clamp(value, 0u, 20u); } void AMD::PMFreqOdProfilePart::mclkOd(unsigned int value) { mclkOd_ = std::clamp(value, 0u, 20u); } bool const AMD::PMFreqOdProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMFreqOd::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodprofilepart.h000066400000000000000000000031371467225065400337360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmfreqod.h" #include namespace AMD { class PMFreqOdProfilePart final : public ProfilePart , public PMFreqOd::Importer { public: class Importer : public IProfilePart::Importer { public: virtual unsigned int providePMFreqOdSclkOd() const = 0; virtual unsigned int providePMFreqOdMclkOd() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMFreqOdSclkOd(unsigned int value) = 0; virtual void takePMFreqOdMclkOd(unsigned int value) = 0; }; PMFreqOdProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; unsigned int providePMFreqOdSclkOd() const override; unsigned int providePMFreqOdMclkOd() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void sclkOd(unsigned int value); void mclkOd(unsigned int value); class Initializer; std::string const id_; unsigned int sclkOd_; unsigned int mclkOd_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodprovider.cpp000066400000000000000000000064321467225065400335750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqodprovider.h" #include "../pmoverclockprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/components/amdutils.h" #include "core/info/igpuinfo.h" #include "core/info/iswinfo.h" #include "core/sysfsdatasource.h" #include "pmfreqod.h" #include #include #include #include #include #include std::vector> AMD::PMFreqOdProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto kernel = Utils::String::parseVersion(swInfo.info(ISWInfo::Keys::kernelVersion)); auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (!(driver == "amdgpu" && (kernel >= std::make_tuple(4, 8, 0) && kernel < std::make_tuple(4, 17, 0)))) return {}; auto sclkOd = gpuInfo.path().sys / "pp_sclk_od"; auto mclkOd = gpuInfo.path().sys / "pp_mclk_od"; auto dpmSclk = gpuInfo.path().sys / "pp_dpm_sclk"; auto dpmMclk = gpuInfo.path().sys / "pp_dpm_mclk"; if (!(Utils::File::isSysFSEntryValid(sclkOd) && Utils::File::isSysFSEntryValid(mclkOd) && Utils::File::isSysFSEntryValid(dpmSclk) && Utils::File::isSysFSEntryValid(dpmMclk))) return {}; unsigned int odValue; auto sclkOdLines = Utils::File::readFileLines(sclkOd); if (!Utils::String::toNumber(odValue, sclkOdLines.front())) { SPDLOG_WARN("Unknown data format on {}", sclkOd.string()); SPDLOG_DEBUG(sclkOdLines.front()); return {}; } auto mclkOdLines = Utils::File::readFileLines(mclkOd); if (!Utils::String::toNumber(odValue, mclkOdLines.front())) { SPDLOG_WARN("Unknown data format on {}", mclkOd.string()); SPDLOG_DEBUG(mclkOdLines.front()); return {}; } auto dpmSclkLines = Utils::File::readFileLines(dpmSclk); auto sclkStates = Utils::AMD::parseDPMStates(dpmSclkLines); if (!sclkStates) { SPDLOG_WARN("Unknown data format on {}", dpmSclk.string()); for (auto const &line : dpmSclkLines) SPDLOG_DEBUG(line); return {}; } auto dpmMclkLines = Utils::File::readFileLines(dpmMclk); auto mclkStates = Utils::AMD::parseDPMStates(dpmMclkLines); if (!mclkStates) { SPDLOG_WARN("Unknown data format on {}", dpmMclk.string()); for (auto const &line : dpmMclkLines) SPDLOG_DEBUG(line); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>( sclkOd, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }), std::make_unique>( mclkOd, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); }), sclkStates.value(), mclkStates.value())); return controls; } bool const AMD::PMFreqOdProvider::registered_ = AMD::PMOverclockProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodprovider.h000066400000000000000000000007471467225065400332450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMFreqOdProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodqmlitem.cpp000066400000000000000000000134671467225065400334210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqodqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmfreqod.h" #include #include #include #include #include #include class AMD::PMFreqOdQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMFreqOd::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMFreqOdQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqOdBaseSclk(units::frequency::megahertz_t value) override; void takePMFreqOdBaseMclk(units::frequency::megahertz_t value) override; void takePMFreqOdSclkOd(unsigned int value) override; void takePMFreqOdMclkOd(unsigned int value) override; private: AMD::PMFreqOdQMLItem &outer_; }; void AMD::PMFreqOdQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMFreqOdQMLItem::Initializer::takePMFreqOdBaseSclk( units::frequency::megahertz_t value) { outer_.takePMFreqOdBaseSclk(value); } void AMD::PMFreqOdQMLItem::Initializer::takePMFreqOdBaseMclk( units::frequency::megahertz_t value) { outer_.takePMFreqOdBaseMclk(value); } void AMD::PMFreqOdQMLItem::Initializer::takePMFreqOdSclkOd(unsigned int value) { outer_.takePMFreqOdSclkOd(value); } void AMD::PMFreqOdQMLItem::Initializer::takePMFreqOdMclkOd(unsigned int value) { outer_.takePMFreqOdMclkOd(value); } AMD::PMFreqOdQMLItem::PMFreqOdQMLItem() noexcept { setName(tr(AMD::PMFreqOd::ItemID.data())); } void AMD::PMFreqOdQMLItem::changeSclkOd(unsigned int value) { if (sclkOd() != value) { sclkOd(value); emit settingsChanged(); } } void AMD::PMFreqOdQMLItem::changeMclkOd(unsigned int value) { if (mclkOd() != value) { mclkOd(value); emit settingsChanged(); } } void AMD::PMFreqOdQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMFreqOdQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMFreqOdQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMFreqOdQMLItem::provideActive() const { return active_; } void AMD::PMFreqOdQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } unsigned int AMD::PMFreqOdQMLItem::providePMFreqOdSclkOd() const { return sclkOd(); } unsigned int AMD::PMFreqOdQMLItem::providePMFreqOdMclkOd() const { return mclkOd(); } void AMD::PMFreqOdQMLItem::takePMFreqOdSclkOd(unsigned int value) { if (sclkOd() != value) sclkOd(value); } void AMD::PMFreqOdQMLItem::takePMFreqOdMclkOd(unsigned int value) { if (mclkOd() != value) mclkOd(value); } void AMD::PMFreqOdQMLItem::takePMFreqOdBaseSclk(units::frequency::megahertz_t value) { baseSclk_ = value.to(); auto scaledValue = sclkOd() > 0 ? static_cast(std::round( baseSclk_ * (sclkOd() / 100.0f))) : baseSclk_; emit sclkChanged(stateLabel(scaledValue)); } void AMD::PMFreqOdQMLItem::takePMFreqOdBaseMclk(units::frequency::megahertz_t value) { baseMclk_ = value.to(); auto scaledValue = mclkOd() > 0 ? static_cast(std::round( baseMclk_ * (mclkOd() / 100.0f))) : baseMclk_; emit mclkChanged(stateLabel(scaledValue)); } std::unique_ptr AMD::PMFreqOdQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } QString AMD::PMFreqOdQMLItem::stateLabel(unsigned int value) { return QString::fromStdString(std::to_string(value)) .append(" ") .append(units::frequency::megahertz_t().abbreviation()); } unsigned int AMD::PMFreqOdQMLItem::sclkOd() const { return sclkOd_; } void AMD::PMFreqOdQMLItem::sclkOd(unsigned int value) { sclkOd_ = value; emit sclkOdChanged(sclkOd_); if (baseSclk_ > 0) { auto scaledValue = sclkOd_ > 0 ? static_cast(std::floor( baseSclk_ * (1.0f + (sclkOd_ / 100.0f)))) : baseSclk_; emit sclkChanged(stateLabel(scaledValue)); } } unsigned int AMD::PMFreqOdQMLItem::mclkOd() const { return mclkOd_; } void AMD::PMFreqOdQMLItem::mclkOd(unsigned int value) { mclkOd_ = value; emit mclkOdChanged(mclkOd_); if (baseMclk_ > 0) { auto scaledValue = mclkOd_ > 0 ? static_cast(std::floor( baseMclk_ * (1.0f + (mclkOd_ / 100.0f)))) : baseMclk_; emit mclkChanged(stateLabel(scaledValue)); } } bool AMD::PMFreqOdQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMFreqOd::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMFreqOd::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDPMFreqOdForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMFreqOdQMLItem::registered_ = AMD::PMFreqOdQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodqmlitem.h000066400000000000000000000036751467225065400330660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmfreqodprofilepart.h" #include #include namespace AMD { class PMFreqOdQMLItem : public QMLItem , public AMD::PMFreqOdProfilePart::Importer , public AMD::PMFreqOdProfilePart::Exporter { Q_OBJECT public: explicit PMFreqOdQMLItem() noexcept; signals: void sclkOdChanged(unsigned int value); void mclkOdChanged(unsigned int value); void sclkChanged(QString const &value); void mclkChanged(QString const &value); public slots: void changeSclkOd(unsigned int value); void changeMclkOd(unsigned int value); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; unsigned int providePMFreqOdSclkOd() const override; unsigned int providePMFreqOdMclkOd() const override; void takePMFreqOdSclkOd(unsigned int value) override; void takePMFreqOdMclkOd(unsigned int value) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void takePMFreqOdBaseSclk(units::frequency::megahertz_t value); void takePMFreqOdBaseMclk(units::frequency::megahertz_t value); QString stateLabel(unsigned int value); unsigned int sclkOd() const; void sclkOd(unsigned int value); unsigned int mclkOd() const; void mclkOd(unsigned int value); bool active_; unsigned int sclkOd_{0}; unsigned int mclkOd_{0}; unsigned int baseSclk_{0}; unsigned int baseMclk_{0}; static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodxmlparser.cpp000066400000000000000000000064471467225065400337660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfreqodxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmfreqod.h" #include class AMD::PMFreqOdXMLParser::Initializer final : public AMD::PMFreqOdProfilePart::Exporter { public: Initializer(AMD::PMFreqOdXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqOdSclkOd(unsigned int value) override; void takePMFreqOdMclkOd(unsigned int value) override; private: AMD::PMFreqOdXMLParser &outer_; }; void AMD::PMFreqOdXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMFreqOdXMLParser::Initializer::takePMFreqOdSclkOd(unsigned int value) { outer_.sclkOd_ = outer_.sclkOdDefault_ = value; } void AMD::PMFreqOdXMLParser::Initializer::takePMFreqOdMclkOd(unsigned int value) { outer_.mclkOd_ = outer_.mclkOdDefault_ = value; } AMD::PMFreqOdXMLParser::PMFreqOdXMLParser() noexcept : ProfilePartXMLParser(AMD::PMFreqOd::ItemID, *this, *this) { } std::unique_ptr AMD::PMFreqOdXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMFreqOdXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMFreqOdXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFreqOdXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMFreqOdXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMFreqOdXMLParser::provideActive() const { return active_; } unsigned int AMD::PMFreqOdXMLParser::providePMFreqOdSclkOd() const { return sclkOd_; } void AMD::PMFreqOdXMLParser::takePMFreqOdSclkOd(unsigned int value) { sclkOd_ = value; } unsigned int AMD::PMFreqOdXMLParser::providePMFreqOdMclkOd() const { return mclkOd_; } void AMD::PMFreqOdXMLParser::takePMFreqOdMclkOd(unsigned int value) { mclkOd_ = value; } void AMD::PMFreqOdXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFrequencyNode = parentNode.append_child(ID().c_str()); pmFrequencyNode.append_attribute("active") = active_; pmFrequencyNode.append_attribute("sclkOd") = sclkOd_; pmFrequencyNode.append_attribute("mclkOd") = mclkOd_; } void AMD::PMFreqOdXMLParser::resetAttributes() { active_ = activeDefault_; sclkOd_ = sclkOdDefault_; mclkOd_ = mclkOdDefault_; } void AMD::PMFreqOdXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFrequencyNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFrequencyNode.attribute("active").as_bool(activeDefault_); sclkOd_ = pmFrequencyNode.attribute("sclkOd").as_uint(sclkOdDefault_); mclkOd_ = pmFrequencyNode.attribute("mclkOd").as_uint(mclkOdDefault_); } bool const AMD::PMFreqOdXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMFreqOd::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqodxmlparser.h000066400000000000000000000027761467225065400334340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmfreqodprofilepart.h" #include namespace AMD { class PMFreqOdXMLParser final : public ProfilePartXMLParser , public AMD::PMFreqOdProfilePart::Exporter , public AMD::PMFreqOdProfilePart::Importer { public: PMFreqOdXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMFreqOdSclkOd(unsigned int value) override; unsigned int providePMFreqOdSclkOd() const override; void takePMFreqOdMclkOd(unsigned int value) override; unsigned int providePMFreqOdMclkOd() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; unsigned int sclkOd_; unsigned int sclkOdDefault_; unsigned int mclkOd_; unsigned int mclkOdDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclock.h000066400000000000000000000010531467225065400307100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroup.h" #include #include #include #include namespace AMD { class PMOverclock : public ControlGroup { public: static constexpr std::string_view ItemID{"AMD_PM_OVERCLOCK"}; PMOverclock(std::vector> &&controls) noexcept : ControlGroup(AMD::PMOverclock::ItemID, std::move(controls), true) { } }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockprofilepart.cpp000066400000000000000000000012631467225065400335160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmoverclockprofilepart.h" #include "core/profilepartprovider.h" #include "pmoverclock.h" #include AMD::PMOverclockProfilePart::PMOverclockProfilePart() noexcept : ControlGroupProfilePart(AMD::PMOverclock::ItemID) { } std::unique_ptr AMD::PMOverclockProfilePart::instance() const { return std::make_unique(); } bool const AMD::PMOverclockProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMOverclock::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockprofilepart.h000066400000000000000000000007171467225065400331660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroupprofilepart.h" namespace AMD { class PMOverclockProfilePart final : public ControlGroupProfilePart { public: PMOverclockProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockprovider.cpp000066400000000000000000000037571467225065400330330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmoverclockprovider.h" #include "../pmadvancedprovider.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/iswinfo.h" #include "pmoverclock.h" #include #include #include #include #include std::vector> AMD::PMOverclockProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto kernel = Utils::String::parseVersion(swInfo.info(ISWInfo::Keys::kernelVersion)); auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (!(driver == "amdgpu" && (kernel >= std::make_tuple(4, 8, 0) && kernel < std::make_tuple(4, 17, 0)))) return {}; std::vector> modeControls; for (auto const &provider : providers_()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); modeControls.insert(modeControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (modeControls.empty()) return {}; std::vector> controls; controls.emplace_back(std::make_unique(std::move(modeControls))); return controls; } bool AMD::PMOverclockProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::PMOverclockProvider::providers_() { static std::vector> providers; return providers; } bool const AMD::PMOverclockProvider::registered_ = AMD::PMAdvancedProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockprovider.h000066400000000000000000000013061467225065400324640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class PMOverclockProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockqmlitem.cpp000066400000000000000000000020671467225065400326420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmoverclockqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmoverclock.h" #include #include #include #include #include AMD::PMOverclockQMLItem::PMOverclockQMLItem() noexcept : ControlGroupQMLItem(AMD::PMOverclock::ItemID) { } bool AMD::PMOverclockQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMOverclock::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMOverclock::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMOverclockForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMOverclockQMLItem::registered_ = AMD::PMOverclockQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockqmlitem.h000066400000000000000000000006121467225065400323010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroupqmlitem.h" namespace AMD { class PMOverclockQMLItem : public ControlGroupQMLItem { public: explicit PMOverclockQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockxmlparser.cpp000066400000000000000000000010521467225065400332000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmoverclockxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmoverclock.h" #include AMD::PMOverclockXMLParser::PMOverclockXMLParser() noexcept : ControlGroupXMLParser(AMD::PMOverclock::ItemID) { } bool const AMD::PMOverclockXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMOverclock::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overclock/pmoverclockxmlparser.h000066400000000000000000000005641467225065400326540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroupxmlparser.h" namespace AMD { class PMOverclockXMLParser final : public ControlGroupXMLParser { public: PMOverclockXMLParser() noexcept; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/000077500000000000000000000000001467225065400262325ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange/000077500000000000000000000000001467225065400302045ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrange.cpp000066400000000000000000000110011467225065400332100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqrange.h" #include "core/components/amdutils.h" #include "core/icommandqueue.h" #include #include #include AMD::PMFreqRange::PMFreqRange( std::string &&controlName, std::string &&controlCmdId, std::unique_ptr>> &&ppOdClkVoltDataSource, std::optional &&disabledBound) noexcept : Control(true) , id_(AMD::PMFreqRange::ItemID) , controlName_(std::move(controlName)) , controlCmdId_(std::move(controlCmdId)) , disabledBound_(std::move(disabledBound)) , ppOdClkVoltDataSource_(std::move(ppOdClkVoltDataSource)) { } void AMD::PMFreqRange::preInit(ICommandQueue &) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { preInitStates_ = Utils::AMD::parseOverdriveClks(controlName(), ppOdClkVoltLines_).value(); } } void AMD::PMFreqRange::postInit(ICommandQueue &ctlCmds) { for (auto [index, freq] : preInitStates_) { // skip disabled bound if (disabledBound_.has_value() && index == disabledBound_->index) continue; ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(index, freq)}); } } void AMD::PMFreqRange::init() { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { stateRange_ = Utils::AMD::parseOverdriveClkRange(controlName(), ppOdClkVoltLines_) .value(); auto states = Utils::AMD::parseOverdriveClks(controlName(), ppOdClkVoltLines_); auto [min, max] = stateRange_; for (auto [index, freq] : states.value()) { // skip disabled bound if (disabledBound_.has_value() && index == disabledBound_->index) continue; states_.emplace(index, (std::clamp(freq, min, max))); } } } std::string const &AMD::PMFreqRange::ID() const { return id_; } std::string const &AMD::PMFreqRange::instanceID() const { return controlName(); } void AMD::PMFreqRange::importControl(IControl::Importer &i) { auto &importer = dynamic_cast(i); for (auto [index, _] : states_) state(index, importer.providePMFreqRangeState(index)); } void AMD::PMFreqRange::exportControl(IControl::Exporter &e) const { auto &exporter = dynamic_cast(e); auto [mim, max] = stateRange(); exporter.takePMFreqRangeControlName(controlName()); exporter.takePMFreqRangeStateRange(mim, max); exporter.takePMFreqRangeStates(states()); } void AMD::PMFreqRange::cleanControl(ICommandQueue &) { } void AMD::PMFreqRange::syncControl(ICommandQueue &ctlCmds) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { auto states = Utils::AMD::parseOverdriveClks(controlName(), ppOdClkVoltLines_); for (auto [index, freq] : states.value()) { // skip disabled bound if (disabledBound_.has_value() && index == disabledBound_->index) continue; auto targetFreq = states_.at(index); if (freq != targetFreq) { ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(index, targetFreq)}); } } } } std::string const &AMD::PMFreqRange::controlName() const { return controlName_; } std::string const &AMD::PMFreqRange::controlCmdId() const { return controlCmdId_; } std::pair const & AMD::PMFreqRange::stateRange() const { return stateRange_; } std::vector> AMD::PMFreqRange::states() const { std::vector> states; states.reserve(states_.size()); std::transform( states_.cbegin(), states_.cend(), std::back_inserter(states), [](auto const &kv) { return std::make_pair(kv.first, kv.second); }); return states; } void AMD::PMFreqRange::state(unsigned int index, units::frequency::megahertz_t freq) { auto [min, max] = stateRange(); auto &sFreq = states_.at(index); sFreq = std::clamp(freq, min, max); } std::string AMD::PMFreqRange::ppOdClkVoltCmd(unsigned int index, units::frequency::megahertz_t freq) const { std::string cmd; cmd.reserve(16); cmd.append(controlCmdId()) .append(" ") .append(std::to_string(index)) .append(" ") .append(std::to_string(freq.to())); return cmd; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrange.h000066400000000000000000000064341467225065400326730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include #include #include namespace AMD { /// Overdrive frequency range control. /// /// A frequency overdrive control has an identifier and up to two /// states for the minimum (optional) and maximum operation frequency /// values. class PMFreqRange : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_FREQ_RANGE"}; /// Disabled range bound. /// /// When PMFreqRange is created with a disabled range bound, it won't generate /// any control commands for the hardware state index defined by the /// DisabledBound. struct DisabledBound { /// Hardware state index of the disabled bound. unsigned int index; }; class Importer : public IControl::Importer { public: virtual units::frequency::megahertz_t providePMFreqRangeState(unsigned int index) const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMFreqRangeControlName(std::string const &name) = 0; virtual void takePMFreqRangeStateRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) = 0; virtual void takePMFreqRangeStates( std::vector> const &states) = 0; }; PMFreqRange( std::string &&controlName, std::string &&controlCmdId, std::unique_ptr>> &&ppOdClkVoltDataSource, std::optional &&disabledBound = std::nullopt) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; std::string const &instanceID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) override; void syncControl(ICommandQueue &ctlCmds) override; std::string const &controlName() const; std::string const &controlCmdId() const; std::pair const & stateRange() const; std::vector> states() const; void state(unsigned int index, units::frequency::megahertz_t freq); std::string ppOdClkVoltCmd(unsigned int index, units::frequency::megahertz_t freq) const; private: std::string const id_; std::string const controlName_; std::string const controlCmdId_; std::optional const disabledBound_; std::unique_ptr>> const ppOdClkVoltDataSource_; std::vector ppOdClkVoltLines_; std::vector> preInitStates_; std::map states_; std::pair stateRange_; }; } // namespace AMD pmfreqrangeprofilepart.cpp000066400000000000000000000101331467225065400354060ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqrangeprofilepart.h" #include "core/profilepartprovider.h" #include #include #include #include class AMD::PMFreqRangeProfilePart::Initializer final : public AMD::PMFreqRange::Exporter { public: Initializer(AMD::PMFreqRangeProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqRangeControlName(std::string const &name) override; void takePMFreqRangeStateRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) override; void takePMFreqRangeStates( std::vector> const &states) override; private: AMD::PMFreqRangeProfilePart &outer_; }; void AMD::PMFreqRangeProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMFreqRangeProfilePart::Initializer::takePMFreqRangeControlName( std::string const &name) { outer_.controlName_ = name; } void AMD::PMFreqRangeProfilePart::Initializer::takePMFreqRangeStateRange( units::frequency::megahertz_t min, units::frequency::megahertz_t max) { outer_.stateRange_ = std::make_pair(min, max); } void AMD::PMFreqRangeProfilePart::Initializer::takePMFreqRangeStates( std::vector> const &states) { outer_.states_ = states; } AMD::PMFreqRangeProfilePart::PMFreqRangeProfilePart() noexcept : id_(AMD::PMFreqRange::ItemID) { } std::string const &AMD::PMFreqRangeProfilePart::ID() const { return id_; } std::string const &AMD::PMFreqRangeProfilePart::instanceID() const { return controlName_; } std::unique_ptr AMD::PMFreqRangeProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMFreqRangeProfilePart::initializer() { return std::make_unique(*this); } std::optional> AMD::PMFreqRangeProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMFreqRangeProfilePart::provideActive() const { return active(); } units::frequency::megahertz_t AMD::PMFreqRangeProfilePart::providePMFreqRangeState(unsigned int index) const { auto stateIt = std::find_if( states_.cbegin(), states_.cend(), [=](auto const &state) { return state.first == index; }); if (stateIt != states_.cend()) return stateIt->second; else return units::frequency::megahertz_t(0); } void AMD::PMFreqRangeProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &importer = dynamic_cast(i); for (auto [index, _] : states_) setState(index, importer.providePMFreqRangeState(index)); } void AMD::PMFreqRangeProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &exporter = dynamic_cast(e); exporter.takePMFreqRangeControlName(controlName_); exporter.takePMFreqRangeStates(states_); } std::unique_ptr AMD::PMFreqRangeProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->controlName_ = controlName_; clone->stateRange_ = stateRange_; clone->states_ = states_; return std::move(clone); } void AMD::PMFreqRangeProfilePart::setState(unsigned int index, units::frequency::megahertz_t freq) { auto stateIt = std::find_if( states_.begin(), states_.end(), [=](auto const &state) { return state.first == index; }); if (stateIt != states_.end()) stateIt->second = std::clamp(freq, stateRange_.first, stateRange_.second); } bool const AMD::PMFreqRangeProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMFreqRange::ItemID, []() { return std::make_unique(); }); pmfreqrangeprofilepart.h000066400000000000000000000036271467225065400350650ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmfreqrange.h" #include #include #include namespace AMD { class PMFreqRangeProfilePart final : public ProfilePart , public PMFreqRange::Importer { public: class Importer : public IProfilePart::Importer { public: virtual units::frequency::megahertz_t providePMFreqRangeState(unsigned int index) const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMFreqRangeControlName(std::string const &mode) = 0; virtual void takePMFreqRangeStates( std::vector> const &states) = 0; }; PMFreqRangeProfilePart() noexcept; std::string const &ID() const override; std::string const &instanceID() const override; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; units::frequency::megahertz_t providePMFreqRangeState(unsigned int index) const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void setState(unsigned int index, units::frequency::megahertz_t freq); class Initializer; std::string const id_; std::string controlName_; std::vector> states_; std::pair stateRange_; static bool const registered_; }; } // namespace AMD pmfreqrangeprovider.cpp000066400000000000000000000057731467225065400347270ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqrangeprovider.h" #include "../pmoverdriveprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/amd/gpuinfopmoverdrive.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmfreqrange.h" #include #include std::optional> AMD::PMFreqRangeProvider::createControl( std::string controlName, std::filesystem::path const &ppOdClkVoltPath, std::vector const &ppOdClkVoltLines) const { auto outOfRangeStates = Utils::AMD::ppOdClkVoltageFreqRangeOutOfRangeStates( controlName, ppOdClkVoltLines); if (outOfRangeStates.has_value()) { for (auto stateIndex : outOfRangeStates.value()) { SPDLOG_WARN("Detected out of range state index {} on control {}", stateIndex, controlName); } } auto valid = !(outOfRangeStates.has_value() && outOfRangeStates->size() > 1) && Utils::AMD::parseOverdriveClkRange(controlName, ppOdClkVoltLines).has_value() && Utils::AMD::parseOverdriveClks(controlName, ppOdClkVoltLines).has_value(); if (!valid) { SPDLOG_WARN("Invalid data on {} for control {}", ppOdClkVoltPath.string(), controlName); for (auto const &line : ppOdClkVoltLines) SPDLOG_DEBUG(line); return {}; } auto controlCmdId = Utils::AMD::getOverdriveClkControlCmdId(controlName); if (!controlCmdId) { SPDLOG_WARN("Unsupported control {}", controlName); return {}; } auto disabledBound = outOfRangeStates.has_value() ? std::optional( AMD::PMFreqRange::DisabledBound{outOfRangeStates->at(0)}) : std::nullopt; return std::make_unique( std::move(controlName), std::move(*controlCmdId), std::make_unique>>(ppOdClkVoltPath), std::move(disabledBound)); } std::vector> AMD::PMFreqRangeProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && gpuInfo.hasCapability(GPUInfoPMOverdrive::Clk))) return {}; auto ppOdClkVoltPath = gpuInfo.path().sys / "pp_od_clk_voltage"; auto ppOdClkVoltLines = Utils::File::readFileLines(ppOdClkVoltPath); auto const controlNames = Utils::AMD::parseOverdriveClkControls(ppOdClkVoltLines); if (!controlNames) return {}; std::vector> controls; for (auto controlName : controlNames.value()) { auto control = createControl(controlName, ppOdClkVoltPath, ppOdClkVoltLines); if (control) controls.emplace_back(std::move(*control)); } return controls; } bool const AMD::PMFreqRangeProvider::registered_ = AMD::PMOverdriveProvider::registerProvider( std::make_unique()); pmfreqrangeprovider.h000066400000000000000000000014461467225065400343650ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include #include #include #include namespace AMD { class PMFreqRangeProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: std::optional> createControl(std::string controlName, std::filesystem::path const &ppOdClkVoltPath, std::vector const &ppOdClkVoltLines) const; static bool const registered_; }; } // namespace AMD pmfreqrangeqmlitem.cpp000066400000000000000000000124411467225065400345330ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqrangeqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmfreqrange.h" #include #include #include #include #include #include #include #include #include #include char const *const AMD::PMFreqRangeQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("AMD::PMFreqRangeQMLItem", "SCLK"), QT_TRANSLATE_NOOP("AMD::PMFreqRangeQMLItem", "MCLK"), }; class AMD::PMFreqRangeQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMFreqRange::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMFreqRangeQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqRangeControlName(std::string const &name) override; void takePMFreqRangeStateRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) override; void takePMFreqRangeStates( std::vector> const &states) override; private: AMD::PMFreqRangeQMLItem &outer_; }; void AMD::PMFreqRangeQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMFreqRangeQMLItem::Initializer::takePMFreqRangeControlName( std::string const &name) { outer_.takePMFreqRangeControlName(name); } void AMD::PMFreqRangeQMLItem::Initializer::takePMFreqRangeStateRange( units::frequency::megahertz_t min, units::frequency::megahertz_t max) { outer_.stateRange(min, max); } void AMD::PMFreqRangeQMLItem::Initializer::takePMFreqRangeStates( std::vector> const &states) { outer_.takePMFreqRangeStates(states); } AMD::PMFreqRangeQMLItem::PMFreqRangeQMLItem() noexcept { setName(tr(AMD::PMFreqRange::ItemID.data())); } void AMD::PMFreqRangeQMLItem::changeState(int index, int freq) { if (states_.count(static_cast(index)) > 0) { auto &stateFreq = states_.at(static_cast(index)); if (stateFreq.to() != freq) { stateFreq = units::frequency::megahertz_t(freq); emit stateChanged(index, freq); emit settingsChanged(); } } } QString const &AMD::PMFreqRangeQMLItem::instanceID() const { return instanceID_; } void AMD::PMFreqRangeQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMFreqRangeQMLItem::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFreqRangeQMLItem::provideImporter(Item const &) { return {}; } void AMD::PMFreqRangeQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::PMFreqRangeQMLItem::takePMFreqRangeControlName(std::string const &name) { controlName(name); } void AMD::PMFreqRangeQMLItem::takePMFreqRangeStates( std::vector> const &states) { QVariantList statesList; std::map newStates; for (auto const &[index, freq] : states) { newStates.emplace(index, freq); statesList.push_back(index); statesList.push_back(freq.to()); } if (newStates != states_) { std::swap(states_, newStates); emit statesChanged(statesList); } } bool AMD::PMFreqRangeQMLItem::provideActive() const { return active_; } units::frequency::megahertz_t AMD::PMFreqRangeQMLItem::providePMFreqRangeState(unsigned int index) const { if (states_.count(index) > 0) return states_.at(index); else return units::frequency::megahertz_t(0); } std::unique_ptr AMD::PMFreqRangeQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::PMFreqRangeQMLItem::controlName(std::string const &name) { instanceID_ = QString::fromStdString(name); emit controlLabelChanged(tr(name.c_str())); } void AMD::PMFreqRangeQMLItem::stateRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) { emit stateRangeChanged(min.to(), max.to()); } bool AMD::PMFreqRangeQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMFreqRange::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMFreqRange::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMFreqRangeForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMFreqRangeQMLItem::registered_ = AMD::PMFreqRangeQMLItem::register_(); pmfreqrangeqmlitem.h000066400000000000000000000040311467225065400341740ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmfreqrangeprofilepart.h" #include #include #include #include #include #include namespace AMD { class PMFreqRangeQMLItem : public QMLItem , public AMD::PMFreqRangeProfilePart::Importer , public AMD::PMFreqRangeProfilePart::Exporter { Q_OBJECT Q_PROPERTY(QString instanceID READ instanceID) public: explicit PMFreqRangeQMLItem() noexcept; signals: void controlLabelChanged(QString const &label); void stateRangeChanged(int min, int max); void statesChanged(QVariantList const &states); void stateChanged(int index, int freq); public slots: void changeState(int index, int freq); public: QString const &instanceID() const; void activate(bool active) override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; void takePMFreqRangeControlName(std::string const &mode) override; void takePMFreqRangeStates( std::vector> const &states) override; bool provideActive() const override; units::frequency::megahertz_t providePMFreqRangeState(unsigned int index) const override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void controlName(std::string const &name); void stateRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max); QString instanceID_; bool active_; std::map states_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD pmfreqrangexmlparser.cpp000066400000000000000000000142401467225065400350770ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqrangexmlparser.h" #include "../pmoverdrive.h" #include "core/profilepartxmlparserprovider.h" #include "pmfreqrange.h" #include #include #include class AMD::PMFreqRangeXMLParser::Initializer final : public AMD::PMFreqRangeProfilePart::Exporter { public: Initializer(AMD::PMFreqRangeXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqRangeControlName(std::string const &name) override; void takePMFreqRangeStates( std::vector> const &states) override; private: AMD::PMFreqRangeXMLParser &outer_; }; void AMD::PMFreqRangeXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMFreqRangeXMLParser::Initializer::takePMFreqRangeControlName( std::string const &name) { outer_.controlName_ = name; outer_.nodeID_ = name; std::transform(outer_.nodeID_.cbegin(), outer_.nodeID_.cend(), outer_.nodeID_.begin(), ::tolower); } void AMD::PMFreqRangeXMLParser::Initializer::takePMFreqRangeStates( std::vector> const &states) { outer_.states_ = outer_.statesDefault_ = states; } AMD::PMFreqRangeXMLParser::PMFreqRangeXMLParser() noexcept : ProfilePartXMLParser(AMD::PMFreqRange::ItemID, *this, *this) { } std::string const &AMD::PMFreqRangeXMLParser::instanceID() const { return controlName_; } std::unique_ptr AMD::PMFreqRangeXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMFreqRangeXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMFreqRangeXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFreqRangeXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMFreqRangeXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMFreqRangeXMLParser::provideActive() const { return active_; } void AMD::PMFreqRangeXMLParser::takePMFreqRangeControlName(std::string const &) { } void AMD::PMFreqRangeXMLParser::takePMFreqRangeStates( std::vector> const &states) { states_ = states; } units::frequency::megahertz_t AMD::PMFreqRangeXMLParser::providePMFreqRangeState(unsigned int index) const { auto stateIt = std::find_if( states_.cbegin(), states_.cend(), [=](auto const &state) { return state.first == index; }); if (stateIt != states_.cend()) return stateIt->second; else return units::frequency::megahertz_t(0); } void AMD::PMFreqRangeXMLParser::appendTo(pugi::xml_node &parentNode) { auto node = parentNode.append_child(ID().c_str()); node.append_attribute("active") = active_; node.append_attribute("id") = nodeID_.c_str(); saveStates(node); } void AMD::PMFreqRangeXMLParser::resetAttributes() { active_ = activeDefault_; states_ = statesDefault_; } void AMD::PMFreqRangeXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto legacyNode = parentNode.find_child([&](pugi::xml_node const &node) { return node.name() == AMD::PMOverdrive::LegacyFVVoltCurveItemID; }); if (!legacyNode) { auto node = parentNode.find_child([&](pugi::xml_node const &node) { if (node.name() != ID()) return false; return node.attribute("id").as_string() == nodeID_; }); active_ = node.attribute("active").as_bool(activeDefault_); loadStates(node); } else { active_ = legacyNode.attribute("active").as_bool(activeDefault_); loadStatesFromLegacyNode(legacyNode); } } void AMD::PMFreqRangeXMLParser::saveStates(pugi::xml_node &node) const { for (auto [index, freq] : states_) { auto stateNode = node.append_child(StateNodeName.data()); stateNode.append_attribute("index") = index; stateNode.append_attribute("freq") = freq.to(); } } void AMD::PMFreqRangeXMLParser::loadStates(pugi::xml_node const &node) { if (!node) { states_ = statesDefault_; } else { states_.clear(); for (auto stateNode : node.children(StateNodeName.data())) { auto indexAttr = stateNode.attribute("index"); auto freqAttr = stateNode.attribute("freq"); if (indexAttr && freqAttr) { auto index = indexAttr.as_uint(); auto indexIt = std::find_if( statesDefault_.cbegin(), statesDefault_.cend(), [=](auto const &state) { return state.first == index; }); if (indexIt == statesDefault_.cend()) continue; // skip unknown index auto freq = freqAttr.as_uint(); states_.emplace_back(index, units::frequency::megahertz_t(freq)); } else continue; // skip malformed state data } if (states_.size() != statesDefault_.size()) { // mix loaded states with default states std::set> states( statesDefault_.cbegin(), statesDefault_.cend()); for (auto &state : states_) { states.erase(state); states.insert(state); } states_ = std::vector>( states.cbegin(), states.cend()); } } } void AMD::PMFreqRangeXMLParser::loadStatesFromLegacyNode(pugi::xml_node const &node) { auto statesNode = node.find_child([&](pugi::xml_node const &node) { // match states node if (node.name() != LegacyStatesNodeName) return false; // match state return node.attribute("id").as_string() == nodeID_; }); loadStates(statesNode); } bool const AMD::PMFreqRangeXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMFreqRange::ItemID, []() { return std::make_unique(); }); pmfreqrangexmlparser.h000066400000000000000000000041261467225065400345460ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqrange// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmfreqrangeprofilepart.h" #include #include #include #include namespace AMD { class PMFreqRangeXMLParser final : public ProfilePartXMLParser , public AMD::PMFreqRangeProfilePart::Exporter , public AMD::PMFreqRangeProfilePart::Importer { public: PMFreqRangeXMLParser() noexcept; std::string const &instanceID() const final override; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMFreqRangeControlName(std::string const &name) override; void takePMFreqRangeStates( std::vector> const &states) override; units::frequency::megahertz_t providePMFreqRangeState(unsigned int index) const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; void saveStates(pugi::xml_node &node) const; void loadStates(pugi::xml_node const &node); void loadStatesFromLegacyNode(pugi::xml_node const &node); private: static constexpr std::string_view LegacyStatesNodeName{"STATES"}; static constexpr std::string_view StateNodeName{"STATE"}; class Initializer; bool active_; bool activeDefault_; std::string controlName_; std::string nodeID_; std::vector> states_; std::vector> statesDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt/000077500000000000000000000000001467225065400300745ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvolt.cpp000066400000000000000000000150741467225065400330060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqvolt.h" #include "core/components/amdutils.h" #include "core/components/controls/amd/pm/handlers/ippdpmhandler.h" #include "core/icommandqueue.h" #include #include AMD::PMFreqVolt::PMFreqVolt( std::string &&controlName, std::string &&controlCmdId, std::unique_ptr>> &&ppOdClkVoltDataSource, std::unique_ptr &&ppDpmHandler) noexcept : Control(true) , id_(AMD::PMFreqVolt::ItemID) , controlName_(std::move(controlName)) , controlCmdId_(std::move(controlCmdId)) , ppDpmHandler_(std::move(ppDpmHandler)) , ppOdClkVoltDataSource_(std::move(ppOdClkVoltDataSource)) , voltModes_({"auto", "manual"}) , voltMode_(AMD::PMFreqVolt::VoltMode::Automatic) { } void AMD::PMFreqVolt::preInit(ICommandQueue &ctlCmds) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { preInitStates_ = Utils::AMD::parseOverdriveClksVolts(controlName(), ppOdClkVoltLines_) .value(); ppDpmHandler_->saveState(); cleanControl(ctlCmds); } } void AMD::PMFreqVolt::postInit(ICommandQueue &ctlCmds) { for (auto [index, freq, volt] : preInitStates_) { ctlCmds.add( {ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(index, freq, volt)}); } if (!preInitStates_.empty()) ppDpmHandler_->restoreState(ctlCmds); } void AMD::PMFreqVolt::init() { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { freqRange_ = Utils::AMD::parseOverdriveClkRange(controlName(), ppOdClkVoltLines_) .value(); voltRange_ = Utils::AMD::parseOverdriveVoltRange(ppOdClkVoltLines_).value(); auto states = Utils::AMD::parseOverdriveClksVolts(controlName(), ppOdClkVoltLines_); auto [voltMin, voltMax] = voltRange_; auto [freqMin, freqMax] = freqRange_; for (auto [index, freq, volt] : states.value()) { initVoltages_.emplace(index, volt); states_.emplace(index, std::make_pair(std::clamp(freq, freqMin, freqMax), std::clamp(volt, voltMin, voltMax))); } } } std::string const &AMD::PMFreqVolt::ID() const { return id_; } std::string const &AMD::PMFreqVolt::instanceID() const { return controlName(); } void AMD::PMFreqVolt::importControl(IControl::Importer &i) { auto &importer = dynamic_cast(i); voltMode(importer.providePMFreqVoltVoltMode()); for (auto [index, _] : states_) { auto [freq, volt] = importer.providePMFreqVoltState(index); state(index, freq, volt); } ppDpmHandler_->activate(importer.providePMFreqVoltActiveStates()); } void AMD::PMFreqVolt::exportControl(IControl::Exporter &e) const { auto &exporter = dynamic_cast(e); exporter.takePMFreqVoltControlName(controlName()); exporter.takePMFreqVoltVoltModes(voltModes()); exporter.takePMFreqVoltVoltMode(voltMode()); auto [freqMim, freqMax] = freqRange(); exporter.takePMFreqVoltFreqRange(freqMim, freqMax); auto [voltMim, voltMax] = voltRange(); exporter.takePMFreqVoltVoltRange(voltMim, voltMax); exporter.takePMFreqVoltStates(states()); exporter.takePMFreqVoltActiveStates(ppDpmHandler_->active()); } void AMD::PMFreqVolt::cleanControl(ICommandQueue &ctlCmds) { ppDpmHandler_->reset(ctlCmds); } void AMD::PMFreqVolt::syncControl(ICommandQueue &ctlCmds) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { auto states = Utils::AMD::parseOverdriveClksVolts(controlName(), ppOdClkVoltLines_); for (auto [index, freq, volt] : states.value()) { auto [targetFreq, sVolt] = states_.at(index); auto targetVolt = voltMode_ == AMD::PMFreqVolt::VoltMode::Automatic ? initVoltages_.at(index) : sVolt; if (freq != targetFreq || volt != targetVolt) { ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(index, targetFreq, targetVolt)}); } } ppDpmHandler_->sync(ctlCmds); } } std::string const &AMD::PMFreqVolt::controlName() const { return controlName_; } std::string const &AMD::PMFreqVolt::controlCmdId() const { return controlCmdId_; } std::vector const &AMD::PMFreqVolt::voltModes() const { return voltModes_; } void AMD::PMFreqVolt::voltMode(std::string const &mode) { voltMode_ = mode == voltModes_[0] ? AMD::PMFreqVolt::VoltMode::Automatic : AMD::PMFreqVolt::VoltMode::Manual; } std::string const &AMD::PMFreqVolt::voltMode() const { return voltModes_[static_cast(voltMode_)]; } std::pair const & AMD::PMFreqVolt::freqRange() const { return freqRange_; } std::pair const & AMD::PMFreqVolt::voltRange() const { return voltRange_; } std::vector> AMD::PMFreqVolt::states() const { std::vector> states; states.reserve(states_.size()); std::transform(states_.cbegin(), states_.cend(), std::back_inserter(states), [](auto const &kv) { return std::make_tuple(kv.first, kv.second.first, kv.second.second); }); return states; } void AMD::PMFreqVolt::state(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) { auto [freqMin, freqMax] = freqRange(); auto [voltMin, voltMax] = voltRange(); auto &[sFreq, sVolt] = states_.at(index); sFreq = std::clamp(freq, freqMin, freqMax); sVolt = std::clamp(volt, voltMin, voltMax); } std::string AMD::PMFreqVolt::ppOdClkVoltCmd(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) const { std::string cmd; cmd.reserve(16); cmd.append(controlCmdId()) .append(" ") .append(std::to_string(index)) .append(" ") .append(std::to_string(freq.to())) .append(" ") .append(std::to_string(volt.to())); return cmd; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvolt.h000066400000000000000000000107261467225065400324520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include #include #include #include namespace AMD { class IPpDpmHandler; /// Overdrive frequency + voltage control. /// /// A frequency + voltage overdrive control has an identifier and a /// list of states that operates on both frequency and voltage values. /// /// States can be toggled on/off individually. class PMFreqVolt : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_FREQ_VOLT"}; class Importer : public IControl::Importer { public: virtual std::string const &providePMFreqVoltVoltMode() const = 0; virtual std::pair providePMFreqVoltState(unsigned int index) const = 0; virtual std::vector providePMFreqVoltActiveStates() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMFreqVoltControlName(std::string const &name) = 0; virtual void takePMFreqVoltVoltModes(std::vector const &modes) = 0; virtual void takePMFreqVoltVoltMode(std::string const &mode) = 0; virtual void takePMFreqVoltFreqRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) = 0; virtual void takePMFreqVoltVoltRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) = 0; virtual void takePMFreqVoltStates( std::vector> const &states) = 0; virtual void takePMFreqVoltActiveStates(std::vector const &states) = 0; }; PMFreqVolt(std::string &&controlName, std::string &&controlCmdId, std::unique_ptr>> &&ppOdClkVoltDataSource, std::unique_ptr &&ppDpmHandler) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; std::string const &instanceID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) override; void syncControl(ICommandQueue &ctlCmds) override; std::string const &controlName() const; std::string const &controlCmdId() const; std::vector const &voltModes() const; void voltMode(std::string const &mode); std::string const &voltMode() const; std::pair const & freqRange() const; std::pair const & voltRange() const; std::vector> states() const; void state(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt); std::string ppOdClkVoltCmd(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) const; private: std::string const id_; std::string const controlName_; std::string const controlCmdId_; std::unique_ptr const ppDpmHandler_; std::unique_ptr>> const ppOdClkVoltDataSource_; std::vector ppOdClkVoltLines_; enum class VoltMode { Automatic, Manual }; std::vector const voltModes_; VoltMode voltMode_; std::unordered_map initVoltages_; std::vector> preInitStates_; std::map> states_; std::pair freqRange_; std::pair voltRange_; }; } // namespace AMD pmfreqvoltprofilepart.cpp000066400000000000000000000156441467225065400352020ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqvoltprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class AMD::PMFreqVoltProfilePart::Initializer final : public AMD::PMFreqVolt::Exporter { public: Initializer(AMD::PMFreqVoltProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqVoltControlName(std::string const &name) override; void takePMFreqVoltVoltModes(std::vector const &modes) override; void takePMFreqVoltVoltRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) override; void takePMFreqVoltFreqRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) override; void takePMFreqVoltVoltMode(std::string const &mode) override; void takePMFreqVoltStates( std::vector> const &states) override; void takePMFreqVoltActiveStates(std::vector const &states) override; private: AMD::PMFreqVoltProfilePart &outer_; }; void AMD::PMFreqVoltProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltControlName( std::string const &name) { outer_.controlName_ = name; } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltVoltModes( std::vector const &modes) { outer_.voltModes_ = modes; } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltVoltRange( units::voltage::millivolt_t min, units::voltage::millivolt_t max) { outer_.voltRange_ = std::make_pair(min, max); } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltFreqRange( units::frequency::megahertz_t min, units::frequency::megahertz_t max) { outer_.freqRange_ = std::make_pair(min, max); } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltVoltMode( std::string const &mode) { outer_.voltMode_ = mode; } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltStates( std::vector> const &states) { outer_.states_ = states; } void AMD::PMFreqVoltProfilePart::Initializer::takePMFreqVoltActiveStates( std::vector const &states) { outer_.activeStates_ = states; } AMD::PMFreqVoltProfilePart::PMFreqVoltProfilePart() noexcept : id_(AMD::PMFreqVolt::ItemID) { } std::unique_ptr AMD::PMFreqVoltProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMFreqVoltProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMFreqVoltProfilePart::ID() const { return id_; } std::string const &AMD::PMFreqVoltProfilePart::instanceID() const { return controlName_; } std::optional> AMD::PMFreqVoltProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMFreqVoltProfilePart::provideActive() const { return active(); } std::string const &AMD::PMFreqVoltProfilePart::providePMFreqVoltVoltMode() const { return voltMode_; } std::pair AMD::PMFreqVoltProfilePart::providePMFreqVoltState(unsigned int index) const { auto stateIt = std::find_if( states_.cbegin(), states_.cend(), [=](auto const &state) { return std::get<0>(state) == index; }); if (stateIt != states_.cend()) return std::make_pair(std::get<1>(*stateIt), std::get<2>(*stateIt)); else return std::make_pair(units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); } std::vector AMD::PMFreqVoltProfilePart::providePMFreqVoltActiveStates() const { return activeStates_; } void AMD::PMFreqVoltProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &importer = dynamic_cast(i); voltMode(importer.providePMFreqVoltVoltMode()); for (auto const &[index, _1, _2] : states_) state(index, importer.providePMFreqVoltState(index)); activateStates(importer.providePMFreqVoltActiveStates()); } void AMD::PMFreqVoltProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &exporter = dynamic_cast(e); exporter.takePMFreqVoltControlName(controlName_); exporter.takePMFreqVoltVoltMode(voltMode_); exporter.takePMFreqVoltStates(states_); exporter.takePMFreqVoltActiveStates(activeStates_); } std::unique_ptr AMD::PMFreqVoltProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->controlName_ = controlName_; clone->voltModes_ = voltModes_; clone->voltMode_ = voltMode_; clone->voltRange_ = voltRange_; clone->freqRange_ = freqRange_; clone->states_ = states_; clone->activeStates_ = activeStates_; return std::move(clone); } void AMD::PMFreqVoltProfilePart::voltMode(std::string const &mode) { auto iter = std::find_if( voltModes_.cbegin(), voltModes_.cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != voltModes_.cend()) voltMode_ = mode; } void AMD::PMFreqVoltProfilePart::state( unsigned int index, std::pair const &value) { auto stateIt = std::find_if( states_.begin(), states_.end(), [=](auto const &state) { return std::get<0>(state) == index; }); if (stateIt != states_.end()) { auto &[_, sFreq, sVolt] = *stateIt; sFreq = std::clamp(value.first, freqRange_.first, freqRange_.second); sVolt = std::clamp(value.second, voltRange_.first, voltRange_.second); } } void AMD::PMFreqVoltProfilePart::activateStates( std::vector const &states) { std::vector active; std::copy_if(states.cbegin(), states.cend(), std::back_inserter(active), [&](unsigned int index) { // skip unknown state states return std::find_if(states_.cbegin(), states_.cend(), [&](auto const &state) { return std::get<0>(state) == index; }) != states_.cend(); }); if (!active.empty()) // at least one state must be active std::swap(active, activeStates_); } bool const AMD::PMFreqVoltProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMFreqVolt::ItemID, []() { return std::make_unique(); }); pmfreqvoltprofilepart.h000066400000000000000000000056411467225065400346430ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmfreqvolt.h" #include #include #include #include namespace AMD { class PMFreqVoltProfilePart final : public ProfilePart , public PMFreqVolt::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &providePMFreqVoltVoltMode() const = 0; virtual std::pair providePMFreqVoltState(unsigned int index) const = 0; virtual std::vector providePMFreqVoltActiveStates() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMFreqVoltControlName(std::string const &mode) = 0; virtual void takePMFreqVoltVoltMode(std::string const &mode) = 0; virtual void takePMFreqVoltStates( std::vector> const &states) = 0; virtual void takePMFreqVoltActiveStates(std::vector const &states) = 0; }; PMFreqVoltProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::string const &instanceID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::string const &providePMFreqVoltVoltMode() const override; std::pair providePMFreqVoltState(unsigned int index) const override; std::vector providePMFreqVoltActiveStates() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void voltMode(std::string const &mode); void state(unsigned int index, std::pair const &value); void activateStates(std::vector const &states); class Initializer; std::string const id_; std::string controlName_; std::string voltMode_; std::vector voltModes_; std::pair voltRange_; std::pair freqRange_; std::vector> states_; std::vector activeStates_; static bool const registered_; }; } // namespace AMD pmfreqvoltprovider.cpp000066400000000000000000000101051467225065400344700ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqvoltprovider.h" #include "../pmoverdriveprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/components/controls/amd/pm/handlers/ppdpmhandler.h" #include "core/info/amd/gpuinfopmoverdrive.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmfreqvolt.h" #include #include #include std::optional AMD::PMFreqVoltProvider::getControlDPMPath(IGPUInfo const &gpuInfo, std::string control) const { std::transform(control.cbegin(), control.cend(), control.begin(), ::tolower); auto dpmPath = gpuInfo.path().sys / ("pp_dpm_" + control); if (!Utils::File::isSysFSEntryValid(dpmPath)) return {}; auto dpmLines = Utils::File::readFileLines(dpmPath); if (!Utils::AMD::parseDPMStates(dpmLines)) { SPDLOG_WARN("Unknown data format on {}", dpmPath.string()); for (auto const &line : dpmLines) SPDLOG_DEBUG(line); return {}; } return dpmPath; } bool AMD::PMFreqVoltProvider::hasValidOverdriveControl( std::string const &controlName, std::filesystem::path const &ppOdClkVoltPath, std::vector const &ppOdClkVoltLines) const { auto valid = !Utils::AMD::ppOdClkVoltageHasKnownFreqVoltQuirks(controlName, ppOdClkVoltLines) && Utils::AMD::parseOverdriveClkRange(controlName, ppOdClkVoltLines) && Utils::AMD::parseOverdriveVoltRange(ppOdClkVoltLines) && Utils::AMD::parseOverdriveClksVolts(controlName, ppOdClkVoltLines); if (!valid) { SPDLOG_WARN("Invalid data on {} for control {}", ppOdClkVoltPath.string(), controlName); for (auto const &line : ppOdClkVoltLines) SPDLOG_DEBUG(line); } return valid; } std::optional> AMD::PMFreqVoltProvider::createControl( IGPUInfo const &gpuInfo, std::string controlName, std::filesystem::path const &perfLevelPath, std::filesystem::path const &ppOdClkVoltPath, std::vector const &ppOdClkVoltLines) const { auto controlDPMPath = getControlDPMPath(gpuInfo, controlName); if (!controlDPMPath) return {}; if (!hasValidOverdriveControl(controlName, ppOdClkVoltPath, ppOdClkVoltLines)) return {}; auto controlCmdId = Utils::AMD::getOverdriveClkControlCmdId(controlName); if (!controlCmdId) { SPDLOG_WARN("Unsupported control {}", controlName); return {}; } return std::make_unique( std::move(controlName), std::move(*controlCmdId), std::make_unique>>(ppOdClkVoltPath), std::make_unique( std::make_unique>(perfLevelPath), std::make_unique>>( *controlDPMPath))); } std::vector> AMD::PMFreqVoltProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && gpuInfo.hasCapability(GPUInfoPMOverdrive::ClkVolt))) return {}; auto ppOdClkVoltPath = gpuInfo.path().sys / "pp_od_clk_voltage"; auto ppOdClkVoltLines = Utils::File::readFileLines(ppOdClkVoltPath); auto const controlNames = Utils::AMD::parseOverdriveClkControls(ppOdClkVoltLines); if (!controlNames) return {}; std::vector> controls; auto perfLevelPath = gpuInfo.path().sys / "power_dpm_force_performance_level"; for (auto controlName : controlNames.value()) { auto control = createControl(gpuInfo, controlName, perfLevelPath, ppOdClkVoltPath, ppOdClkVoltLines); if (control) controls.emplace_back(std::move(*control)); } return controls; } bool const AMD::PMFreqVoltProvider::registered_ = AMD::PMOverdriveProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvoltprovider.h000066400000000000000000000022431467225065400342200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include #include #include #include namespace AMD { class PMFreqVoltProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: std::optional getControlDPMPath(IGPUInfo const &gpuInfo, std::string control) const; bool hasValidOverdriveControl( std::string const &controlName, std::filesystem::path const &ppOdClkVoltPath, std::vector const &ppOdClkVoltLines) const; std::optional> createControl(IGPUInfo const &gpuInfo, std::string controlName, std::filesystem::path const &perfLevelPath, std::filesystem::path const &ppOdClkVoltPath, std::vector const &ppOdClkVoltLines) const; static bool const registered_; }; } // namespace AMD pmfreqvoltqmlitem.cpp000066400000000000000000000215401467225065400343130ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqvoltqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmfreqvolt.h" #include #include #include #include #include #include #include #include char const *const AMD::PMFreqVoltQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("AMD::PMFreqVoltQMLItem", "SCLK"), QT_TRANSLATE_NOOP("AMD::PMFreqVoltQMLItem", "MCLK"), }; class AMD::PMFreqVoltQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMFreqVolt::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMFreqVoltQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqVoltControlName(std::string const &name) override; void takePMFreqVoltVoltRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) override; void takePMFreqVoltFreqRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) override; void takePMFreqVoltVoltMode(std::string const &mode) override; void takePMFreqVoltVoltModes(std::vector const &modes) override; void takePMFreqVoltStates( std::vector> const &states) override; void takePMFreqVoltActiveStates(std::vector const &indices) override; private: AMD::PMFreqVoltQMLItem &outer_; }; void AMD::PMFreqVoltQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltControlName( std::string const &name) { outer_.takePMFreqVoltControlName(name); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltVoltRange( units::voltage::millivolt_t min, units::voltage::millivolt_t max) { outer_.voltRange(min, max); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltFreqRange( units::frequency::megahertz_t min, units::frequency::megahertz_t max) { outer_.freqRange(min, max); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltVoltMode( std::string const &mode) { outer_.takePMFreqVoltVoltMode(mode); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltVoltModes( std::vector const &modes) { outer_.voltModes(modes); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltStates( std::vector> const &states) { outer_.takePMFreqVoltStates(states); } void AMD::PMFreqVoltQMLItem::Initializer::takePMFreqVoltActiveStates( std::vector const &indices) { outer_.takePMFreqVoltActiveStates(indices); } AMD::PMFreqVoltQMLItem::PMFreqVoltQMLItem() noexcept { setName(tr(AMD::PMFreqVolt::ItemID.data())); } void AMD::PMFreqVoltQMLItem::changeVoltMode(const QString &mode) { auto newMode = mode.toStdString(); if (voltMode_ != newMode) { voltMode_ = newMode; emit voltModeChanged(mode); emit settingsChanged(); } } void AMD::PMFreqVoltQMLItem::changeState(int index, int freq, int volt) { if (states_.count(static_cast(index))) { auto &[stateFreq, stateVolt] = states_.at(static_cast(index)); if (stateFreq.to() != freq || stateVolt.to() != volt) { stateFreq = units::frequency::megahertz_t(freq); stateVolt = units::voltage::millivolt_t(volt); emit stateChanged(index, freq, volt); emit settingsChanged(); } } } void AMD::PMFreqVoltQMLItem::changeActiveState(int index, bool activate) { if (states_.count(static_cast(index))) { if (activate) { auto activeIt = std::find(activeStates_.cbegin(), activeStates_.cend(), index); if (activeIt == activeStates_.cend()) { activeStates_.push_back(static_cast(index)); emit activeStatesChanged(activeStatesIndices(activeStates_)); emit settingsChanged(); } } else { std::erase(activeStates_, static_cast(index)); emit activeStatesChanged(activeStatesIndices(activeStates_)); emit settingsChanged(); } } } QString const &AMD::PMFreqVoltQMLItem::instanceID() const { return instanceID_; } void AMD::PMFreqVoltQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMFreqVoltQMLItem::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFreqVoltQMLItem::provideImporter(Item const &) { return {}; } void AMD::PMFreqVoltQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::PMFreqVoltQMLItem::takePMFreqVoltControlName(std::string const &name) { controlName(name); } void AMD::PMFreqVoltQMLItem::takePMFreqVoltVoltMode(std::string const &mode) { if (voltMode_ != mode) { voltMode_ = mode; emit voltModeChanged(QString::fromStdString(voltMode_)); } } void AMD::PMFreqVoltQMLItem::takePMFreqVoltStates( std::vector> const &states) { std::map> newStates; QVariantList statesList; statesList.reserve(states.size() * 3); for (auto const &[index, freq, volt] : states) { newStates.emplace(index, std::make_pair(freq, volt)); statesList.push_back(index); statesList.push_back(freq.to()); statesList.push_back(volt.to()); } if (newStates != states_) { std::swap(states_, newStates); emit statesChanged(statesList); } } void AMD::PMFreqVoltQMLItem::takePMFreqVoltActiveStates( std::vector const &indices) { if (indices != activeStates_) { activeStates_ = indices; emit activeStatesChanged(activeStatesIndices(indices)); } } bool AMD::PMFreqVoltQMLItem::provideActive() const { return active_; } std::string const &AMD::PMFreqVoltQMLItem::providePMFreqVoltVoltMode() const { return voltMode_; } std::pair AMD::PMFreqVoltQMLItem::providePMFreqVoltState(unsigned int index) const { if (states_.count(index) > 0) return states_.at(index); else return std::make_pair(units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); } std::vector AMD::PMFreqVoltQMLItem::providePMFreqVoltActiveStates() const { return activeStates_; } std::unique_ptr AMD::PMFreqVoltQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::PMFreqVoltQMLItem::controlName(std::string const &name) { instanceID_ = QString::fromStdString(name); emit controlLabelChanged(tr(name.c_str())); } void AMD::PMFreqVoltQMLItem::voltModes(std::vector const &) { } void AMD::PMFreqVoltQMLItem::voltRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) { emit voltRangeChanged(min.to(), max.to()); } void AMD::PMFreqVoltQMLItem::freqRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max) { emit freqRangeChanged(min.to(), max.to()); } QVector AMD::PMFreqVoltQMLItem::activeStatesIndices( std::vector const &indices) const { QVector states; states.reserve(indices.size()); std::transform(indices.cbegin(), indices.cend(), std::back_inserter(states), [&](unsigned int index) { return static_cast(index); }); return states; } bool AMD::PMFreqVoltQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMFreqVolt::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMFreqVolt::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMFreqVoltForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMFreqVoltQMLItem::registered_ = AMD::PMFreqVoltQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvoltqmlitem.h000066400000000000000000000060461467225065400340430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmfreqvoltprofilepart.h" #include #include #include #include #include #include #include #include namespace AMD { class PMFreqVoltQMLItem : public QMLItem , public AMD::PMFreqVoltProfilePart::Importer , public AMD::PMFreqVoltProfilePart::Exporter { Q_OBJECT Q_PROPERTY(QString instanceID READ instanceID) public: explicit PMFreqVoltQMLItem() noexcept; signals: void controlLabelChanged(QString const &label); void voltRangeChanged(int min, int max); void freqRangeChanged(int min, int max); void voltModeChanged(QString const &mode); void statesChanged(QVariantList const &states); void activeStatesChanged(QVector const &states); void stateChanged(int index, int freq, int volt); public slots: void changeVoltMode(QString const &mode); void changeState(int index, int freq, int volt); void changeActiveState(int index, bool activate); public: QString const &instanceID() const; void activate(bool active) override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; void takePMFreqVoltControlName(std::string const &mode) override; void takePMFreqVoltVoltMode(std::string const &mode) override; void takePMFreqVoltStates( std::vector> const &states) override; void takePMFreqVoltActiveStates(std::vector const &states) override; bool provideActive() const override; std::string const &providePMFreqVoltVoltMode() const override; std::pair providePMFreqVoltState(unsigned int index) const override; std::vector providePMFreqVoltActiveStates() const override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void controlName(std::string const &name); void voltModes(std::vector const &modes); void voltRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max); void freqRange(units::frequency::megahertz_t min, units::frequency::megahertz_t max); QVector activeStatesIndices(std::vector const &indices) const; QString instanceID_; bool active_; std::string voltMode_; std::map> states_; std::vector activeStates_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD pmfreqvoltxmlparser.cpp000066400000000000000000000200111467225065400346500ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmfreqvoltxmlparser.h" #include "../pmoverdrive.h" #include "core/profilepartxmlparserprovider.h" #include "pmfreqvolt.h" #include #include class AMD::PMFreqVoltXMLParser::Initializer final : public AMD::PMFreqVoltProfilePart::Exporter { public: Initializer(AMD::PMFreqVoltXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFreqVoltControlName(std::string const &name) override; void takePMFreqVoltVoltMode(std::string const &mode) override; void takePMFreqVoltStates( std::vector> const &states) override; void takePMFreqVoltActiveStates(std::vector const &states) override; private: AMD::PMFreqVoltXMLParser &outer_; }; void AMD::PMFreqVoltXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMFreqVoltXMLParser::Initializer::takePMFreqVoltControlName( std::string const &name) { outer_.controlName_ = name; outer_.nodeID_ = name; std::transform(outer_.nodeID_.cbegin(), outer_.nodeID_.cend(), outer_.nodeID_.begin(), ::tolower); } void AMD::PMFreqVoltXMLParser::Initializer::takePMFreqVoltVoltMode( std::string const &mode) { outer_.voltMode_ = outer_.voltModeDefault_ = mode; } void AMD::PMFreqVoltXMLParser::Initializer::takePMFreqVoltStates( std::vector> const &states) { outer_.states_ = outer_.statesDefault_ = states; } void AMD::PMFreqVoltXMLParser::Initializer::takePMFreqVoltActiveStates( std::vector const &states) { outer_.activeStates_ = outer_.activeStatesDefault_ = states; } AMD::PMFreqVoltXMLParser::PMFreqVoltXMLParser() noexcept : ProfilePartXMLParser(AMD::PMFreqVolt::ItemID, *this, *this) { } std::string const &AMD::PMFreqVoltXMLParser::instanceID() const { return controlName_; } std::unique_ptr AMD::PMFreqVoltXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMFreqVoltXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMFreqVoltXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFreqVoltXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMFreqVoltXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMFreqVoltXMLParser::provideActive() const { return active_; } void AMD::PMFreqVoltXMLParser::takePMFreqVoltControlName(std::string const &) { } void AMD::PMFreqVoltXMLParser::takePMFreqVoltVoltMode(std::string const &mode) { voltMode_ = mode; } void AMD::PMFreqVoltXMLParser::takePMFreqVoltStates( std::vector> const &states) { states_ = states; } void AMD::PMFreqVoltXMLParser::takePMFreqVoltActiveStates( std::vector const &states) { activeStates_ = states; } std::string const &AMD::PMFreqVoltXMLParser::providePMFreqVoltVoltMode() const { return voltMode_; } std::pair AMD::PMFreqVoltXMLParser::providePMFreqVoltState(unsigned int index) const { auto stateIt = std::find_if( states_.cbegin(), states_.cend(), [=](auto const &state) { return std::get<0>(state) == index; }); if (stateIt != states_.cend()) return std::make_pair(std::get<1>(*stateIt), std::get<2>(*stateIt)); else return std::make_pair(units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); } std::vector AMD::PMFreqVoltXMLParser::providePMFreqVoltActiveStates() const { return activeStates_; } void AMD::PMFreqVoltXMLParser::appendTo(pugi::xml_node &parentNode) { auto node = parentNode.append_child(ID().c_str()); node.append_attribute("active") = active_; node.append_attribute("id") = nodeID_.c_str(); node.append_attribute("voltMode") = voltMode_.c_str(); saveStates(node); } void AMD::PMFreqVoltXMLParser::resetAttributes() { active_ = activeDefault_; voltMode_ = voltModeDefault_; states_ = statesDefault_; activeStates_ = activeStatesDefault_; } void AMD::PMFreqVoltXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto legacyNode = parentNode.find_child([&](pugi::xml_node const &node) { return node.name() == AMD::PMOverdrive::LegacyFVStateItemID; }); if (!legacyNode) { auto node = parentNode.find_child([&](pugi::xml_node const &node) { if (node.name() != ID()) return false; return node.attribute("id").as_string() == nodeID_; }); active_ = node.attribute("active").as_bool(activeDefault_); voltMode_ = node.attribute("voltMode").as_string(voltModeDefault_.c_str()); loadStates(node); } else { active_ = legacyNode.attribute("active").as_bool(activeDefault_); loadStatesFromLegacyNode(legacyNode); } } void AMD::PMFreqVoltXMLParser::saveStates(pugi::xml_node &node) const { for (auto [index, freq, volt] : states_) { auto stateNode = node.append_child(StateNodeName.data()); auto activeIt = std::find(activeStates_.cbegin(), activeStates_.cend(), index); stateNode.append_attribute("active") = activeIt != activeStates_.cend(); stateNode.append_attribute("index") = index; stateNode.append_attribute("freq") = freq.to(); stateNode.append_attribute("volt") = volt.to(); } } void AMD::PMFreqVoltXMLParser::loadStates(pugi::xml_node const &node) { if (!node) { states_ = statesDefault_; activeStates_ = activeStatesDefault_; } else { states_.clear(); activeStates_.clear(); for (auto stateNode : node.children(StateNodeName.data())) { auto activeAttr = stateNode.attribute("active"); auto indexAttr = stateNode.attribute("index"); auto freqAttr = stateNode.attribute("freq"); auto voltAttr = stateNode.attribute("volt"); if (activeAttr && indexAttr && freqAttr && voltAttr) { auto index = indexAttr.as_uint(); auto indexIt = std::find_if( statesDefault_.cbegin(), statesDefault_.cend(), [=](auto const &state) { return std::get<0>(state) == index; }); if (indexIt == statesDefault_.cend()) // unknown index break; auto freq = freqAttr.as_uint(); auto volt = voltAttr.as_uint(); states_.emplace_back(index, units::frequency::megahertz_t(freq), units::voltage::millivolt_t(volt)); if (activeAttr.as_bool()) activeStates_.emplace_back(index); } else // malformed data break; } if (states_.size() != statesDefault_.size()) { states_ = statesDefault_; activeStates_ = activeStatesDefault_; } else if (activeStates_.size() > statesDefault_.size()) activeStates_ = activeStatesDefault_; } } void AMD::PMFreqVoltXMLParser::loadStatesFromLegacyNode(pugi::xml_node const &node) { auto statesNode = node.find_child([&](pugi::xml_node const &node) { // match states node if (node.name() != LegacyStatesNodeName) return false; // match state return node.attribute("id").as_string() == nodeID_; }); voltMode_ = statesNode.attribute("voltMode").as_string(voltModeDefault_.c_str()); loadStates(statesNode); } bool const AMD::PMFreqVoltXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMFreqVolt::ItemID, []() { return std::make_unique(); }); pmfreqvoltxmlparser.h000066400000000000000000000053361467225065400343320ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/freqvolt// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmfreqvoltprofilepart.h" #include #include #include #include namespace AMD { class PMFreqVoltXMLParser final : public ProfilePartXMLParser , public AMD::PMFreqVoltProfilePart::Exporter , public AMD::PMFreqVoltProfilePart::Importer { public: PMFreqVoltXMLParser() noexcept; std::string const &instanceID() const final override; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMFreqVoltControlName(std::string const &name) override; void takePMFreqVoltVoltMode(std::string const &mode) override; void takePMFreqVoltStates( std::vector> const &states) override; void takePMFreqVoltActiveStates(std::vector const &states) override; std::string const &providePMFreqVoltVoltMode() const override; std::pair providePMFreqVoltState(unsigned int index) const override; std::vector providePMFreqVoltActiveStates() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; void saveStates(pugi::xml_node &node) const; void loadStates(pugi::xml_node const &node); void loadStatesFromLegacyNode(pugi::xml_node const &node); private: static constexpr std::string_view LegacyStatesNodeName{"STATES"}; static constexpr std::string_view StateNodeName{"STATE"}; class Initializer; bool active_; bool activeDefault_; std::string controlName_; std::string nodeID_; std::string voltMode_; std::string voltModeDefault_; std::vector> states_; std::vector> statesDefault_; std::vector activeStates_; std::vector activeStatesDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdrive.cpp000066400000000000000000000045641467225065400313110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmoverdrive.h" #include "core/icommandqueue.h" #include AMD::PMOverdrive::PMOverdrive( std::unique_ptr> &&perfLevelDataSource, std::unique_ptr>> &&ppOdClkVoltDataSource, std::vector> &&controls) noexcept : ControlGroup(AMD::PMOverdrive::ItemID, std::move(controls), false) , perfLevelDataSource_(std::move(perfLevelDataSource)) , ppOdClkVoltDataSource_(std::move(ppOdClkVoltDataSource)) { } void AMD::PMOverdrive::preInit(ICommandQueue &ctlCmds) { perfLevelDataSource_->read(perfLevelPreInitValue_); // NOTE Each aggregated control will generate clean commands on its // own preInit stage. As cleanControl forces the generation of clean // commands on aggregated controls, it cannot be called here. if (perfLevelDataSource_->read(perfLevelEntry_) && perfLevelEntry_ != "manual") ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.add({ppOdClkVoltDataSource_->source(), "r"}); ctlCmds.add({ppOdClkVoltDataSource_->source(), "c"}); ControlGroup::preInit(ctlCmds); } void AMD::PMOverdrive::postInit(ICommandQueue &ctlCmds) { ControlGroup::postInit(ctlCmds); ctlCmds.add({ppOdClkVoltDataSource_->source(), "c"}); ctlCmds.add({perfLevelDataSource_->source(), perfLevelPreInitValue_}); } void AMD::PMOverdrive::cleanControl(ICommandQueue &ctlCmds) { if (perfLevelDataSource_->read(perfLevelEntry_) && perfLevelEntry_ != "manual") ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.add({ppOdClkVoltDataSource_->source(), "r"}); ctlCmds.add({ppOdClkVoltDataSource_->source(), "c"}); ControlGroup::cleanControl(ctlCmds); } void AMD::PMOverdrive::syncControl(ICommandQueue &ctlCmds) { if (perfLevelDataSource_->read(perfLevelEntry_)) { if (perfLevelEntry_ != "manual") ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.pack(true); ControlGroup::syncControl(ctlCmds); auto commit = ctlCmds.packWritesTo(ppOdClkVoltDataSource_->source()); if (commit.has_value() && *commit) ctlCmds.add({ppOdClkVoltDataSource_->source(), "c"}); ctlCmds.pack(false); } } std::string const &AMD::PMOverdrive::perfLevelPreInitValue() const { return perfLevelPreInitValue_; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdrive.h000066400000000000000000000026261467225065400307530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlgroup.h" #include "core/idatasource.h" #include #include #include #include namespace AMD { class PMOverdrive : public ControlGroup { public: static constexpr std::string_view ItemID{"AMD_PM_OVERDRIVE"}; // Legacy overdrive controls ItemIDs static constexpr std::string_view LegacyFVStateItemID{"AMD_PM_FV_STATE"}; static constexpr std::string_view LegacyFVVoltCurveItemID{ "AMD_PM_FV_VOLTCURVE"}; PMOverdrive(std::unique_ptr> &&perfLevelDataSource, std::unique_ptr>> &&ppOdClkVoltDataSource, std::vector> &&controls) noexcept; void preInit(ICommandQueue &ctlCmds) override; void postInit(ICommandQueue &ctlCmds) override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; protected: std::string const &perfLevelPreInitValue() const; private: std::unique_ptr> const perfLevelDataSource_; std::unique_ptr>> const ppOdClkVoltDataSource_; std::string perfLevelEntry_; std::string perfLevelPreInitValue_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdriveprofilepart.cpp000066400000000000000000000012631467225065400335520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmoverdriveprofilepart.h" #include "core/profilepartprovider.h" #include "pmoverdrive.h" #include AMD::PMOverdriveProfilePart::PMOverdriveProfilePart() noexcept : ControlGroupProfilePart(AMD::PMOverdrive::ItemID) { } std::unique_ptr AMD::PMOverdriveProfilePart::instance() const { return std::make_unique(); } bool const AMD::PMOverdriveProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMOverdrive::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdriveprofilepart.h000066400000000000000000000007171467225065400332220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlgroupprofilepart.h" namespace AMD { class PMOverdriveProfilePart final : public ControlGroupProfilePart { public: PMOverdriveProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdriveprovider.cpp000066400000000000000000000046001467225065400330530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmoverdriveprovider.h" #include "../pmadvancedprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/iswinfo.h" #include "core/sysfsdatasource.h" #include "pmoverdrive.h" #include #include #include #include std::vector> AMD::PMOverdriveProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto kernel = Utils::String::parseVersion(swInfo.info(ISWInfo::Keys::kernelVersion)); auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (!(driver == "amdgpu" && (kernel >= std::make_tuple(4, 18, 0)))) return {}; auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; auto ppOdClkVolt = gpuInfo.path().sys / "pp_od_clk_voltage"; if (!(Utils::File::isSysFSEntryValid(perfLevel) && Utils::File::isSysFSEntryValid(ppOdClkVolt))) return {}; std::vector> groupControls; for (auto const &provider : providers_()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); groupControls.insert(groupControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (groupControls.empty()) return {}; std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>(perfLevel), std::make_unique>>(ppOdClkVolt), std::move(groupControls))); return controls; } bool AMD::PMOverdriveProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::PMOverdriveProvider::providers_() { static std::vector> providers; return providers; } bool const AMD::PMOverdriveProvider::registered_ = AMD::PMAdvancedProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdriveprovider.h000066400000000000000000000013061467225065400325200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class PMOverdriveProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdriveqmlitem.cpp000066400000000000000000000020671467225065400326760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmoverdriveqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmoverdrive.h" #include #include #include #include #include AMD::PMOverdriveQMLItem::PMOverdriveQMLItem() noexcept : ControlGroupQMLItem(AMD::PMOverdrive::ItemID) { } bool AMD::PMOverdriveQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMOverdrive::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMOverdrive::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMOverdriveForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMOverdriveQMLItem::registered_ = AMD::PMOverdriveQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdriveqmlitem.h000066400000000000000000000006121467225065400323350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlgroupqmlitem.h" namespace AMD { class PMOverdriveQMLItem : public ControlGroupQMLItem { public: explicit PMOverdriveQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdrivexmlparser.cpp000066400000000000000000000021031467225065400332320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmoverdrivexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmoverdrive.h" #include AMD::PMOverdriveXMLParser::PMOverdriveXMLParser() noexcept : ControlGroupXMLParser(AMD::PMOverdrive::ItemID) { } void AMD::PMOverdriveXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto node = parentNode.find_child([&](pugi::xml_node const &node) { return node.name() == AMD::PMOverdrive::ItemID; }); takeActive(node.attribute("active").as_bool(activeDefault())); if (!node) { // Legacy control settings section might be present in the profile. // These section hangs from the parent node, so we must pass it // to load the settings on each sub-component. node = parentNode; } loadComponents(node); } bool const AMD::PMOverdriveXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMOverdrive::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/pmoverdrivexmlparser.h000066400000000000000000000007071467225065400327070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlgroupxmlparser.h" namespace AMD { class PMOverdriveXMLParser final : public ControlGroupXMLParser { public: PMOverdriveXMLParser() noexcept; protected: void loadPartFrom(pugi::xml_node const &parentNode) final override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve/000077500000000000000000000000001467225065400302635ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurve.cpp000066400000000000000000000115501467225065400333570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltcurve.h" #include "core/components/amdutils.h" #include "core/icommandqueue.h" #include #include #include AMD::PMVoltCurve::PMVoltCurve(std::string &&controlCmdId, std::unique_ptr>> &&ppOdClkVoltDataSource) noexcept : Control(true) , id_(AMD::PMVoltCurve::ItemID) , controlCmdId_(std::move(controlCmdId)) , ppOdClkVoltDataSource_(std::move(ppOdClkVoltDataSource)) , modes_({"auto", "manual"}) , mode_(AMD::PMVoltCurve::Mode::Automatic) { } void AMD::PMVoltCurve::preInit(ICommandQueue &) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { preInitPoints_ = Utils::AMD::parseOverdriveVoltCurve(ppOdClkVoltLines_).value(); } } void AMD::PMVoltCurve::postInit(ICommandQueue &ctlCmds) { for (size_t i = 0; i < preInitPoints_.size(); ++i) { auto [freq, volt] = preInitPoints_.at(i); ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(static_cast(i), freq, volt)}); } } void AMD::PMVoltCurve::init() { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { pointsRange_ = Utils::AMD::parseOverdriveVoltCurveRange(ppOdClkVoltLines_).value(); points_ = initPoints_ = Utils::AMD::parseOverdriveVoltCurve(ppOdClkVoltLines_).value(); } } std::string const &AMD::PMVoltCurve::ID() const { return id_; } void AMD::PMVoltCurve::importControl(IControl::Importer &i) { auto &importer = dynamic_cast(i); mode(importer.providePMVoltCurveMode()); for (size_t i = 0; i < points().size(); ++i) { auto [freq, volt] = importer.providePMVoltCurvePoint(static_cast(i)); point(static_cast(i), freq, volt); } } void AMD::PMVoltCurve::exportControl(IControl::Exporter &e) const { auto &pmFVVoltCurveExporter = dynamic_cast(e); pmFVVoltCurveExporter.takePMVoltCurveModes(modes()); pmFVVoltCurveExporter.takePMVoltCurveMode(mode()); pmFVVoltCurveExporter.takePMVoltCurvePointsRange(pointsRange()); pmFVVoltCurveExporter.takePMVoltCurvePoints(points()); } void AMD::PMVoltCurve::cleanControl(ICommandQueue &) { } void AMD::PMVoltCurve::syncControl(ICommandQueue &ctlCmds) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { auto points = Utils::AMD::parseOverdriveVoltCurve(ppOdClkVoltLines_); for (size_t i = 0; i < points->size(); ++i) { auto [freq, volt] = points->at(i); auto [targetFreq, targetVolt] = mode_ == AMD::PMVoltCurve::Mode::Automatic ? initPoints_.at(i) : points_.at(i); if (freq != targetFreq || volt != targetVolt) { ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(static_cast(i), targetFreq, targetVolt)}); } } } } std::string const &AMD::PMVoltCurve::controlCmdId() const { return controlCmdId_; } std::vector const &AMD::PMVoltCurve::modes() const { return modes_; } void AMD::PMVoltCurve::mode(std::string const &mode) { mode_ = mode == modes_[0] ? AMD::PMVoltCurve::Mode::Automatic : AMD::PMVoltCurve::Mode::Manual; } std::string const &AMD::PMVoltCurve::mode() const { return modes_[static_cast(mode_)]; } std::vector, std::pair>> const & AMD::PMVoltCurve::pointsRange() const { return pointsRange_; } std::vector> const & AMD::PMVoltCurve::points() const { return points_; } void AMD::PMVoltCurve::point(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) { if (index < points_.size()) { auto [freqRange, voltRange] = pointsRange_.at(index); auto &[pointFreq, pointVolt] = points_.at(index); pointFreq = std::clamp(freq, freqRange.first, freqRange.second); pointVolt = std::clamp(volt, voltRange.first, voltRange.second); } } std::string AMD::PMVoltCurve::ppOdClkVoltCmd(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) const { std::string cmd; cmd.reserve(16); cmd.append(controlCmdId()) .append(" ") .append(std::to_string(index)) .append(" ") .append(std::to_string(freq.to())) .append(" ") .append(std::to_string(volt.to())); return cmd; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurve.h000066400000000000000000000071301467225065400330230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include #include namespace AMD { /// Overdrive voltage curve control. class PMVoltCurve : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_VOLT_CURVE"}; class Importer : public IControl::Importer { public: virtual std::string const &providePMVoltCurveMode() const = 0; virtual std::pair providePMVoltCurvePoint(unsigned int index) const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMVoltCurveModes(std::vector const &modes) = 0; virtual void takePMVoltCurveMode(std::string const &mode) = 0; virtual void takePMVoltCurvePointsRange( std::vector, std::pair>> const &pointRanges) = 0; virtual void takePMVoltCurvePoints( std::vector> const &curve) = 0; }; PMVoltCurve(std::string &&controlCmdId, std::unique_ptr>> &&ppOdClkVoltDataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) override; void syncControl(ICommandQueue &ctlCmds) override; std::string const &controlCmdId() const; std::vector const &modes() const; void mode(std::string const &mode); std::string const &mode() const; std::vector, std::pair>> const & pointsRange() const; std::vector> const & points() const; void point(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt); std::string ppOdClkVoltCmd(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) const; private: std::string const id_; std::string const controlCmdId_; std::unique_ptr>> const ppOdClkVoltDataSource_; std::vector ppOdClkVoltLines_; enum class Mode { Automatic, Manual }; std::vector const modes_; Mode mode_; std::vector> preInitPoints_; std::vector> initPoints_; std::vector> points_; std::vector, std::pair>> pointsRange_; }; } // namespace AMD pmvoltcurveprofilepart.cpp000066400000000000000000000122071467225065400355500ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltcurveprofilepart.h" #include "core/profilepartprovider.h" #include #include #include #include class AMD::PMVoltCurveProfilePart::Initializer final : public AMD::PMVoltCurve::Exporter { public: Initializer(AMD::PMVoltCurveProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takePMVoltCurveModes(std::vector const &modes) override; void takePMVoltCurvePointsRange( std::vector, std::pair>> const &pointRanges) override; void takeActive(bool active) override; void takePMVoltCurveMode(std::string const &mode) override; void takePMVoltCurvePoints( std::vector> const &points) override; private: AMD::PMVoltCurveProfilePart &outer_; }; void AMD::PMVoltCurveProfilePart::Initializer::takePMVoltCurveModes( std::vector const &modes) { outer_.modes_ = modes; } void AMD::PMVoltCurveProfilePart::Initializer::takePMVoltCurvePointsRange( std::vector, std::pair>> const &pointRanges) { outer_.pointsRange_ = pointRanges; } void AMD::PMVoltCurveProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMVoltCurveProfilePart::Initializer::takePMVoltCurveMode( std::string const &mode) { outer_.mode_ = mode; } void AMD::PMVoltCurveProfilePart::Initializer::takePMVoltCurvePoints( std::vector> const &points) { outer_.points_ = points; } AMD::PMVoltCurveProfilePart::PMVoltCurveProfilePart() noexcept : id_(AMD::PMVoltCurve::ItemID) { } std::unique_ptr AMD::PMVoltCurveProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMVoltCurveProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMVoltCurveProfilePart::ID() const { return id_; } std::optional> AMD::PMVoltCurveProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMVoltCurveProfilePart::provideActive() const { return active(); } std::string const &AMD::PMVoltCurveProfilePart::providePMVoltCurveMode() const { return mode_; } std::pair AMD::PMVoltCurveProfilePart::providePMVoltCurvePoint(unsigned int index) const { if (index < points_.size()) return points_.at(index); else return std::make_pair(units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); } void AMD::PMVoltCurveProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &importer = dynamic_cast(i); mode(importer.providePMVoltCurveMode()); for (size_t i = 0; i < points_.size(); ++i) { auto [freq, volt] = importer.providePMVoltCurvePoint(static_cast(i)); point(static_cast(i), freq, volt); } } void AMD::PMVoltCurveProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmFVVoltCurveExporter = dynamic_cast(e); pmFVVoltCurveExporter.takePMVoltCurveMode(mode_); pmFVVoltCurveExporter.takePMVoltCurvePoints(points_); } std::unique_ptr AMD::PMVoltCurveProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->modes_ = modes_; clone->mode_ = mode_; clone->pointsRange_ = pointsRange_; clone->points_ = points_; return std::move(clone); } void AMD::PMVoltCurveProfilePart::mode(std::string const &mode) { auto iter = std::find_if( modes_.cbegin(), modes_.cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != modes_.cend()) mode_ = mode; } void AMD::PMVoltCurveProfilePart::point(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt) { if (index < points_.size()) { auto [freqRange, voltRange] = pointsRange_.at(index); auto &[pointFreq, pointVolt] = points_.at(index); pointFreq = std::clamp(freq, freqRange.first, freqRange.second); pointVolt = std::clamp(volt, voltRange.first, voltRange.second); } } bool const AMD::PMVoltCurveProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMVoltCurve::ItemID, []() { return std::make_unique(); }); pmvoltcurveprofilepart.h000066400000000000000000000045061467225065400352200ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmvoltcurve.h" #include #include #include namespace AMD { class PMVoltCurveProfilePart final : public ProfilePart , public PMVoltCurve::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &providePMVoltCurveMode() const = 0; virtual std::pair providePMVoltCurvePoint(unsigned int index) const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMVoltCurveMode(std::string const &mode) = 0; virtual void takePMVoltCurvePoints( std::vector> const &curve) = 0; }; PMVoltCurveProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::string const &providePMVoltCurveMode() const override; std::pair providePMVoltCurvePoint(unsigned int index) const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void mode(std::string const &mode); void point(unsigned int index, units::frequency::megahertz_t freq, units::voltage::millivolt_t volt); class Initializer; std::string const id_; std::string mode_; std::vector modes_; std::vector> points_; std::vector, std::pair>> pointsRange_; static bool const registered_; }; } // namespace AMD pmvoltcurveprovider.cpp000066400000000000000000000032601467225065400350520ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltcurveprovider.h" #include "../pmoverdriveprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/amd/gpuinfopmoverdrive.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmvoltcurve.h" #include #include #include #include #include std::vector> AMD::PMVoltCurveProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && gpuInfo.hasCapability(GPUInfoPMOverdrive::VoltCurve))) return {}; auto ppOdClkVolt = gpuInfo.path().sys / "pp_od_clk_voltage"; auto ppOdClkVoltLines = Utils::File::readFileLines(ppOdClkVolt); auto valid = !Utils::AMD::ppOdClkVoltageHasKnownVoltCurveQuirks(ppOdClkVoltLines) && Utils::AMD::parseOverdriveVoltCurveRange(ppOdClkVoltLines).has_value() && Utils::AMD::parseOverdriveVoltCurve(ppOdClkVoltLines).has_value(); if (!valid) { SPDLOG_WARN("Invalid data on {}", ppOdClkVolt.string()); for (auto const &line : ppOdClkVoltLines) SPDLOG_DEBUG(line); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( "vc", std::make_unique>>(ppOdClkVolt))); return controls; } bool const AMD::PMVoltCurveProvider::registered_ = AMD::PMOverdriveProvider::registerProvider( std::make_unique()); pmvoltcurveprovider.h000066400000000000000000000007521467225065400345220ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMVoltCurveProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD pmvoltcurveqmlitem.cpp000066400000000000000000000150741467225065400346760ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltcurveqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmvoltcurve.h" #include #include #include #include #include #include #include #include #include #include class AMD::PMVoltCurveQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMVoltCurve::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMVoltCurveQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMVoltCurveModes(std::vector const &modes) override; void takePMVoltCurveMode(std::string const &mode) override; void takePMVoltCurvePointsRange( std::vector, std::pair>> const &ranges) override; void takePMVoltCurvePoints( std::vector> const &points) override; private: AMD::PMVoltCurveQMLItem &outer_; }; void AMD::PMVoltCurveQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMVoltCurveQMLItem::Initializer::takePMVoltCurveModes( std::vector const &modes) { outer_.modes(modes); } void AMD::PMVoltCurveQMLItem::Initializer::takePMVoltCurveMode( std::string const &mode) { outer_.takePMVoltCurveMode(mode); } void AMD::PMVoltCurveQMLItem::Initializer::takePMVoltCurvePointsRange( std::vector, std::pair>> const &ranges) { outer_.pointsRange(ranges); } void AMD::PMVoltCurveQMLItem::Initializer::takePMVoltCurvePoints( std::vector> const &points) { outer_.takePMVoltCurvePoints(points); } AMD::PMVoltCurveQMLItem::PMVoltCurveQMLItem() noexcept { setName(tr(AMD::PMVoltCurve::ItemID.data())); } void AMD::PMVoltCurveQMLItem::changeMode(const QString &mode) { auto newMode = mode.toStdString(); if (mode_ != newMode) { mode_ = newMode; emit modeChanged(mode); emit settingsChanged(); } } void AMD::PMVoltCurveQMLItem::updatePoint(QPointF const &oldPoint, QPointF const &newPoint) { if (oldPoint != newPoint) { auto oPoint = std::make_pair( units::frequency::megahertz_t(std::round(oldPoint.x())), units::voltage::millivolt_t(std::round(oldPoint.y()))); auto nPoint = std::make_pair( units::frequency::megahertz_t(std::round(newPoint.x())), units::voltage::millivolt_t(std::round(newPoint.y()))); for (size_t i = 0; i < points_.size(); ++i) { if (points_[i] == oPoint) { points_[i] = nPoint; qPoints_.replace(static_cast(i), newPoint); emit pointsChanged(qPoints_); emit settingsChanged(); break; } } } } void AMD::PMVoltCurveQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMVoltCurveQMLItem::provideExporter(Item const &) { return {}; } std::optional> AMD::PMVoltCurveQMLItem::provideImporter(Item const &) { return {}; } void AMD::PMVoltCurveQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } bool AMD::PMVoltCurveQMLItem::provideActive() const { return active_; } void AMD::PMVoltCurveQMLItem::takePMVoltCurveMode(std::string const &mode) { if (mode_ != mode) { mode_ = mode; emit modeChanged(QString::fromStdString(mode_)); } } std::string const &AMD::PMVoltCurveQMLItem::providePMVoltCurveMode() const { return mode_; } void AMD::PMVoltCurveQMLItem::takePMVoltCurvePoints( std::vector> const &points) { if (points_ != points) { points_ = points; qPoints_.clear(); for (auto [freq, volt] : points) qPoints_.push_back(QPointF(freq.to(), volt.to())); emit pointsChanged(qPoints_); } } std::pair AMD::PMVoltCurveQMLItem::providePMVoltCurvePoint(unsigned int index) const { if (index < points_.size()) return points_.at(index); else return std::make_pair(units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); } std::unique_ptr AMD::PMVoltCurveQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::PMVoltCurveQMLItem::modes(std::vector const &) { } void AMD::PMVoltCurveQMLItem::pointsRange( std::vector, std::pair>> const &ranges) { // NOTE Assuming that all points has the same range. emit pointsRangeChanged(ranges.back().first.first.to(), ranges.back().first.second.to(), ranges.back().second.first.to(), ranges.back().second.second.to()); } bool AMD::PMVoltCurveQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMVoltCurve::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMVoltCurve::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMVoltCurveForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMVoltCurveQMLItem::registered_ = AMD::PMVoltCurveQMLItem::register_(); pmvoltcurveqmlitem.h000066400000000000000000000044541467225065400343430ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmvoltcurveprofilepart.h" #include #include #include #include #include #include #include namespace AMD { class PMVoltCurveQMLItem : public QMLItem , public AMD::PMVoltCurveProfilePart::Importer , public AMD::PMVoltCurveProfilePart::Exporter { Q_OBJECT public: explicit PMVoltCurveQMLItem() noexcept; signals: void modeChanged(QString const &mode); void pointsRangeChanged(int freqMin, int freqMax, int voltMin, int voltMax); void pointsChanged(QVariantList const &points); public slots: void changeMode(QString const &mode); void updatePoint(QPointF const &oldPoint, QPointF const &newPoint); public: void activate(bool active) override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMVoltCurveMode(std::string const &mode) override; std::string const &providePMVoltCurveMode() const override; void takePMVoltCurvePoints( std::vector> const &points) override; std::pair providePMVoltCurvePoint(unsigned int index) const override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void modes(std::vector const &modes); void pointsRange( std::vector, std::pair>> const &ranges); bool active_; std::string mode_; QVariantList qPoints_; std::vector> points_; static bool register_(); static bool const registered_; }; } // namespace AMD pmvoltcurvexmlparser.cpp000066400000000000000000000130011467225065400352270ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltcurvexmlparser.h" #include "../pmoverdrive.h" #include "core/profilepartxmlparserprovider.h" #include "pmvoltcurve.h" #include #include class AMD::PMVoltCurveXMLParser::Initializer final : public AMD::PMVoltCurveProfilePart::Exporter { public: Initializer(AMD::PMVoltCurveXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMVoltCurveMode(std::string const &mode) override; void takePMVoltCurvePoints( std::vector> const &points) override; private: AMD::PMVoltCurveXMLParser &outer_; }; void AMD::PMVoltCurveXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMVoltCurveXMLParser::Initializer::takePMVoltCurveMode( std::string const &mode) { outer_.mode_ = outer_.modeDefault_ = mode; } void AMD::PMVoltCurveXMLParser::Initializer::takePMVoltCurvePoints( std::vector> const &points) { outer_.points_ = outer_.pointsDefault_ = points; } AMD::PMVoltCurveXMLParser::PMVoltCurveXMLParser() noexcept : ProfilePartXMLParser(AMD::PMVoltCurve::ItemID, *this, *this) { } std::unique_ptr AMD::PMVoltCurveXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMVoltCurveXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMVoltCurveXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMVoltCurveXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMVoltCurveXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMVoltCurveXMLParser::provideActive() const { return active_; } void AMD::PMVoltCurveXMLParser::takePMVoltCurveMode(std::string const &mode) { mode_ = mode; } std::string const &AMD::PMVoltCurveXMLParser::providePMVoltCurveMode() const { return mode_; } void AMD::PMVoltCurveXMLParser::takePMVoltCurvePoints( std::vector> const &points) { points_ = points; } std::pair AMD::PMVoltCurveXMLParser::providePMVoltCurvePoint(unsigned int index) const { if (index < points_.size()) return points_.at(index); else return std::make_pair(units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); } void AMD::PMVoltCurveXMLParser::appendTo(pugi::xml_node &parentNode) { auto node = parentNode.append_child(ID().c_str()); node.append_attribute("active") = active_; node.append_attribute("mode") = mode_.data(); savePoints(node); } void AMD::PMVoltCurveXMLParser::resetAttributes() { active_ = activeDefault_; mode_ = modeDefault_; points_ = pointsDefault_; } void AMD::PMVoltCurveXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto legacyNode = parentNode.find_child([&](pugi::xml_node const &node) { return node.name() == AMD::PMOverdrive::LegacyFVVoltCurveItemID; }); if (!legacyNode) { auto node = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = node.attribute("active").as_bool(activeDefault_); mode_ = node.attribute("mode").as_string(modeDefault_.data()); loadPoints(node); } else { active_ = legacyNode.attribute("active").as_bool(activeDefault_); mode_ = legacyNode.attribute(LegacyModeAttribute.data()) .as_string(modeDefault_.data()); loadPointsFromLegacyNode(legacyNode); } } void AMD::PMVoltCurveXMLParser::savePoints(pugi::xml_node &node) const { for (auto [freq, volt] : points_) { auto pointNode = node.append_child(PointNodeName.data()); pointNode.append_attribute("freq") = freq.to(); pointNode.append_attribute("volt") = volt.to(); } } void AMD::PMVoltCurveXMLParser::loadPoints(pugi::xml_node &node) { if (!node) points_ = pointsDefault_; else { points_.clear(); for (auto pointNode : node.children(PointNodeName.data())) { auto freqAttr = pointNode.attribute("freq"); auto voltAttr = pointNode.attribute("volt"); if (freqAttr && voltAttr) { auto freq = freqAttr.as_uint(); auto volt = voltAttr.as_uint(); points_.emplace_back(units::frequency::megahertz_t(freq), units::voltage::millivolt_t(volt)); } else // malformed data break; } if (points_.size() != pointsDefault_.size()) points_ = pointsDefault_; } } void AMD::PMVoltCurveXMLParser::loadPointsFromLegacyNode(pugi::xml_node &node) { auto pointsNode = node.find_child([&](pugi::xml_node const &node) { return node.name() == LegacyPointsNodeName; }); loadPoints(pointsNode); } bool const AMD::PMVoltCurveXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMVoltCurve::ItemID, []() { return std::make_unique(); }); pmvoltcurvexmlparser.h000066400000000000000000000044041467225065400347030ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltcurve// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmvoltcurveprofilepart.h" #include #include #include #include namespace AMD { class PMVoltCurveXMLParser final : public ProfilePartXMLParser , public AMD::PMVoltCurveProfilePart::Exporter , public AMD::PMVoltCurveProfilePart::Importer { public: PMVoltCurveXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMVoltCurveMode(std::string const &mode) override; std::string const &providePMVoltCurveMode() const override; void takePMVoltCurvePoints( std::vector> const &points) override; std::pair providePMVoltCurvePoint(unsigned int index) const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; void savePoints(pugi::xml_node &node) const; void loadPoints(pugi::xml_node &node); void loadPointsFromLegacyNode(pugi::xml_node &node); private: static constexpr std::string_view LegacyPointsNodeName{"VOLT_CURVE"}; static constexpr std::string_view LegacyModeAttribute{"voltMode"}; static constexpr std::string_view PointNodeName{"POINT"}; class Initializer; bool active_; bool activeDefault_; std::string mode_; std::string modeDefault_; std::vector> points_; std::vector> pointsDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset/000077500000000000000000000000001467225065400304255ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffset.cpp000066400000000000000000000050121467225065400336570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltoffset.h" #include "core/components/amdutils.h" #include "core/icommandqueue.h" #include #include AMD::PMVoltOffset::PMVoltOffset( std::unique_ptr>> &&ppOdClkVoltDataSource) noexcept : Control(true) , id_(AMD::PMVoltOffset::ItemID) , ppOdClkVoltDataSource_(std::move(ppOdClkVoltDataSource)) , range_(std::make_pair(units::voltage::millivolt_t(-250), units::voltage::millivolt_t(250))) { } void AMD::PMVoltOffset::preInit(ICommandQueue &) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { preInitOffset_ = Utils::AMD::parseOverdriveVoltOffset(ppOdClkVoltLines_).value(); } } void AMD::PMVoltOffset::postInit(ICommandQueue &ctlCmds) { ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(preInitOffset_)}); } void AMD::PMVoltOffset::init() { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { value_ = Utils::AMD::parseOverdriveVoltOffset(ppOdClkVoltLines_).value(); } } std::string const &AMD::PMVoltOffset::ID() const { return id_; } void AMD::PMVoltOffset::importControl(IControl::Importer &i) { auto &importer = dynamic_cast(i); value(importer.providePMVoltOffsetValue()); } void AMD::PMVoltOffset::exportControl(IControl::Exporter &e) const { auto &exporter = dynamic_cast(e); auto [mim, max] = range(); exporter.takePMVoltOffsetRange(mim, max); exporter.takePMVoltOffsetValue(value()); } void AMD::PMVoltOffset::cleanControl(ICommandQueue &) { } void AMD::PMVoltOffset::syncControl(ICommandQueue &ctlCmds) { if (ppOdClkVoltDataSource_->read(ppOdClkVoltLines_)) { auto offset = Utils::AMD::parseOverdriveVoltOffset(ppOdClkVoltLines_).value(); if (offset != value()) { ctlCmds.add({ppOdClkVoltDataSource_->source(), ppOdClkVoltCmd(value())}); } } } std::pair const & AMD::PMVoltOffset::range() const { return range_; } units::voltage::millivolt_t AMD::PMVoltOffset::value() const { return value_; } void AMD::PMVoltOffset::value(units::voltage::millivolt_t value) { value_ = std::clamp(value, range_.first, range_.second); } std::string AMD::PMVoltOffset::ppOdClkVoltCmd(units::voltage::millivolt_t offset) const { std::string cmd; cmd.reserve(8); cmd.append("vo ").append(std::to_string(offset.to())); return cmd; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffset.h000066400000000000000000000040701467225065400333270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include namespace AMD { /// Overdrive voltage offset control. class PMVoltOffset : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_VOLT_OFFSET"}; class Importer : public IControl::Importer { public: virtual units::voltage::millivolt_t providePMVoltOffsetValue() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMVoltOffsetRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) = 0; virtual void takePMVoltOffsetValue(units::voltage::millivolt_t value) = 0; }; PMVoltOffset(std::unique_ptr>> &&ppOdClkVoltDataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) override; void syncControl(ICommandQueue &ctlCmds) override; std::pair const & range() const; units::voltage::millivolt_t value() const; void value(units::voltage::millivolt_t value); std::string ppOdClkVoltCmd(units::voltage::millivolt_t offset) const; private: std::string const id_; std::unique_ptr>> const ppOdClkVoltDataSource_; std::vector ppOdClkVoltLines_; units::voltage::millivolt_t preInitOffset_; units::voltage::millivolt_t value_; std::pair const range_; }; } // namespace AMD pmvoltoffsetprofilepart.cpp000066400000000000000000000061451467225065400360600ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltoffsetprofilepart.h" #include "core/profilepartprovider.h" #include #include class AMD::PMVoltOffsetProfilePart::Initializer final : public AMD::PMVoltOffset::Exporter { public: Initializer(AMD::PMVoltOffsetProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMVoltOffsetValue(units::voltage::millivolt_t value) override; void takePMVoltOffsetRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) override; private: AMD::PMVoltOffsetProfilePart &outer_; }; void AMD::PMVoltOffsetProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMVoltOffsetProfilePart::Initializer::takePMVoltOffsetValue( units::voltage::millivolt_t value) { outer_.value_ = value; } void AMD::PMVoltOffsetProfilePart::Initializer::takePMVoltOffsetRange( units::voltage::millivolt_t min, units::voltage::millivolt_t max) { outer_.range_ = std::make_pair(min, max); } AMD::PMVoltOffsetProfilePart::PMVoltOffsetProfilePart() noexcept : id_(AMD::PMVoltOffset::ItemID) { } std::unique_ptr AMD::PMVoltOffsetProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMVoltOffsetProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMVoltOffsetProfilePart::ID() const { return id_; } std::optional> AMD::PMVoltOffsetProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMVoltOffsetProfilePart::provideActive() const { return active(); } units::voltage::millivolt_t AMD::PMVoltOffsetProfilePart::providePMVoltOffsetValue() const { return value_; } void AMD::PMVoltOffsetProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmPowerCapProfilePartImporter = dynamic_cast(i); value(pmPowerCapProfilePartImporter.providePMVoltOffsetValue()); } void AMD::PMVoltOffsetProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmPowerCapProfilePartExporter = dynamic_cast(e); pmPowerCapProfilePartExporter.takePMVoltOffsetValue(value_); } std::unique_ptr AMD::PMVoltOffsetProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->range_ = range_; clone->value_ = value_; return std::move(clone); } void AMD::PMVoltOffsetProfilePart::value(units::voltage::millivolt_t value) { value_ = std::clamp(value, range_.first, range_.second); } bool const AMD::PMVoltOffsetProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMVoltOffset::ItemID, []() { return std::make_unique(); }); pmvoltoffsetprofilepart.h000066400000000000000000000030731467225065400355220ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmvoltoffset.h" #include #include namespace AMD { class PMVoltOffsetProfilePart final : public ProfilePart , public AMD::PMVoltOffset::Importer { public: class Importer : public IProfilePart::Importer { public: virtual units::voltage::millivolt_t providePMVoltOffsetValue() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMVoltOffsetValue(units::voltage::millivolt_t value) = 0; }; PMVoltOffsetProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; units::voltage::millivolt_t providePMVoltOffsetValue() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void value(units::voltage::millivolt_t value); class Initializer; std::string const id_; units::voltage::millivolt_t value_; std::pair range_; static bool const registered_; }; } // namespace AMD pmvoltoffsetprovider.cpp000066400000000000000000000027451467225065400353650ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltoffsetprovider.h" #include "../pmoverdriveprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/amd/gpuinfopmoverdrive.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmvoltoffset.h" #include #include #include #include #include std::vector> AMD::PMVoltOffsetProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (!(gpuInfo.vendor() == Vendor::AMD && gpuInfo.hasCapability(GPUInfoPMOverdrive::VoltOffset))) return {}; auto ppOdClkVolt = gpuInfo.path().sys / "pp_od_clk_voltage"; auto ppOdClkVoltLines = Utils::File::readFileLines(ppOdClkVolt); if (!Utils::AMD::parseOverdriveVoltOffset(ppOdClkVoltLines)) { SPDLOG_WARN("Invalid data on {}", ppOdClkVolt.string()); for (auto const &line : ppOdClkVoltLines) SPDLOG_DEBUG(line); return {}; } std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>>(ppOdClkVolt))); return controls; } bool const AMD::PMVoltOffsetProvider::registered_ = AMD::PMOverdriveProvider::registerProvider( std::make_unique()); pmvoltoffsetprovider.h000066400000000000000000000007531467225065400350270ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMVoltOffsetProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD pmvoltoffsetqmlitem.cpp000066400000000000000000000074141467225065400352010ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltoffsetqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmvoltoffset.h" #include #include #include #include #include class AMD::PMVoltOffsetQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMVoltOffset::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMVoltOffsetQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMVoltOffsetValue(units::voltage::millivolt_t value) override; void takePMVoltOffsetRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max) override; private: AMD::PMVoltOffsetQMLItem &outer_; }; void AMD::PMVoltOffsetQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMVoltOffsetQMLItem::Initializer::takePMVoltOffsetValue( units::voltage::millivolt_t value) { outer_.takePMVoltOffsetValue(value); } void AMD::PMVoltOffsetQMLItem::Initializer::takePMVoltOffsetRange( units::voltage::millivolt_t min, units::voltage::millivolt_t max) { outer_.takePMVoltOffsetRange(min, max); } AMD::PMVoltOffsetQMLItem::PMVoltOffsetQMLItem() noexcept { setName(tr(AMD::PMVoltOffset::ItemID.data())); } void AMD::PMVoltOffsetQMLItem::changeValue(int value) { if (value_ != value) { value_ = value; emit valueChanged(value_); emit settingsChanged(); } } void AMD::PMVoltOffsetQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMVoltOffsetQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMVoltOffsetQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMVoltOffsetQMLItem::provideActive() const { return active_; } units::voltage::millivolt_t AMD::PMVoltOffsetQMLItem::providePMVoltOffsetValue() const { return units::voltage::millivolt_t(value_); } void AMD::PMVoltOffsetQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::PMVoltOffsetQMLItem::takePMVoltOffsetValue( units::voltage::millivolt_t value) { auto newValue = value.to(); if (value_ != newValue) { value_ = newValue; emit valueChanged(value_); } } std::unique_ptr AMD::PMVoltOffsetQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::PMVoltOffsetQMLItem::takePMVoltOffsetRange( units::voltage::millivolt_t min, units::voltage::millivolt_t max) { emit rangeChanged(min.to(), max.to()); } bool AMD::PMVoltOffsetQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMVoltOffset::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMVoltOffset::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMVoltOffsetForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMVoltOffsetQMLItem::registered_ = AMD::PMVoltOffsetQMLItem::register_(); pmvoltoffsetqmlitem.h000066400000000000000000000027251467225065400346460ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmvoltoffsetprofilepart.h" #include #include namespace AMD { class PMVoltOffsetQMLItem : public QMLItem , public AMD::PMVoltOffsetProfilePart::Importer , public AMD::PMVoltOffsetProfilePart::Exporter { Q_OBJECT public: explicit PMVoltOffsetQMLItem() noexcept; signals: void valueChanged(int value); void rangeChanged(int min, int max); public slots: void changeValue(int value); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; units::voltage::millivolt_t providePMVoltOffsetValue() const override; void takeActive(bool active) override; void takePMVoltOffsetValue(units::voltage::millivolt_t value) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: void takePMVoltOffsetRange(units::voltage::millivolt_t min, units::voltage::millivolt_t max); class Initializer; bool active_; int value_; static bool register_(); static bool const registered_; }; } // namespace AMD pmvoltoffsetxmlparser.cpp000066400000000000000000000057511467225065400355500ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmvoltoffsetxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmvoltoffset.h" #include class AMD::PMVoltOffsetXMLParser::Initializer final : public AMD::PMVoltOffsetProfilePart::Exporter { public: Initializer(AMD::PMVoltOffsetXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMVoltOffsetValue(units::voltage::millivolt_t value) override; private: AMD::PMVoltOffsetXMLParser &outer_; }; void AMD::PMVoltOffsetXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMVoltOffsetXMLParser::Initializer::takePMVoltOffsetValue( units::voltage::millivolt_t value) { outer_.value_ = outer_.valueDefault_ = value; } AMD::PMVoltOffsetXMLParser::PMVoltOffsetXMLParser() noexcept : ProfilePartXMLParser(AMD::PMVoltOffset::ItemID, *this, *this) { } std::unique_ptr AMD::PMVoltOffsetXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMVoltOffsetXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMVoltOffsetXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMVoltOffsetXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMVoltOffsetXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMVoltOffsetXMLParser::provideActive() const { return active_; } void AMD::PMVoltOffsetXMLParser::takePMVoltOffsetValue( units::voltage::millivolt_t value) { value_ = value; } units::voltage::millivolt_t AMD::PMVoltOffsetXMLParser::providePMVoltOffsetValue() const { return value_; } void AMD::PMVoltOffsetXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; pmFixedNode.append_attribute("value") = value_.to(); } void AMD::PMVoltOffsetXMLParser::resetAttributes() { active_ = activeDefault_; value_ = valueDefault_; } void AMD::PMVoltOffsetXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); value_ = units::voltage::millivolt_t( pmFixedNode.attribute("value").as_int(valueDefault_.to())); } bool const AMD::PMVoltOffsetXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMVoltOffset::ItemID, []() { return std::make_unique(); }); pmvoltoffsetxmlparser.h000066400000000000000000000026521467225065400352120ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/overdrive/voltoffset// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmvoltoffsetprofilepart.h" #include namespace AMD { class PMVoltOffsetXMLParser final : public ProfilePartXMLParser , public AMD::PMVoltOffsetProfilePart::Exporter , public AMD::PMVoltOffsetProfilePart::Importer { public: PMVoltOffsetXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMVoltOffsetValue(units::voltage::millivolt_t value) override; units::voltage::millivolt_t providePMVoltOffsetValue() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; units::voltage::millivolt_t value_; units::voltage::millivolt_t valueDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvanced.h000066400000000000000000000010501467225065400264740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroup.h" #include #include #include #include namespace AMD { class PMAdvanced : public ControlGroup { public: static constexpr std::string_view ItemID{"AMD_PM_ADVANCED"}; PMAdvanced(std::vector> &&controls) noexcept : ControlGroup(AMD::PMAdvanced::ItemID, std::move(controls), false) { } }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedprofilepart.cpp000066400000000000000000000012511467225065400313020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmadvancedprofilepart.h" #include "core/profilepartprovider.h" #include "pmadvanced.h" #include AMD::PMAdvancedProfilePart::PMAdvancedProfilePart() noexcept : ControlGroupProfilePart(AMD::PMAdvanced::ItemID) { } std::unique_ptr AMD::PMAdvancedProfilePart::instance() const { return std::make_unique(); } bool const AMD::PMAdvancedProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMAdvanced::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedprofilepart.h000066400000000000000000000007151467225065400307530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroupprofilepart.h" namespace AMD { class PMAdvancedProfilePart final : public ControlGroupProfilePart { public: PMAdvancedProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedprovider.cpp000066400000000000000000000031121467225065400306030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmadvancedprovider.h" #include "../pmperfmodeprovider.h" #include "core/info/igpuinfo.h" #include "pmadvanced.h" #include #include std::vector> AMD::PMAdvancedProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::vector> groupControls; for (auto const &provider : providers_()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); groupControls.insert(groupControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (groupControls.empty()) return {}; std::vector> controls; controls.emplace_back(std::make_unique(std::move(groupControls))); return controls; } bool AMD::PMAdvancedProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::PMAdvancedProvider::providers_() { static std::vector> providers; return providers; } bool const AMD::PMAdvancedProvider::registered_ = AMD::PMPerfModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedprovider.h000066400000000000000000000013051467225065400302520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class PMAdvancedProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedqmlitem.cpp000066400000000000000000000022741467225065400304310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmadvancedqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmadvanced.h" #include #include #include #include #include #include char const *const AMD::PMAdvancedQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_PM_ADVANCED"), }; AMD::PMAdvancedQMLItem::PMAdvancedQMLItem() noexcept : ControlGroupQMLItem(AMD::PMAdvanced::ItemID) { } bool AMD::PMAdvancedQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMAdvanced::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMAdvanced::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMAdvancedForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMAdvancedQMLItem::registered_ = AMD::PMAdvancedQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedqmlitem.h000066400000000000000000000006611467225065400300740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroupqmlitem.h" namespace AMD { class PMAdvancedQMLItem : public ControlGroupQMLItem { public: explicit PMAdvancedQMLItem() noexcept; private: static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedxmlparser.cpp000066400000000000000000000010331467225065400307660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmadvancedxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmadvanced.h" #include AMD::PMAdvancedXMLParser::PMAdvancedXMLParser() noexcept : ControlGroupXMLParser(AMD::PMAdvanced::ItemID) { } bool const AMD::PMAdvancedXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMAdvanced::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/pmadvancedxmlparser.h000066400000000000000000000005621467225065400304410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlgroupxmlparser.h" namespace AMD { class PMAdvancedXMLParser final : public ControlGroupXMLParser { public: PMAdvancedXMLParser() noexcept; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/000077500000000000000000000000001467225065400260455ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercap.cpp000066400000000000000000000052771467225065400307410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowercap.h" #include "core/icommandqueue.h" #include #include AMD::PMPowerCap::PMPowerCap( std::unique_ptr> &&powerCapDataSource, units::power::watt_t min, units::power::watt_t max, std::optional defaultValue) noexcept : Control(true) , id_(AMD::PMPowerCap::ItemID) , powerCapDataSource_(std::move(powerCapDataSource)) , powerCapPreInitValue_{0u} , min_(min) , max_(max) , defaultValue_(defaultValue) , value_(defaultValue ? *defaultValue : units::power::watt_t(1)) { if (min_ == units::power::watt_t(0)) min_ = units::power::watt_t(1); } void AMD::PMPowerCap::preInit(ICommandQueue &ctlCmds) { if (defaultValue_) return; powerCapDataSource_->read(powerCapPreInitValue_); cleanControl(ctlCmds); } void AMD::PMPowerCap::postInit(ICommandQueue &ctlCmds) { if (defaultValue_) return; ctlCmds.add( {powerCapDataSource_->source(), std::to_string(powerCapPreInitValue_)}); } void AMD::PMPowerCap::init() { if (defaultValue_) return; unsigned long powerCapValue; if (powerCapDataSource_->read(powerCapValue)) value(units::power::microwatt_t(powerCapValue)); } std::string const &AMD::PMPowerCap::ID() const { return id_; } void AMD::PMPowerCap::importControl(IControl::Importer &i) { auto &pmPowerCapImporter = dynamic_cast(i); value(pmPowerCapImporter.providePMPowerCapValue()); } void AMD::PMPowerCap::exportControl(IControl::Exporter &e) const { auto &pmPowerCapExporter = dynamic_cast(e); pmPowerCapExporter.takePMPowerCapRange(min(), max()); pmPowerCapExporter.takePMPowerCapValue(value()); } void AMD::PMPowerCap::cleanControl(ICommandQueue &ctlCmds) { auto value = defaultValue_ ? std::to_string((*defaultValue_).to()) : "0"; // restore default value ctlCmds.add({powerCapDataSource_->source(), value}); } void AMD::PMPowerCap::syncControl(ICommandQueue &ctlCmds) { unsigned long powerCapValue; if (powerCapDataSource_->read(powerCapValue)) { if (units::power::microwatt_t(powerCapValue) != value()) ctlCmds.add({powerCapDataSource_->source(), std::to_string(value().to())}); } } units::power::microwatt_t AMD::PMPowerCap::value() const { return value_; } void AMD::PMPowerCap::value(units::power::microwatt_t value) { value_ = std::clamp(value, min(), max()); } units::power::microwatt_t AMD::PMPowerCap::min() const { return min_; } units::power::microwatt_t AMD::PMPowerCap::max() const { return max_; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercap.h000066400000000000000000000037351467225065400304030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include namespace AMD { class PMPowerCap : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_POWERCAP"}; class Importer : public IControl::Importer { public: virtual units::power::watt_t providePMPowerCapValue() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMPowerCapValue(units::power::watt_t value) = 0; virtual void takePMPowerCapRange(units::power::watt_t min, units::power::watt_t max) = 0; }; PMPowerCap(std::unique_ptr> &&powerCapDataSource, units::power::watt_t min, units::power::watt_t max, std::optional defaultValue = {}) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; units::power::microwatt_t value() const; void value(units::power::microwatt_t value); units::power::microwatt_t min() const; units::power::microwatt_t max() const; private: std::string const id_; std::unique_ptr> const powerCapDataSource_; unsigned long powerCapPreInitValue_; units::power::microwatt_t min_; units::power::microwatt_t const max_; std::optional const defaultValue_; units::power::microwatt_t value_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapprofilepart.cpp000066400000000000000000000057451467225065400332110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowercapprofilepart.h" #include "core/profilepartprovider.h" #include #include class AMD::PMPowerCapProfilePart::Initializer final : public AMD::PMPowerCap::Exporter { public: Initializer(AMD::PMPowerCapProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerCapValue(units::power::watt_t value) override; void takePMPowerCapRange(units::power::watt_t min, units::power::watt_t max) override; private: AMD::PMPowerCapProfilePart &outer_; }; void AMD::PMPowerCapProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMPowerCapProfilePart::Initializer::takePMPowerCapValue( units::power::watt_t value) { outer_.value_ = value; } void AMD::PMPowerCapProfilePart::Initializer::takePMPowerCapRange( units::power::watt_t min, units::power::watt_t max) { outer_.range_ = std::make_pair(min, max); } AMD::PMPowerCapProfilePart::PMPowerCapProfilePart() noexcept : id_(AMD::PMPowerCap::ItemID) { } std::unique_ptr AMD::PMPowerCapProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMPowerCapProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMPowerCapProfilePart::ID() const { return id_; } std::optional> AMD::PMPowerCapProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMPowerCapProfilePart::provideActive() const { return active(); } units::power::watt_t AMD::PMPowerCapProfilePart::providePMPowerCapValue() const { return value_; } void AMD::PMPowerCapProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmPowerCapProfilePartImporter = dynamic_cast(i); value(pmPowerCapProfilePartImporter.providePMPowerCapValue()); } void AMD::PMPowerCapProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmPowerCapProfilePartExporter = dynamic_cast(e); pmPowerCapProfilePartExporter.takePMPowerCapValue(value_); } std::unique_ptr AMD::PMPowerCapProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->range_ = range_; clone->value_ = value_; return std::move(clone); } void AMD::PMPowerCapProfilePart::value(units::power::watt_t value) { value_ = std::clamp(value, range_.first, range_.second); } bool const AMD::PMPowerCapProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMPowerCap::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapprofilepart.h000066400000000000000000000027741467225065400326550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmpowercap.h" #include #include namespace AMD { class PMPowerCapProfilePart final : public ProfilePart , public AMD::PMPowerCap::Importer { public: class Importer : public IProfilePart::Importer { public: virtual units::power::watt_t providePMPowerCapValue() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMPowerCapValue(units::power::watt_t value) = 0; }; PMPowerCapProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; units::power::watt_t providePMPowerCapValue() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void value(units::power::watt_t value); class Initializer; std::string const id_; units::power::watt_t value_; std::pair range_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapprovider.cpp000066400000000000000000000046551467225065400325130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowercapprovider.h" #include "../pmadvancedprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmpowercap.h" #include #include #include #include #include std::optional AMD::PMPowerCapProvider::readPowerFrom(std::filesystem::path const &path) const { if (!Utils::File::isSysFSEntryValid(path)) return {}; unsigned long value; auto lines = Utils::File::readFileLines(path); if (!Utils::String::toNumber(value, lines.front())) { SPDLOG_WARN("Unknown data format on {}", path.string()); SPDLOG_DEBUG(lines.front()); return {}; } return units::power::microwatt_t(value); } std::vector> AMD::PMPowerCapProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; auto power1CapPath = path.value() / "power1_cap"; auto value = readPowerFrom(power1CapPath); auto min = readPowerFrom(path.value() / "power1_cap_min"); auto max = readPowerFrom(path.value() / "power1_cap_max"); if (!(value && min && max)) return {}; // Drivers might report bogus values for either (or both) upper // and lower range bounds. See #337. if (*max <= *min) { SPDLOG_DEBUG("Bogus power cap range bounds detected: " "power1_cap_min ({}), power1_cap_max ({}).", (*min).to(), (*max).to()); return {}; } auto defaultValue = readPowerFrom(path.value() / "power1_cap_default"); std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>( power1CapPath, [](std::string const &data, unsigned long &output) { Utils::String::toNumber(output, data); }), *min, *max, defaultValue)); return controls; } bool const AMD::PMPowerCapProvider::registered_ = AMD::PMAdvancedProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapprovider.h000066400000000000000000000012141467225065400321440ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include #include namespace AMD { class PMPowerCapProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: std::optional readPowerFrom(std::filesystem::path const &path) const; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapqmlitem.cpp000066400000000000000000000072241467225065400323240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowercapqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmpowercap.h" #include #include #include #include #include class AMD::PMPowerCapQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMPowerCap::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMPowerCapQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerCapValue(units::power::watt_t value) override; void takePMPowerCapRange(units::power::watt_t min, units::power::watt_t max) override; private: AMD::PMPowerCapQMLItem &outer_; }; void AMD::PMPowerCapQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMPowerCapQMLItem::Initializer::takePMPowerCapValue( units::power::watt_t value) { outer_.takePMPowerCapValue(value); } void AMD::PMPowerCapQMLItem::Initializer::takePMPowerCapRange( units::power::watt_t min, units::power::watt_t max) { outer_.takePMPowerCapRange(min, max); } AMD::PMPowerCapQMLItem::PMPowerCapQMLItem() noexcept { setName(tr(AMD::PMPowerCap::ItemID.data())); } void AMD::PMPowerCapQMLItem::changeValue(int value) { if (value_ != value) { value_ = value; emit valueChanged(value_); emit settingsChanged(); } } void AMD::PMPowerCapQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMPowerCapQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMPowerCapQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMPowerCapQMLItem::provideActive() const { return active_; } units::power::watt_t AMD::PMPowerCapQMLItem::providePMPowerCapValue() const { return units::power::watt_t(value_); } void AMD::PMPowerCapQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::PMPowerCapQMLItem::takePMPowerCapValue(units::power::watt_t value) { auto newValue = value.to(); if (value_ != newValue) { value_ = newValue; emit valueChanged(value_); } } std::unique_ptr AMD::PMPowerCapQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::PMPowerCapQMLItem::takePMPowerCapRange(units::power::watt_t min, units::power::watt_t max) { emit rangeChanged(min.to(), max.to()); } bool AMD::PMPowerCapQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMPowerCap::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMPowerCap::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMPowerCapForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMPowerCapQMLItem::registered_ = AMD::PMPowerCapQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapqmlitem.h000066400000000000000000000026141467225065400317670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmpowercapprofilepart.h" #include #include namespace AMD { class PMPowerCapQMLItem : public QMLItem , public AMD::PMPowerCapProfilePart::Importer , public AMD::PMPowerCapProfilePart::Exporter { Q_OBJECT public: explicit PMPowerCapQMLItem() noexcept; signals: void valueChanged(int value); void rangeChanged(int min, int max); public slots: void changeValue(int value); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; units::power::watt_t providePMPowerCapValue() const override; void takeActive(bool active) override; void takePMPowerCapValue(units::power::watt_t value) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: void takePMPowerCapRange(units::power::watt_t min, units::power::watt_t max); class Initializer; bool active_; int value_; static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapxmlparser.cpp000066400000000000000000000056211467225065400326700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowercapxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmpowercap.h" #include class AMD::PMPowerCapXMLParser::Initializer final : public AMD::PMPowerCapProfilePart::Exporter { public: Initializer(AMD::PMPowerCapXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerCapValue(units::power::watt_t value) override; private: AMD::PMPowerCapXMLParser &outer_; }; void AMD::PMPowerCapXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMPowerCapXMLParser::Initializer::takePMPowerCapValue( units::power::watt_t value) { outer_.value_ = outer_.valueDefault_ = value; } AMD::PMPowerCapXMLParser::PMPowerCapXMLParser() noexcept : ProfilePartXMLParser(AMD::PMPowerCap::ItemID, *this, *this) { } std::unique_ptr AMD::PMPowerCapXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMPowerCapXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMPowerCapXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMPowerCapXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMPowerCapXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMPowerCapXMLParser::provideActive() const { return active_; } void AMD::PMPowerCapXMLParser::takePMPowerCapValue(units::power::watt_t value) { value_ = value; } units::power::watt_t AMD::PMPowerCapXMLParser::providePMPowerCapValue() const { return value_; } void AMD::PMPowerCapXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; pmFixedNode.append_attribute("value") = value_.to(); } void AMD::PMPowerCapXMLParser::resetAttributes() { active_ = activeDefault_; value_ = valueDefault_; } void AMD::PMPowerCapXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); value_ = units::power::watt_t( pmFixedNode.attribute("value").as_uint(valueDefault_.to())); } bool const AMD::PMPowerCapXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMPowerCap::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powercap/pmpowercapxmlparser.h000066400000000000000000000026001467225065400323270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmpowercapprofilepart.h" #include namespace AMD { class PMPowerCapXMLParser final : public ProfilePartXMLParser , public AMD::PMPowerCapProfilePart::Exporter , public AMD::PMPowerCapProfilePart::Importer { public: PMPowerCapXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMPowerCapValue(units::power::watt_t value) override; units::power::watt_t providePMPowerCapValue() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; units::power::watt_t value_; units::power::watt_t valueDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/000077500000000000000000000000001467225065400267425ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofile.cpp000066400000000000000000000053371467225065400325300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerprofile.h" #include "core/icommandqueue.h" AMD::PMPowerProfile::PMPowerProfile( std::unique_ptr> &&perfLevelDataSource, std::unique_ptr>> &&powerProfileDataSource, std::vector> const &modes) noexcept : Control(true) , id_(AMD::PMPowerProfile::ItemID) , perfLevelDataSource_(std::move(perfLevelDataSource)) , powerProfileDataSource_(std::move(powerProfileDataSource)) { for (auto &[mode, index] : modes) { modes_.push_back(mode); indexMode_.emplace(index, mode); } mode(modes_.front()); defaultModeIndex_ = currentModeIndex_; } void AMD::PMPowerProfile::preInit(ICommandQueue &) { } void AMD::PMPowerProfile::postInit(ICommandQueue &) { } void AMD::PMPowerProfile::init() { } std::string const &AMD::PMPowerProfile::ID() const { return id_; } void AMD::PMPowerProfile::importControl(IControl::Importer &i) { auto &pmPowerProfileImporter = dynamic_cast(i); mode(pmPowerProfileImporter.providePMPowerProfileMode()); } void AMD::PMPowerProfile::exportControl(IControl::Exporter &e) const { auto &pmPowerProfileExporter = dynamic_cast(e); pmPowerProfileExporter.takePMPowerProfileModes(modes()); pmPowerProfileExporter.takePMPowerProfileMode(mode()); } void AMD::PMPowerProfile::cleanControl(ICommandQueue &ctlCmds) { if (perfLevelDataSource_->read(dataSourceEntry_) && dataSourceEntry_ != "manual") ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.add( {powerProfileDataSource_->source(), std::to_string(defaultModeIndex_)}); } void AMD::PMPowerProfile::syncControl(ICommandQueue &ctlCmds) { std::optional modeIndex; if (perfLevelDataSource_->read(dataSourceEntry_) && powerProfileDataSource_->read(modeIndex)) { if (dataSourceEntry_ != "manual") { ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.add({powerProfileDataSource_->source(), std::to_string(currentModeIndex_)}); } else { if (modeIndex.has_value() && currentModeIndex_ != modeIndex) ctlCmds.add({powerProfileDataSource_->source(), std::to_string(currentModeIndex_)}); } } } void AMD::PMPowerProfile::mode(std::string const &mode) { for (auto const &kv : indexMode_) { if (kv.second == mode) { currentModeIndex_ = kv.first; break; } } } std::string const &AMD::PMPowerProfile::mode() const { return indexMode_.at(currentModeIndex_); } std::vector const &AMD::PMPowerProfile::modes() const { return modes_; } corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofile.h000066400000000000000000000037551467225065400321770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include #include #include #include namespace AMD { class PMPowerProfile : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_POWER_PROFILE"}; class Importer : public IControl::Importer { public: virtual std::string const &providePMPowerProfileMode() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMPowerProfileMode(std::string const &mode) = 0; virtual void takePMPowerProfileModes(std::vector const &modes) = 0; }; PMPowerProfile( std::unique_ptr> &&perfLevelDataSource, std::unique_ptr>> &&powerProfileDataSource, std::vector> const &modes) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; void mode(std::string const &mode); std::string const &mode() const; std::vector const &modes() const; private: std::string const id_; std::unique_ptr> const perfLevelDataSource_; std::unique_ptr>> const powerProfileDataSource_; int currentModeIndex_; int defaultModeIndex_; std::vector modes_; std::unordered_map indexMode_; std::string dataSourceEntry_; }; } // namespace AMD pmpowerprofileprofilepart.cpp000066400000000000000000000062021467225065400347110ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerprofileprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class AMD::PMPowerProfileProfilePart::Initializer final : public PMPowerProfile::Exporter { public: Initializer(AMD::PMPowerProfileProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerProfileMode(std::string const &mode) override; void takePMPowerProfileModes(std::vector const &modes) override; private: AMD::PMPowerProfileProfilePart &outer_; }; void AMD::PMPowerProfileProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMPowerProfileProfilePart::Initializer::takePMPowerProfileMode( std::string const &mode) { outer_.mode_ = mode; } void AMD::PMPowerProfileProfilePart::Initializer::takePMPowerProfileModes( std::vector const &modes) { outer_.modes_ = modes; } AMD::PMPowerProfileProfilePart::PMPowerProfileProfilePart() noexcept : id_(AMD::PMPowerProfile::ItemID) { } std::unique_ptr AMD::PMPowerProfileProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMPowerProfileProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMPowerProfileProfilePart::ID() const { return id_; } std::optional> AMD::PMPowerProfileProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMPowerProfileProfilePart::provideActive() const { return active(); } std::string const &AMD::PMPowerProfileProfilePart::providePMPowerProfileMode() const { return mode_; } void AMD::PMPowerProfileProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmPowerProfileImporter = dynamic_cast(i); mode(pmPowerProfileImporter.providePMPowerProfileMode()); } void AMD::PMPowerProfileProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmPowerProfileExporter = dynamic_cast(e); pmPowerProfileExporter.takePMPowerProfileMode(mode_); } std::unique_ptr AMD::PMPowerProfileProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->modes_ = modes_; clone->mode_ = mode_; return std::move(clone); } void AMD::PMPowerProfileProfilePart::mode(std::string const &mode) { auto iter = std::find_if( modes_.cbegin(), modes_.cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != modes_.cend()) mode_ = mode; } bool const AMD::PMPowerProfileProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMPowerProfile::ItemID, []() { return std::make_unique(); }); pmpowerprofileprofilepart.h000066400000000000000000000027341467225065400343640ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmpowerprofile.h" #include #include namespace AMD { class PMPowerProfileProfilePart final : public ProfilePart , public PMPowerProfile::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &providePMPowerProfileMode() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMPowerProfileMode(std::string const &mode) = 0; }; PMPowerProfileProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::string const &providePMPowerProfileMode() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void mode(std::string const &mode); class Initializer; std::string const id_; std::string mode_; std::vector modes_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileprovider.cpp000066400000000000000000000045711467225065400343020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerprofileprovider.h" #include "../pmadvancedprovider.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmpowerprofile.h" #include #include #include #include #include #include std::vector> AMD::PMPowerProfileProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver != "amdgpu") return {}; auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; auto profileMode = gpuInfo.path().sys / "pp_power_profile_mode"; if (!(Utils::File::isSysFSEntryValid(perfLevel) && Utils::File::isSysFSEntryValid(profileMode))) return {}; auto modeLines = Utils::File::readFileLines(profileMode); auto columnarData = Utils::AMD::isPowerProfileModeDataColumnar(modeLines); auto modes = columnarData ? Utils::AMD::parsePowerProfileModeModesColumnar(modeLines) : Utils::AMD::parsePowerProfileModeModes(modeLines); if (!modes) { SPDLOG_WARN("Unknown data format on {}", profileMode.string()); for (auto const &line : modeLines) SPDLOG_DEBUG(line); return {}; } auto indexFn = columnarData ? [](std::vector const &data, std::optional &output) { output = Utils::AMD::parsePowerProfileModeCurrentModeIndexColumnar(data); } : [](std::vector const &data, std::optional &output) { output = Utils::AMD::parsePowerProfileModeCurrentModeIndex(data); }; std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>(perfLevel), std::make_unique, std::vector>>( profileMode, std::move(indexFn)), *modes)); return controls; } bool const AMD::PMPowerProfileProvider::registered_ = AMD::PMAdvancedProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileprovider.h000066400000000000000000000007551467225065400337470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMPowerProfileProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileqmlitem.cpp000066400000000000000000000102741467225065400341150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerprofileqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmpowerprofile.h" #include #include #include #include #include #include char const *const AMD::PMPowerProfileQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("AMD::PMPowerProfileQMLItem", "3D_FULL_SCREEN"), QT_TRANSLATE_NOOP("AMD::PMPowerProfileQMLItem", "POWER_SAVING"), QT_TRANSLATE_NOOP("AMD::PMPowerProfileQMLItem", "VIDEO"), QT_TRANSLATE_NOOP("AMD::PMPowerProfileQMLItem", "VR"), QT_TRANSLATE_NOOP("AMD::PMPowerProfileQMLItem", "COMPUTE"), }; class AMD::PMPowerProfileQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMPowerProfile::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMPowerProfileQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerProfileMode(std::string const &mode) override; void takePMPowerProfileModes(std::vector const &modes) override; private: AMD::PMPowerProfileQMLItem &outer_; }; void AMD::PMPowerProfileQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMPowerProfileQMLItem::Initializer::takePMPowerProfileMode( std::string const &mode) { outer_.takePMPowerProfileMode(mode); } void AMD::PMPowerProfileQMLItem::Initializer::takePMPowerProfileModes( std::vector const &modes) { outer_.takePMPowerProfileModes(modes); } AMD::PMPowerProfileQMLItem::PMPowerProfileQMLItem() noexcept { setName(tr(AMD::PMPowerProfile::ItemID.data())); } void AMD::PMPowerProfileQMLItem::changeMode(QString const &mode) { auto newMode = mode.toStdString(); if (mode_ != newMode) { std::swap(mode_, newMode); emit modeChanged(mode); emit settingsChanged(); } } void AMD::PMPowerProfileQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMPowerProfileQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMPowerProfileQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMPowerProfileQMLItem::provideActive() const { return active_; } void AMD::PMPowerProfileQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } std::string const &AMD::PMPowerProfileQMLItem::providePMPowerProfileMode() const { return mode_; } void AMD::PMPowerProfileQMLItem::takePMPowerProfileMode(std::string const &mode) { if (mode_ != mode) { mode_ = mode; emit modeChanged(QString::fromStdString(mode)); } } void AMD::PMPowerProfileQMLItem::takePMPowerProfileModes( std::vector const &modes) { QList modeText; for (auto const &mode : modes) { modeText.push_back(QString::fromStdString(mode)); modeText.push_back(tr(mode.data())); } emit modesChanged(modeText); } std::unique_ptr AMD::PMPowerProfileQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } bool AMD::PMPowerProfileQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType( "CoreCtrl.UIComponents", 1, 0, AMD::PMPowerProfile::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMPowerProfile::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMPowerProfileForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMPowerProfileQMLItem::registered_ = AMD::PMPowerProfileQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofileqmlitem.h000066400000000000000000000030331467225065400335550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmpowerprofileprofilepart.h" #include #include #include #include #include namespace AMD { class PMPowerProfileQMLItem : public QMLItem , public AMD::PMPowerProfileProfilePart::Importer , public AMD::PMPowerProfileProfilePart::Exporter { Q_OBJECT public: explicit PMPowerProfileQMLItem() noexcept; signals: void modeChanged(QString const &mode); void modesChanged(QList const &modes); public slots: void changeMode(QString const &mode); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::string const &providePMPowerProfileMode() const override; void takePMPowerProfileMode(std::string const &mode) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void takePMPowerProfileModes(std::vector const &modes); bool active_; std::string mode_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD pmpowerprofilexmlparser.cpp000066400000000000000000000057331467225065400344070ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerprofilexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmpowerprofile.h" #include class AMD::PMPowerProfileXMLParser::Initializer final : public AMD::PMPowerProfileProfilePart::Exporter { public: Initializer(AMD::PMPowerProfileXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerProfileMode(std::string const &mode) override; private: AMD::PMPowerProfileXMLParser &outer_; }; void AMD::PMPowerProfileXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMPowerProfileXMLParser::Initializer::takePMPowerProfileMode( std::string const &mode) { outer_.mode_ = outer_.modeDefault_ = mode; } AMD::PMPowerProfileXMLParser::PMPowerProfileXMLParser() noexcept : ProfilePartXMLParser(AMD::PMPowerProfile::ItemID, *this, *this) { } std::unique_ptr AMD::PMPowerProfileXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMPowerProfileXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMPowerProfileXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMPowerProfileXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMPowerProfileXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMPowerProfileXMLParser::provideActive() const { return active_; } void AMD::PMPowerProfileXMLParser::takePMPowerProfileMode(std::string const &mode) { mode_ = mode; } std::string const &AMD::PMPowerProfileXMLParser::providePMPowerProfileMode() const { return mode_; } void AMD::PMPowerProfileXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFrequencyNode = parentNode.append_child(ID().c_str()); pmFrequencyNode.append_attribute("active") = active_; pmFrequencyNode.append_attribute("mode") = mode_.c_str(); } void AMD::PMPowerProfileXMLParser::resetAttributes() { active_ = activeDefault_; mode_ = modeDefault_; } void AMD::PMPowerProfileXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFrequencyNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFrequencyNode.attribute("active").as_bool(activeDefault_); mode_ = pmFrequencyNode.attribute("mode").as_string(modeDefault_.c_str()); } bool const AMD::PMPowerProfileXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMPowerProfile::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofilexmlparser.h000066400000000000000000000026011467225065400341220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmpowerprofileprofilepart.h" #include namespace AMD { class PMPowerProfileXMLParser final : public ProfilePartXMLParser , public AMD::PMPowerProfileProfilePart::Exporter , public AMD::PMPowerProfileProfilePart::Importer { public: PMPowerProfileXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMPowerProfileMode(std::string const &mode) override; std::string const &providePMPowerProfileMode() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; std::string mode_; std::string modeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/000077500000000000000000000000001467225065400234305ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmauto.cpp000066400000000000000000000010031467225065400254330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmauto.h" AMD::PMAuto::PMAuto() noexcept : Control(true) , id_(AMD::PMAuto::ItemID) { } void AMD::PMAuto::preInit(ICommandQueue &) { } void AMD::PMAuto::postInit(ICommandQueue &) { } void AMD::PMAuto::init() { } std::string const &AMD::PMAuto::ID() const { return id_; } void AMD::PMAuto::importControl(IControl::Importer &) { } void AMD::PMAuto::exportControl(IControl::Exporter &) const { } corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmauto.h000066400000000000000000000013351467225065400251100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include #include namespace AMD { class PMAuto : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_AUTO"}; PMAuto() noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; private: std::string const id_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautolegacy.cpp000066400000000000000000000021011467225065400266200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmautolegacy.h" #include "core/icommandqueue.h" #include AMD::PMAutoLegacy::PMAutoLegacy( std::unique_ptr> &&powerMethodDataSource, std::unique_ptr> &&powerProfileDataSource) noexcept : powerMethodDataSource_(std::move(powerMethodDataSource)) , powerProfileDataSource_(std::move(powerProfileDataSource)) { } void AMD::PMAutoLegacy::cleanControl(ICommandQueue &) { } void AMD::PMAutoLegacy::syncControl(ICommandQueue &ctlCmds) { if (powerMethodDataSource_->read(powerMethodEntry_) && powerProfileDataSource_->read(powerProfileEntry_)) { if (powerMethodEntry_ != AMD::PMAutoLegacy::Method || powerProfileEntry_ != AMD::PMAutoLegacy::Profile) { ctlCmds.add({powerMethodDataSource_->source(), std::string(AMD::PMAutoLegacy::Method)}); ctlCmds.add({powerProfileDataSource_->source(), std::string(AMD::PMAutoLegacy::Profile)}); } } } corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautolegacy.h000066400000000000000000000016771467225065400263060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include "pmauto.h" #include #include #include namespace AMD { class PMAutoLegacy : public AMD::PMAuto { static constexpr std::string_view Method{"profile"}; static constexpr std::string_view Profile{"auto"}; public: PMAutoLegacy( std::unique_ptr> &&powerMethodDataSource, std::unique_ptr> &&powerProfileDataSource) noexcept; protected: void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: std::unique_ptr> const powerMethodDataSource_; std::unique_ptr> const powerProfileDataSource_; std::string powerMethodEntry_; std::string powerProfileEntry_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoprofilepart.cpp000066400000000000000000000034111467225065400277100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmautoprofilepart.h" #include "core/profilepartprovider.h" #include class AMD::PMAutoProfilePart::Initializer final : public AMD::PMAuto::Exporter { public: Initializer(AMD::PMAutoProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::PMAutoProfilePart &outer_; }; void AMD::PMAutoProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } AMD::PMAutoProfilePart::PMAutoProfilePart() noexcept : id_(AMD::PMAuto::ItemID) { } std::string const &AMD::PMAutoProfilePart::ID() const { return id_; } std::unique_ptr AMD::PMAutoProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMAutoProfilePart::initializer() { return std::make_unique(*this); } std::optional> AMD::PMAutoProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMAutoProfilePart::provideActive() const { return active(); } void AMD::PMAutoProfilePart::importProfilePart(IProfilePart::Importer &) { } void AMD::PMAutoProfilePart::exportProfilePart(IProfilePart::Exporter &) const { } std::unique_ptr AMD::PMAutoProfilePart::cloneProfilePart() const { return std::make_unique(); } bool const AMD::PMAutoProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMAuto::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoprofilepart.h000066400000000000000000000021641467225065400273610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmauto.h" #include namespace AMD { class PMAutoProfilePart final : public ProfilePart , public AMD::PMAuto::Importer { public: class Importer : public IProfilePart::Importer { }; class Exporter : public IProfilePart::Exporter { }; PMAutoProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const final override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: class Initializer; std::string const id_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoprovider.cpp000066400000000000000000000032761467225065400272240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmautoprovider.h" #include "../pmperfmodeprovider.h" #include "common/fileutils.h" #include "core/info/amd/gpuinfopm.h" #include "core/sysfsdatasource.h" #include "pmautolegacy.h" #include "pmautor600.h" #include #include #include std::vector> AMD::PMAutoProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { std::vector> controls; if (gpuInfo.vendor() != Vendor::AMD) return {}; if (gpuInfo.hasCapability(GPUInfoPM::Legacy)) { auto powerMethod = gpuInfo.path().sys / "power_method"; auto powerProfile = gpuInfo.path().sys / "power_profile"; if (!(Utils::File::isSysFSEntryValid(powerMethod) && Utils::File::isSysFSEntryValid(powerProfile))) return {}; controls.emplace_back(std::make_unique( std::make_unique>(powerMethod), std::make_unique>(powerProfile))); } else if (gpuInfo.hasCapability(GPUInfoPM::Radeon) || gpuInfo.hasCapability(GPUInfoPM::Amdgpu)) { auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; if (!Utils::File::isSysFSEntryValid(perfLevel)) return {}; controls.emplace_back(std::make_unique( std::make_unique>(perfLevel))); } return controls; } bool const AMD::PMAutoProvider::registered_ = AMD::PMPerfModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoprovider.h000066400000000000000000000007451467225065400266670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMAutoProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoqmlitem.cpp000066400000000000000000000051641467225065400270400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmautoqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmauto.h" #include #include #include #include #include #include char const *const AMD::PMAutoQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_PM_AUTO"), }; class AMD::PMAutoQMLItem::Initializer final : public QMLItem::Initializer , public IControl::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMAutoQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::PMAutoQMLItem &outer_; }; void AMD::PMAutoQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } AMD::PMAutoQMLItem::PMAutoQMLItem() noexcept { setName(tr(PMAuto::ItemID.data())); } void AMD::PMAutoQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMAutoQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMAutoQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMAutoQMLItem::provideActive() const { return active_; } void AMD::PMAutoQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } std::unique_ptr AMD::PMAutoQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } bool AMD::PMAutoQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMAuto::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMAuto::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDPMAutoForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMAutoQMLItem::registered_ = AMD::PMAutoQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoqmlitem.h000066400000000000000000000020451467225065400265000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmautoprofilepart.h" #include namespace AMD { class PMAutoQMLItem : public QMLItem , public AMD::PMAutoProfilePart::Importer , public AMD::PMAutoProfilePart::Exporter { Q_OBJECT public: explicit PMAutoQMLItem() noexcept; void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; bool active_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautor600.cpp000066400000000000000000000012631467225065400260530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmautor600.h" #include "core/icommandqueue.h" #include AMD::PMAutoR600::PMAutoR600( std::unique_ptr> &&perfLevelDataSource) noexcept : perfLevelDataSource_(std::move(perfLevelDataSource)) { } void AMD::PMAutoR600::cleanControl(ICommandQueue &) { } void AMD::PMAutoR600::syncControl(ICommandQueue &ctlCmds) { if (perfLevelDataSource_->read(perfLevelEntry_)) { if (perfLevelEntry_ != AMD::PMAutoR600::PerfLevel) ctlCmds.add({perfLevelDataSource_->source(), std::string(AMD::PMAutoR600::PerfLevel)}); } } corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautor600.h000066400000000000000000000013111467225065400255120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include "pmauto.h" #include #include #include namespace AMD { class PMAutoR600 : public AMD::PMAuto { static constexpr std::string_view PerfLevel{"auto"}; public: PMAutoR600( std::unique_ptr> &&perfLevelDataSource) noexcept; protected: void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: std::unique_ptr> const perfLevelDataSource_; std::string perfLevelEntry_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoxmlparser.cpp000066400000000000000000000043031467225065400273770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmautoxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmauto.h" #include class AMD::PMAutoXMLParser::Initializer final : public AMD::PMAutoProfilePart::Exporter { public: Initializer(AMD::PMAutoXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: AMD::PMAutoXMLParser &outer_; }; void AMD::PMAutoXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } AMD::PMAutoXMLParser::PMAutoXMLParser() noexcept : ProfilePartXMLParser(AMD::PMAuto::ItemID, *this, *this) { } std::unique_ptr AMD::PMAutoXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMAutoXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMAutoXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMAutoXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMAutoXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMAutoXMLParser::provideActive() const { return active_; } void AMD::PMAutoXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; } void AMD::PMAutoXMLParser::resetAttributes() { active_ = activeDefault_; } void AMD::PMAutoXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); } bool const AMD::PMAutoXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMAuto::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/auto/pmautoxmlparser.h000066400000000000000000000022441467225065400270460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmautoprofilepart.h" #include namespace AMD { class PMAutoXMLParser final : public ProfilePartXMLParser , public AMD::PMAutoProfilePart::Exporter , public AMD::PMAutoProfilePart::Importer { public: PMAutoXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/000077500000000000000000000000001467225065400235575ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixed.cpp000066400000000000000000000022541467225065400257220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixed.h" #include AMD::PMFixed::PMFixed(std::string_view mode) noexcept : Control(false) , id_(AMD::PMFixed::ItemID) , mode_(mode) { } void AMD::PMFixed::preInit(ICommandQueue &) { } void AMD::PMFixed::postInit(ICommandQueue &) { } void AMD::PMFixed::init() { } std::string const &AMD::PMFixed::ID() const { return id_; } void AMD::PMFixed::importControl(IControl::Importer &i) { auto &pmFixedImporter = dynamic_cast(i); mode(pmFixedImporter.providePMFixedMode()); } void AMD::PMFixed::exportControl(IControl::Exporter &e) const { auto &pmFixedExporter = dynamic_cast(e); pmFixedExporter.takePMFixedModes(modes()); pmFixedExporter.takePMFixedMode(mode()); } std::string const &AMD::PMFixed::mode() const { return mode_; } void AMD::PMFixed::mode(std::string const &mode) { // only assign known modes auto iter = std::find_if( modes().cbegin(), modes().cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != modes().cend()) mode_ = mode; } corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixed.h000066400000000000000000000023641467225065400253710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include #include #include namespace AMD { class PMFixed : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_FIXED"}; class Importer : public IControl::Importer { public: virtual std::string const &providePMFixedMode() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMFixedMode(std::string const &mode) = 0; virtual void takePMFixedModes(std::vector const &modes) = 0; }; PMFixed(std::string_view mode) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; std::string const &mode() const; void mode(std::string const &mode); virtual std::vector const &modes() const = 0; private: std::string const id_; std::string mode_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedlegacy.cpp000066400000000000000000000032221467225065400271030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedlegacy.h" #include "core/icommandqueue.h" #include AMD::PMFixedLegacy::PMFixedLegacy( std::unique_ptr> &&powerMethodDataSource, std::unique_ptr> &&powerProfileDataSource) noexcept : AMD::PMFixed(AMD::PMFixedLegacy::Profile::low) , powerMethodDataSource_(std::move(powerMethodDataSource)) , powerProfileDataSource_(std::move(powerProfileDataSource)) { } void AMD::PMFixedLegacy::cleanControl(ICommandQueue &ctlCmds) { ctlCmds.add({powerMethodDataSource_->source(), std::string(AMD::PMFixedLegacy::Method)}); ctlCmds.add({powerProfileDataSource_->source(), std::string(AMD::PMFixedLegacy::Profile::clean)}); } void AMD::PMFixedLegacy::syncControl(ICommandQueue &ctlCmds) { if (powerMethodDataSource_->read(powerMethodEntry_) && powerProfileDataSource_->read(powerProfileEntry_)) { if (powerMethodEntry_ != AMD::PMFixedLegacy::Method) { ctlCmds.add({powerMethodDataSource_->source(), std::string(AMD::PMFixedLegacy::Method)}); ctlCmds.add({powerProfileDataSource_->source(), mode()}); } else if (powerProfileEntry_ != mode()) { ctlCmds.add({powerProfileDataSource_->source(), mode()}); } } } std::vector const &AMD::PMFixedLegacy::modes() const { return modes_; } std::vector const AMD::PMFixedLegacy::modes_{ std::string(AMD::PMFixedLegacy::Profile::low), std::string(AMD::PMFixedLegacy::Profile::mid), std::string(AMD::PMFixedLegacy::Profile::high)}; corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedlegacy.h000066400000000000000000000023641467225065400265560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include "pmfixed.h" #include #include #include #include namespace AMD { class PMFixedLegacy : public PMFixed { static constexpr std::string_view Method{"profile"}; struct Profile { static constexpr std::string_view low{"low"}; static constexpr std::string_view mid{"mid"}; static constexpr std::string_view high{"high"}; static constexpr std::string_view clean{"auto"}; }; public: PMFixedLegacy( std::unique_ptr> &&powerMethodDataSource, std::unique_ptr> &&powerProfileDataSource) noexcept; protected: void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::vector const &modes() const final override; private: std::unique_ptr> const powerMethodDataSource_; std::unique_ptr> const powerProfileDataSource_; std::string powerMethodEntry_; std::string powerProfileEntry_; static std::vector const modes_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedprofilepart.cpp000066400000000000000000000055251467225065400301760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class AMD::PMFixedProfilePart::Initializer final : public AMD::PMFixed::Exporter { public: Initializer(AMD::PMFixedProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFixedMode(std::string const &mode) override; void takePMFixedModes(std::vector const &modes) override; private: AMD::PMFixedProfilePart &outer_; }; void AMD::PMFixedProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMFixedProfilePart::Initializer::takePMFixedMode(std::string const &mode) { outer_.mode_ = mode; } void AMD::PMFixedProfilePart::Initializer::takePMFixedModes( std::vector const &modes) { outer_.modes_ = modes; } AMD::PMFixedProfilePart::PMFixedProfilePart() noexcept : id_(AMD::PMFixed::ItemID) { } std::unique_ptr AMD::PMFixedProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMFixedProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMFixedProfilePart::ID() const { return id_; } std::optional> AMD::PMFixedProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMFixedProfilePart::provideActive() const { return active(); } std::string const &AMD::PMFixedProfilePart::providePMFixedMode() const { return mode_; } void AMD::PMFixedProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmfImporter = dynamic_cast(i); mode(pmfImporter.providePMFixedMode()); } void AMD::PMFixedProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmfExporter = dynamic_cast(e); pmfExporter.takePMFixedMode(mode_); } std::unique_ptr AMD::PMFixedProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->modes_ = modes_; clone->mode_ = mode_; return std::move(clone); } void AMD::PMFixedProfilePart::mode(std::string const &mode) { auto iter = std::find_if( modes_.cbegin(), modes_.cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != modes_.cend()) mode_ = mode; } bool const AMD::PMFixedProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMFixed::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedprofilepart.h000066400000000000000000000026671467225065400276470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmfixed.h" #include #include namespace AMD { class PMFixedProfilePart final : public ProfilePart , public AMD::PMFixed::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &providePMFixedMode() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMFixedMode(std::string const &mode) = 0; }; PMFixedProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const final override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::string const &providePMFixedMode() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void mode(std::string const &mode); class Initializer; std::string const id_; std::string mode_; std::vector modes_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedprovider.cpp000066400000000000000000000033071467225065400274750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedprovider.h" #include "../pmperfmodeprovider.h" #include "common/fileutils.h" #include "core/info/amd/gpuinfopm.h" #include "core/sysfsdatasource.h" #include "pmfixedlegacy.h" #include "pmfixedr600.h" #include #include #include std::vector> AMD::PMFixedProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { std::vector> controls; if (gpuInfo.vendor() != Vendor::AMD) return {}; if (gpuInfo.hasCapability(GPUInfoPM::Legacy)) { auto powerMethod = gpuInfo.path().sys / "power_method"; auto powerProfile = gpuInfo.path().sys / "power_profile"; if (!(Utils::File::isSysFSEntryValid(powerMethod) && Utils::File::isSysFSEntryValid(powerProfile))) return {}; controls.emplace_back(std::make_unique( std::make_unique>(powerMethod), std::make_unique>(powerProfile))); } else if (gpuInfo.hasCapability(GPUInfoPM::Radeon) || gpuInfo.hasCapability(GPUInfoPM::Amdgpu)) { auto perfLevel = gpuInfo.path().sys / "power_dpm_force_performance_level"; if (!Utils::File::isSysFSEntryValid(perfLevel)) return {}; controls.emplace_back(std::make_unique( std::make_unique>(perfLevel))); } return controls; } bool const AMD::PMFixedProvider::registered_ = AMD::PMPerfModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedprovider.h000066400000000000000000000007461467225065400271460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMFixedProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedqmlitem.cpp000066400000000000000000000077001467225065400273140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmfixed.h" #include #include #include #include #include #include char const *const AMD::PMFixedQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_PM_FIXED"), QT_TRANSLATE_NOOP("AMD::PMFixedQMLItem", "low"), QT_TRANSLATE_NOOP("AMD::PMFixedQMLItem", "mid"), QT_TRANSLATE_NOOP("AMD::PMFixedQMLItem", "high"), }; class AMD::PMFixedQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMFixed::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMFixedQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFixedMode(std::string const &mode) override; void takePMFixedModes(std::vector const &modes) override; private: AMD::PMFixedQMLItem &outer_; }; void AMD::PMFixedQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMFixedQMLItem::Initializer::takePMFixedMode(std::string const &mode) { outer_.takePMFixedMode(mode); } void AMD::PMFixedQMLItem::Initializer::takePMFixedModes( std::vector const &modes) { outer_.takePMFixedModes(modes); } AMD::PMFixedQMLItem::PMFixedQMLItem() noexcept { setName(tr(AMD::PMFixed::ItemID.data())); } void AMD::PMFixedQMLItem::changeMode(QString const &mode) { auto newMode = mode.toStdString(); if (mode_ != newMode) { std::swap(mode_, newMode); emit modeChanged(mode); emit settingsChanged(); } } void AMD::PMFixedQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMFixedQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMFixedQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMFixedQMLItem::provideActive() const { return active_; } std::string const &AMD::PMFixedQMLItem::providePMFixedMode() const { return mode_; } void AMD::PMFixedQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::PMFixedQMLItem::takePMFixedMode(std::string const &mode) { if (mode_ != mode) { mode_ = mode; emit modeChanged(QString::fromStdString(mode_)); } } std::unique_ptr AMD::PMFixedQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } void AMD::PMFixedQMLItem::takePMFixedModes(std::vector const &modes) { QList modeTextVector; for (auto mode : modes) { modeTextVector.push_back(QString::fromStdString(mode)); modeTextVector.push_back(tr(mode.data())); } emit modesChanged(modeTextVector); } bool AMD::PMFixedQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMFixed::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMFixed::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/AMDPMFixedForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMFixedQMLItem::registered_ = AMD::PMFixedQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedqmlitem.h000066400000000000000000000027421467225065400267620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmfixedprofilepart.h" #include #include #include #include #include namespace AMD { class PMFixedQMLItem : public QMLItem , public AMD::PMFixedProfilePart::Importer , public AMD::PMFixedProfilePart::Exporter { Q_OBJECT public: explicit PMFixedQMLItem() noexcept; signals: void modeChanged(QString const &mode); void modesChanged(QList const &modes); public slots: void changeMode(QString const &mode); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; std::string const &providePMFixedMode() const override; void takeActive(bool active) override; void takePMFixedMode(std::string const &mode) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void takePMFixedModes(std::vector const &modes); bool active_; std::string mode_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedr600.cpp000066400000000000000000000020211467225065400263220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedr600.h" #include "core/icommandqueue.h" #include AMD::PMFixedR600::PMFixedR600( std::unique_ptr> &&perfLevelDataSource) noexcept : AMD::PMFixed(AMD::PMFixedR600::PerfLevel::low) , perfLevelDataSource_(std::move(perfLevelDataSource)) { } void AMD::PMFixedR600::cleanControl(ICommandQueue &ctlCmds) { ctlCmds.add({perfLevelDataSource_->source(), std::string(AMD::PMFixedR600::PerfLevel::clean)}); } void AMD::PMFixedR600::syncControl(ICommandQueue &ctlCmds) { if (perfLevelDataSource_->read(perfLevelEntry_)) { if (perfLevelEntry_ != mode()) ctlCmds.add({perfLevelDataSource_->source(), mode()}); } } std::vector const &AMD::PMFixedR600::modes() const { return modes_; } std::vector const AMD::PMFixedR600::modes_{ std::string(AMD::PMFixedR600::PerfLevel::low), std::string(AMD::PMFixedR600::PerfLevel::high)}; corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedr600.h000066400000000000000000000017211467225065400257750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include "pmfixed.h" #include #include #include #include namespace AMD { class PMFixedR600 : public AMD::PMFixed { struct PerfLevel { static constexpr std::string_view low{"low"}; static constexpr std::string_view high{"high"}; static constexpr std::string_view clean{"auto"}; }; public: PMFixedR600( std::unique_ptr> &&perfLevelDataSource) noexcept; protected: void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::vector const &modes() const final override; private: std::unique_ptr> const perfLevelDataSource_; std::string perfLevelEntry_; static std::vector const modes_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedxmlparser.cpp000066400000000000000000000053451467225065400276640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmfixedxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmfixed.h" #include class AMD::PMFixedXMLParser::Initializer final : public AMD::PMFixedProfilePart::Exporter { public: Initializer(AMD::PMFixedXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMFixedMode(std::string const &mode) override; private: AMD::PMFixedXMLParser &outer_; }; void AMD::PMFixedXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMFixedXMLParser::Initializer::takePMFixedMode(std::string const &mode) { outer_.mode_ = outer_.modeDefault_ = mode; } AMD::PMFixedXMLParser::PMFixedXMLParser() noexcept : ProfilePartXMLParser(AMD::PMFixed::ItemID, *this, *this) { } std::unique_ptr AMD::PMFixedXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMFixedXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMFixedXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMFixedXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMFixedXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMFixedXMLParser::provideActive() const { return active_; } void AMD::PMFixedXMLParser::takePMFixedMode(std::string const &mode) { mode_ = mode; } std::string const &AMD::PMFixedXMLParser::providePMFixedMode() const { return mode_; } void AMD::PMFixedXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; pmFixedNode.append_attribute("mode") = mode_.c_str(); } void AMD::PMFixedXMLParser::resetAttributes() { active_ = activeDefault_; mode_ = modeDefault_; } void AMD::PMFixedXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); mode_ = pmFixedNode.attribute("mode").as_string(modeDefault_.c_str()); } bool const AMD::PMFixedXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMFixed::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/fixed/pmfixedxmlparser.h000066400000000000000000000025201467225065400273210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmfixedprofilepart.h" #include namespace AMD { class PMFixedXMLParser final : public ProfilePartXMLParser , public AMD::PMFixedProfilePart::Exporter , public AMD::PMFixedProfilePart::Importer { public: PMFixedXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMFixedMode(std::string const &mode) override; std::string const &providePMFixedMode() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; std::string mode_; std::string modeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/handlers/000077500000000000000000000000001467225065400242605ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/handlers/ippdpmhandler.h000066400000000000000000000011431467225065400272570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/idatasourcehandler.h" #include #include #include namespace AMD { class IPpDpmHandler : public IDataSourceHandler { public: virtual std::vector> const & states() const = 0; virtual std::vector const &active() const = 0; virtual void activate(std::vector const &states) = 0; virtual ~IPpDpmHandler() = default; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/handlers/ppdpmhandler.cpp000066400000000000000000000077071467225065400274550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "ppdpmhandler.h" #include "core/components/amdutils.h" #include "core/icommandqueue.h" #include #include AMD::PpDpmHandler::PpDpmHandler( std::unique_ptr> &&perfLevelDataSource, std::unique_ptr>> &&ppDpmDataSource) noexcept : perfLevelDataSource_(std::move(perfLevelDataSource)) , ppDpmDataSource_(std::move(ppDpmDataSource)) , resync_(true) { if (ppDpmDataSource_->read(ppDpmLines_)) { auto states = Utils::AMD::parseDPMStates(ppDpmLines_); if (states.has_value()) std::swap(states_, states.value()); active_.reserve(states_.size()); std::transform(states_.cbegin(), states_.cend(), std::back_inserter(active_), [](auto const &state) { return state.first; }); } } std::vector> const & AMD::PpDpmHandler::states() const { return states_; } std::vector const &AMD::PpDpmHandler::active() const { return active_; } void AMD::PpDpmHandler::activate(std::vector const &states) { std::vector active; std::copy_if(states.cbegin(), states.cend(), std::back_inserter(active), [&](unsigned int index) { // skip unknown state indices return std::find_if(states_.cbegin(), states_.cend(), [&](auto const &state) { return state.first == index; }) != states_.cend(); }); if (!active.empty()) { // cannot deactivate all states! std::swap(active, active_); resync_ = true; } } void AMD::PpDpmHandler::saveState() { // NOTE At the moment, there is no way to get the active states // from pp_dpm_* files. The data source state cannot be saved. } void AMD::PpDpmHandler::restoreState(ICommandQueue &) { // NOTE At the moment, there is no way to get the active states // from pp_dpm_* files. The data source state cannot be restored. } void AMD::PpDpmHandler::reset(ICommandQueue &ctlCmds) { std::string activeStatesStr; for (auto const &state : states_) activeStatesStr.append(std::to_string(state.first)).append(" "); activeStatesStr.pop_back(); // remove trailing space if (perfLevelDataSource_->read(perfLevelValue_) && perfLevelValue_ != "manual") ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.add({ppDpmDataSource_->source(), activeStatesStr}); resync_ = false; } void AMD::PpDpmHandler::sync(ICommandQueue &ctlCmds) { // NOTE As there is no way to obtain a list of active states from // pp_dpm_* files, we cannot control external changes of the file // when the external change selected one or more states within the // current active states group of this handler. // Also, we need to keep track manually when is necessary a re-sync. if (perfLevelDataSource_->read(perfLevelValue_) && ppDpmDataSource_->read(ppDpmLines_)) { if (perfLevelValue_ != "manual") { apply(ctlCmds); // apply it unconditionally } else { auto currentIndex = Utils::AMD::parseDPMCurrentStateIndex(ppDpmLines_); if (currentIndex.has_value()) { if (resync_ || // modified: needs syncing std::find( // current index is not an active index active_.cbegin(), active_.cend(), *currentIndex) == active_.cend()) apply(ctlCmds); } } } } void AMD::PpDpmHandler::apply(ICommandQueue &ctlCmds) { std::string activeStatesStr; for (auto index : active_) activeStatesStr.append(std::to_string(index)).append(" "); activeStatesStr.pop_back(); // remove trailing space if (perfLevelValue_ != "manual") ctlCmds.add({perfLevelDataSource_->source(), "manual"}); ctlCmds.add({ppDpmDataSource_->source(), activeStatesStr}); resync_ = false; } corectrl-v1.4.2/src/core/components/controls/amd/pm/handlers/ppdpmhandler.h000066400000000000000000000025431467225065400271130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include "ippdpmhandler.h" #include #include #include #include #include namespace AMD { class PpDpmHandler : public IPpDpmHandler { public: PpDpmHandler(std::unique_ptr> &&perfLevelDataSource, std::unique_ptr>> &&ppDpmDataSource) noexcept; std::vector> const & states() const override; std::vector const &active() const override; void activate(std::vector const &states) override; void saveState() override; void restoreState(ICommandQueue &ctlCmds) override; void reset(ICommandQueue &ctlCmds) override; void sync(ICommandQueue &ctlCmds) override; private: void apply(ICommandQueue &ctlCmds); std::unique_ptr> const perfLevelDataSource_; std::unique_ptr>> const ppDpmDataSource_; std::string perfLevelValue_; std::vector ppDpmLines_; std::vector> states_; std::vector active_; bool resync_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmode.h000066400000000000000000000010441467225065400247660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmode.h" #include #include #include #include namespace AMD { class PMPerfMode : public ControlMode { public: static constexpr std::string_view ItemID{"AMD_PM_PERFMODE"}; PMPerfMode(std::vector> &&controls) noexcept : ControlMode(AMD::PMPerfMode::ItemID, std::move(controls), true) { } }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodeprofilepart.cpp000066400000000000000000000012471467225065400275760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmperfmodeprofilepart.h" #include "core/profilepartprovider.h" #include "pmperfmode.h" #include AMD::PMPerfModeProfilePart::PMPerfModeProfilePart() noexcept : ControlModeProfilePart(AMD::PMPerfMode::ItemID) { } std::unique_ptr AMD::PMPerfModeProfilePart::instance() const { return std::make_unique(); } bool const AMD::PMPerfModeProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMPerfMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodeprofilepart.h000066400000000000000000000007121467225065400272370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodeprofilepart.h" namespace AMD { class PMPerfModeProfilePart final : public ControlModeProfilePart { public: PMPerfModeProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodeprovider.cpp000066400000000000000000000035261467225065400271030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmperfmodeprovider.h" #include "core/components/controls/gpucontrolprovider.h" #include "core/components/controls/noop.h" #include "core/info/igpuinfo.h" #include "pmperfmode.h" #include #include std::vector> AMD::PMPerfModeProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::vector> modeControls; for (auto const &provider : gpuControlProviders()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); modeControls.insert(modeControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (modeControls.empty()) return {}; modeControls.emplace_back(std::make_unique()); std::vector> controls; controls.emplace_back(std::make_unique(std::move(modeControls))); return controls; } std::vector> const & AMD::PMPerfModeProvider::gpuControlProviders() const { return providers_(); } bool AMD::PMPerfModeProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::PMPerfModeProvider::providers_() { static std::vector> providers; return providers; } bool const AMD::PMPerfModeProvider::registered_ = GPUControlProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodeprovider.h000066400000000000000000000015301467225065400265410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class PMPerfModeProvider final : public IGPUControlProvider::IProvider , public IGPUControlProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; std::vector> const & gpuControlProviders() const final override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodeqmlitem.cpp000066400000000000000000000020511467225065400267110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmperfmodeqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmperfmode.h" #include #include #include #include #include AMD::PMPerfModeQMLItem::PMPerfModeQMLItem() noexcept : ControlModeQMLItem(AMD::PMPerfMode::ItemID) { } bool AMD::PMPerfModeQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMPerfMode::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMPerfMode::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMPerfModeForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMPerfModeQMLItem::registered_ = AMD::PMPerfModeQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodeqmlitem.h000066400000000000000000000006061467225065400263620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodeqmlitem.h" namespace AMD { class PMPerfModeQMLItem : public ControlModeQMLItem { public: explicit PMPerfModeQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodexmlparser.cpp000066400000000000000000000010321467225065400272540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmperfmodexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmperfmode.h" #include AMD::PMPerfModeXMLParser::PMPerfModeXMLParser() noexcept : ControlModeXMLParser(AMD::PMPerfMode::ItemID) { } bool const AMD::PMPerfModeXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(AMD::PMPerfMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/pmperfmodexmlparser.h000066400000000000000000000005601467225065400267260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/controlmodexmlparser.h" namespace AMD { class PMPerfModeXMLParser final : public ControlModeXMLParser { public: PMPerfModeXMLParser() noexcept; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/000077500000000000000000000000001467225065400246555ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstate.cpp000066400000000000000000000040421467225065400301130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerstate.h" #include "core/icommandqueue.h" #include #include AMD::PMPowerState::PMPowerState( std::unique_ptr> &&powerDpmStateDataSource) noexcept : Control(true) , id_(AMD::PMPowerState::ItemID) , powerDpmStateDataSource_(std::move(powerDpmStateDataSource)) , mode_(State::Balanced) { } void AMD::PMPowerState::preInit(ICommandQueue &) { } void AMD::PMPowerState::postInit(ICommandQueue &) { } void AMD::PMPowerState::init() { } std::string const &AMD::PMPowerState::ID() const { return id_; } void AMD::PMPowerState::importControl(IControl::Importer &i) { auto &pmPowerStateImporter = dynamic_cast(i); mode(pmPowerStateImporter.providePMPowerStateMode()); } void AMD::PMPowerState::exportControl(IControl::Exporter &e) const { auto &pmPowerStateExporter = dynamic_cast(e); pmPowerStateExporter.takePMPowerStateModes(modes()); pmPowerStateExporter.takePMPowerStateMode(mode()); } void AMD::PMPowerState::cleanControl(ICommandQueue &) { } void AMD::PMPowerState::syncControl(ICommandQueue &ctlCmds) { if (powerDpmStateDataSource_->read(powerDpmStateEntry_)) { if (powerDpmStateEntry_ != mode()) ctlCmds.add({powerDpmStateDataSource_->source(), mode()}); } } std::string const &AMD::PMPowerState::mode() const { return mode_; } void AMD::PMPowerState::mode(std::string const &mode) { // only assign known modes auto iter = std::find_if( modes().cbegin(), modes().cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != modes().cend()) mode_ = mode; } std::vector const &AMD::PMPowerState::modes() const { return modes_; } std::vector const AMD::PMPowerState::modes_{ std::string(AMD::PMPowerState::State::Battery), std::string(AMD::PMPowerState::State::Balanced), std::string(AMD::PMPowerState::State::Performance)}; corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstate.h000066400000000000000000000035411467225065400275630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/idatasource.h" #include #include #include #include namespace AMD { class PMPowerState : public Control { public: static constexpr std::string_view ItemID{"AMD_PM_POWERSTATE"}; struct State { static constexpr std::string_view Battery{"battery"}; static constexpr std::string_view Balanced{"balanced"}; static constexpr std::string_view Performance{"performance"}; }; class Importer : public IControl::Importer { public: virtual std::string const &providePMPowerStateMode() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takePMPowerStateMode(std::string const &mode) = 0; virtual void takePMPowerStateModes(std::vector const &modes) = 0; }; PMPowerState(std::unique_ptr> &&powerDpmStateDataSource) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::string const &mode() const; void mode(std::string const &mode); std::vector const &modes() const; private: std::string const id_; std::unique_ptr> const powerDpmStateDataSource_; std::string powerDpmStateEntry_; std::string mode_; static std::vector const modes_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemode.h000066400000000000000000000010751467225065400304300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmode.h" #include #include #include #include namespace AMD { class PMPowerStateMode : public ControlMode { public: static constexpr std::string_view ItemID{"AMD_PM_POWERSTATE_MODE"}; PMPowerStateMode(std::vector> &&controls) noexcept : ControlMode(AMD::PMPowerStateMode::ItemID, std::move(controls), true) { } }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodeprofilepart.cpp000066400000000000000000000013431467225065400332310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmpowerstatemodeprofilepart.h" #include "core/profilepartprovider.h" #include "pmpowerstatemode.h" #include AMD::PMPowerStateModeProfilePart::PMPowerStateModeProfilePart() noexcept : ControlModeProfilePart(AMD::PMPowerStateMode::ItemID) { } std::unique_ptr AMD::PMPowerStateModeProfilePart::instance() const { return std::make_unique(); } bool const AMD::PMPowerStateModeProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMPowerStateMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodeprofilepart.h000066400000000000000000000007261467225065400327020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmodeprofilepart.h" namespace AMD { class PMPowerStateModeProfilePart final : public ControlModeProfilePart { public: PMPowerStateModeProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodeprovider.cpp000066400000000000000000000036311467225065400325360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmpowerstatemodeprovider.h" #include "core/components/controls/gpucontrolprovider.h" #include "core/components/controls/noop.h" #include "core/info/igpuinfo.h" #include "pmpowerstatemode.h" #include #include std::vector> AMD::PMPowerStateModeProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::vector> modeControls; for (auto const &provider : gpuControlProviders()) { auto newControls = provider->provideGPUControls(gpuInfo, swInfo); modeControls.insert(modeControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (modeControls.empty()) return {}; modeControls.emplace_back(std::make_unique()); std::vector> controls; controls.emplace_back( std::make_unique(std::move(modeControls))); return controls; } std::vector> const & AMD::PMPowerStateModeProvider::gpuControlProviders() const { return providers_(); } bool AMD::PMPowerStateModeProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & AMD::PMPowerStateModeProvider::providers_() { static std::vector> providers; return providers; } bool const AMD::PMPowerStateModeProvider::registered_ = GPUControlProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodeprovider.h000066400000000000000000000015361467225065400322050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" #include #include namespace AMD { class PMPowerStateModeProvider final : public IGPUControlProvider::IProvider , public IGPUControlProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; std::vector> const & gpuControlProviders() const final override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodeqmlitem.cpp000066400000000000000000000021161467225065400323510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmpowerstatemodeqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmpowerstatemode.h" #include #include #include #include #include AMD::PMPowerStateModeQMLItem::PMPowerStateModeQMLItem() noexcept : ControlModeQMLItem(AMD::PMPowerStateMode::ItemID) { } bool AMD::PMPowerStateModeQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType( "CoreCtrl.UIComponents", 1, 0, AMD::PMPowerStateMode::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMPowerStateMode::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMPowerStateModeForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMPowerStateModeQMLItem::registered_ = AMD::PMPowerStateModeQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodeqmlitem.h000066400000000000000000000006221467225065400320160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmodeqmlitem.h" namespace AMD { class PMPowerStateModeQMLItem : public ControlModeQMLItem { public: explicit PMPowerStateModeQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodexmlparser.cpp000066400000000000000000000022661467225065400327240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "pmpowerstatemodexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmpowerstatemode.h" #include AMD::PMPowerStateModeXMLParser::PMPowerStateModeXMLParser() noexcept : ControlModeXMLParser(AMD::PMPowerStateMode::ItemID) { } void AMD::PMPowerStateModeXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto node = parentNode.find_child([&](pugi::xml_node const &node) { return node.name() == AMD::PMPowerStateMode::ItemID; }); takeActive(node.attribute("active").as_bool(activeDefault())); takeActive(node.attribute("mode").as_string(modeDefault().c_str())); if (!node) { // Legacy control settings might be present in the profile. // The old control settings were attach to this node parent, // so we must pass it in order to load its settings. node = parentNode; } loadComponents(node); } bool const AMD::PMPowerStateModeXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMPowerStateMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatemodexmlparser.h000066400000000000000000000007111467225065400323620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmodexmlparser.h" namespace AMD { class PMPowerStateModeXMLParser final : public ControlModeXMLParser { public: PMPowerStateModeXMLParser() noexcept; protected: void loadPartFrom(pugi::xml_node const &parentNode) override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstateprofilepart.cpp000066400000000000000000000060411467225065400323640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerstateprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class AMD::PMPowerStateProfilePart::Initializer final : public AMD::PMPowerState::Exporter { public: Initializer(AMD::PMPowerStateProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerStateMode(std::string const &mode) override; void takePMPowerStateModes(std::vector const &modes) override; private: AMD::PMPowerStateProfilePart &outer_; }; void AMD::PMPowerStateProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void AMD::PMPowerStateProfilePart::Initializer::takePMPowerStateMode( std::string const &mode) { outer_.mode_ = mode; } void AMD::PMPowerStateProfilePart::Initializer::takePMPowerStateModes( std::vector const &modes) { outer_.modes_ = modes; } AMD::PMPowerStateProfilePart::PMPowerStateProfilePart() noexcept : id_(AMD::PMPowerState::ItemID) { } std::unique_ptr AMD::PMPowerStateProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr AMD::PMPowerStateProfilePart::initializer() { return std::make_unique(*this); } std::string const &AMD::PMPowerStateProfilePart::ID() const { return id_; } std::optional> AMD::PMPowerStateProfilePart::provideImporter(Item const &) { return {}; } bool AMD::PMPowerStateProfilePart::provideActive() const { return active(); } std::string const &AMD::PMPowerStateProfilePart::providePMPowerStateMode() const { return mode_; } void AMD::PMPowerStateProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmfImporter = dynamic_cast(i); mode(pmfImporter.providePMPowerStateMode()); } void AMD::PMPowerStateProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmfExporter = dynamic_cast(e); pmfExporter.takePMPowerStateMode(mode_); } std::unique_ptr AMD::PMPowerStateProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->modes_ = modes_; clone->mode_ = mode_; return std::move(clone); } void AMD::PMPowerStateProfilePart::mode(std::string const &mode) { // import known modes auto iter = std::find_if( modes_.cbegin(), modes_.cend(), [&](auto const &availableMode) { return mode == availableMode; }); if (iter != modes_.cend()) mode_ = mode; } bool const AMD::PMPowerStateProfilePart::registered_ = ProfilePartProvider::registerProvider(AMD::PMPowerState::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstateprofilepart.h000066400000000000000000000027321467225065400320340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "pmpowerstate.h" #include #include namespace AMD { class PMPowerStateProfilePart final : public ProfilePart , public AMD::PMPowerState::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &providePMPowerStateMode() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePMPowerStateMode(std::string const &mode) = 0; }; PMPowerStateProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const final override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::string const &providePMPowerStateMode() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void mode(std::string const &mode); class Initializer; std::string const id_; std::string mode_; std::vector modes_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstateprovider.cpp000066400000000000000000000022611467225065400316670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerstateprovider.h" #include "common/fileutils.h" #include "core/info/igpuinfo.h" #include "core/sysfsdatasource.h" #include "pmpowerstate.h" #include "pmpowerstatemodeprovider.h" #include #include #include std::vector> AMD::PMPowerStateProvider::provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &) const { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver != "radeon") return {}; auto powerDpmStatePath = gpuInfo.path().sys / "power_dpm_state"; if (!Utils::File::isSysFSEntryValid(powerDpmStatePath)) return {}; std::vector> controls; controls.emplace_back(std::make_unique( std::make_unique>(powerDpmStatePath))); return controls; } bool const AMD::PMPowerStateProvider::registered_ = AMD::PMPowerStateModeProvider::registerProvider( std::make_unique()); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstateprovider.h000066400000000000000000000007531467225065400313400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/igpucontrolprovider.h" namespace AMD { class PMPowerStateProvider final : public IGPUControlProvider::IProvider { public: std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const override; private: static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstateqmlitem.cpp000066400000000000000000000101371467225065400315060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerstateqmlitem.h" #include "core/qmlcomponentregistry.h" #include "pmpowerstate.h" #include #include #include #include #include #include char const *const AMD::PMPowerStateQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "AMD_PM_POWERSTATE"), QT_TRANSLATE_NOOP("AMD::PMPowerStateQMLItem", "battery"), QT_TRANSLATE_NOOP("AMD::PMPowerStateQMLItem", "balanced"), QT_TRANSLATE_NOOP("AMD::PMPowerStateQMLItem", "performance"), }; class AMD::PMPowerStateQMLItem::Initializer final : public QMLItem::Initializer , public AMD::PMPowerState::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, AMD::PMPowerStateQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerStateMode(std::string const &mode) override; void takePMPowerStateModes(std::vector const &modes) override; private: AMD::PMPowerStateQMLItem &outer_; }; void AMD::PMPowerStateQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void AMD::PMPowerStateQMLItem::Initializer::takePMPowerStateMode( std::string const &mode) { outer_.takePMPowerStateMode(mode); } void AMD::PMPowerStateQMLItem::Initializer::takePMPowerStateModes( std::vector const &modes) { outer_.takePMPowerStateModes(modes); } AMD::PMPowerStateQMLItem::PMPowerStateQMLItem() noexcept { setName(tr(AMD::PMPowerState::ItemID.data())); } void AMD::PMPowerStateQMLItem::changeMode(QString const &mode) { auto newMode = mode.toStdString(); if (mode_ != newMode) { std::swap(mode_, newMode); emit modeChanged(mode); emit settingsChanged(); } } void AMD::PMPowerStateQMLItem::activate(bool active) { takeActive(active); } std::optional> AMD::PMPowerStateQMLItem::provideImporter(Item const &) { return {}; } std::optional> AMD::PMPowerStateQMLItem::provideExporter(Item const &) { return {}; } bool AMD::PMPowerStateQMLItem::provideActive() const { return active_; } std::string const &AMD::PMPowerStateQMLItem::providePMPowerStateMode() const { return mode_; } void AMD::PMPowerStateQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void AMD::PMPowerStateQMLItem::takePMPowerStateMode(std::string const &mode) { if (mode_ != mode) { mode_ = mode; emit modeChanged(QString::fromStdString(mode_)); } } std::unique_ptr AMD::PMPowerStateQMLItem::initializer( IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique( qmlComponentFactory, qmlEngine, *this); } void AMD::PMPowerStateQMLItem::takePMPowerStateModes( std::vector const &modes) { QList modeTextVector; for (auto mode : modes) { modeTextVector.push_back(QString::fromStdString(mode)); modeTextVector.push_back(tr(mode.data())); } emit modesChanged(modeTextVector); } bool AMD::PMPowerStateQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, AMD::PMPowerState::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( AMD::PMPowerState::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component( &engine, QStringLiteral("qrc:/qml/AMDPMPowerStateForm.qml")); return qobject_cast(component.create()); }); return true; } bool const AMD::PMPowerStateQMLItem::registered_ = AMD::PMPowerStateQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstateqmlitem.h000066400000000000000000000030121467225065400311450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "pmpowerstateprofilepart.h" #include #include #include #include #include namespace AMD { class PMPowerStateQMLItem : public QMLItem , public AMD::PMPowerStateProfilePart::Importer , public AMD::PMPowerStateProfilePart::Exporter { Q_OBJECT public: explicit PMPowerStateQMLItem() noexcept; signals: void modeChanged(QString const &mode); void modesChanged(QList const &modes); public slots: void changeMode(QString const &mode); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; std::string const &providePMPowerStateMode() const override; void takeActive(bool active) override; void takePMPowerStateMode(std::string const &mode) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void takePMPowerStateModes(std::vector const &modes); bool active_; std::string mode_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatexmlparser.cpp000066400000000000000000000056071467225065400320610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "pmpowerstatexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "pmpowerstate.h" #include class AMD::PMPowerStateXMLParser::Initializer final : public AMD::PMPowerStateProfilePart::Exporter { public: Initializer(AMD::PMPowerStateXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takePMPowerStateMode(std::string const &mode) override; private: AMD::PMPowerStateXMLParser &outer_; }; void AMD::PMPowerStateXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void AMD::PMPowerStateXMLParser::Initializer::takePMPowerStateMode( std::string const &mode) { outer_.mode_ = outer_.modeDefault_ = mode; } AMD::PMPowerStateXMLParser::PMPowerStateXMLParser() noexcept : ProfilePartXMLParser(AMD::PMPowerState::ItemID, *this, *this) { } std::unique_ptr AMD::PMPowerStateXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr AMD::PMPowerStateXMLParser::initializer() { return std::make_unique(*this); } std::optional> AMD::PMPowerStateXMLParser::provideExporter(Item const &) { return {}; } std::optional> AMD::PMPowerStateXMLParser::provideImporter(Item const &) { return {}; } void AMD::PMPowerStateXMLParser::takeActive(bool active) { active_ = active; } bool AMD::PMPowerStateXMLParser::provideActive() const { return active_; } void AMD::PMPowerStateXMLParser::takePMPowerStateMode(std::string const &mode) { mode_ = mode; } std::string const &AMD::PMPowerStateXMLParser::providePMPowerStateMode() const { return mode_; } void AMD::PMPowerStateXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; pmFixedNode.append_attribute("mode") = mode_.c_str(); } void AMD::PMPowerStateXMLParser::resetAttributes() { active_ = activeDefault_; mode_ = modeDefault_; } void AMD::PMPowerStateXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); mode_ = pmFixedNode.attribute("mode").as_string(modeDefault_.c_str()); } bool const AMD::PMPowerStateXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( AMD::PMPowerState::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/amd/pm/powerstate/pmpowerstatexmlparser.h000066400000000000000000000025631467225065400315240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "pmpowerstateprofilepart.h" #include namespace AMD { class PMPowerStateXMLParser final : public ProfilePartXMLParser , public AMD::PMPowerStateProfilePart::Exporter , public AMD::PMPowerStateProfilePart::Importer { public: PMPowerStateXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePMPowerStateMode(std::string const &mode) override; std::string const &providePMPowerStateMode() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; std::string mode_; std::string modeDefault_; static bool const registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/components/controls/control.cpp000066400000000000000000000025161467225065400234730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "control.h" Control::Control(bool active, bool forceClean) noexcept : active_(active) , forceClean_(forceClean) { } bool Control::active() const { return active_; } void Control::activate(bool active) { if (active_ && !active) dirty(true); active_ = active; } void Control::cleanOnce() { dirty(true); } void Control::importWith(Importable::Importer &i) { auto importer = i.provideImporter(*this); if (importer.has_value()) { auto &controlImporter = dynamic_cast(importer->get()); activate(controlImporter.provideActive()); importControl(controlImporter); } } void Control::exportWith(Exportable::Exporter &e) const { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { auto &controlExporter = dynamic_cast(exporter->get()); controlExporter.takeActive(active()); exportControl(controlExporter); } } void Control::clean(ICommandQueue &ctlCmds) { if (forceClean_ || dirty()) { cleanControl(ctlCmds); dirty(false); } } void Control::sync(ICommandQueue &ctlCmds) { if (active()) syncControl(ctlCmds); } bool Control::dirty() const { return dirty_; } void Control::dirty(bool isDirty) { dirty_ = isDirty; } corectrl-v1.4.2/src/core/components/controls/control.h000066400000000000000000000016771467225065400231470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icontrol.h" class Control : public IControl { public: Control(bool active = true, bool forceClean = false) noexcept; bool active() const final override; void activate(bool active) override; void cleanOnce() override; void importWith(Importable::Importer &i) final override; void exportWith(Exportable::Exporter &e) const final override; void clean(ICommandQueue &ctlCmds) final override; void sync(ICommandQueue &ctlCmds) final override; protected: virtual void importControl(IControl::Importer &i) = 0; virtual void exportControl(IControl::Exporter &e) const = 0; virtual void cleanControl(ICommandQueue &ctlCmds) = 0; virtual void syncControl(ICommandQueue &ctlCmds) = 0; bool dirty() const; void dirty(bool isDirty); protected: bool active_; bool forceClean_; bool dirty_{false}; }; corectrl-v1.4.2/src/core/components/controls/controlgroup.cpp000066400000000000000000000037161467225065400245530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlgroup.h" #include ControlGroup::ControlGroup(std::string_view id, std::vector> &&controls, bool active) noexcept : Control(active) , id_(id) , controls_(std::move(controls)) { } void ControlGroup::preInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->preInit(ctlCmds); } void ControlGroup::postInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->postInit(ctlCmds); } void ControlGroup::init() { if (!controls_.empty()) { for (auto &control : controls_) { control->init(); // activate inactive controls if (!control->active()) control->activate(true); } } } std::string const &ControlGroup::ID() const { return id_; } void ControlGroup::activate(bool active) { Control::activate(active); if (dirty()) { // All aggregated controls are always active. Therefore, we must // clean them manually as they will never enter in dirty state on // their own. for (auto &control : controls_) control->cleanOnce(); } } void ControlGroup::cleanOnce() { Control::cleanOnce(); // propagate clean once to aggregated controls for (auto &control : controls_) control->cleanOnce(); } void ControlGroup::importControl(IControl::Importer &i) { for (auto &control : controls_) { control->importWith(i); // ensure that all controls are active control->activate(true); } } void ControlGroup::exportControl(IControl::Exporter &e) const { for (auto const &control : controls_) control->exportWith(e); } void ControlGroup::cleanControl(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->clean(ctlCmds); } void ControlGroup::syncControl(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->sync(ctlCmds); } corectrl-v1.4.2/src/core/components/controls/controlgroup.h000066400000000000000000000020661467225065400242150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include #include #include #include /// A control that aggregates other controls. class ControlGroup : public Control { public: ControlGroup(std::string_view id, std::vector> &&controls, bool active) noexcept; void preInit(ICommandQueue &ctlCmds) override; void postInit(ICommandQueue &ctlCmds) override; void init() final override; std::string const &ID() const final override; void activate(bool active) final override; void cleanOnce() final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) override; void syncControl(ICommandQueue &ctlCmds) override; private: std::string const id_; std::vector> const controls_; }; corectrl-v1.4.2/src/core/components/controls/controlgroupprofilepart.cpp000066400000000000000000000103741467225065400270210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlgroupprofilepart.h" #include #include #include #include class ControlGroupProfilePart::Factory final : public ProfilePart::Factory , public ControlGroup::Exporter { public: Factory(IProfilePartProvider const &profilePartProvider, ControlGroupProfilePart &profilePart) noexcept : ProfilePart::Factory(profilePartProvider) , outer_(profilePart) { } void takeProfilePart(std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } private: ControlGroupProfilePart &outer_; }; void ControlGroupProfilePart::Factory::takeProfilePart( std::unique_ptr &&part) { outer_.parts_.emplace_back(std::move(part)); } std::optional> ControlGroupProfilePart::Factory::provideExporter(Item const &i) { return factory(i.ID()); } class ControlGroupProfilePart::Initializer final : public ControlGroup::Exporter { public: Initializer(ControlGroupProfilePart &profilePart) noexcept : outer_(profilePart) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; private: ControlGroupProfilePart &outer_; std::unordered_map> initializers_; }; std::optional> ControlGroupProfilePart::Initializer::provideExporter(Item const &i) { for (auto &part : outer_.parts_) { if (part->ID() == i.ID() && (part->instanceID() == i.instanceID() || part->instanceID().empty())) { // Each item instance must have its own initializer auto const id = i.ID() != i.instanceID() ? i.ID() + i.instanceID() : i.ID(); if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = part->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } break; } } return {}; } void ControlGroupProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } ControlGroupProfilePart::ControlGroupProfilePart(std::string_view id) noexcept : id_(id) { } std::unique_ptr ControlGroupProfilePart::factory(IProfilePartProvider const &profilePartProvider) { return std::make_unique(profilePartProvider, *this); } std::unique_ptr ControlGroupProfilePart::initializer() { return std::make_unique(*this); } std::string const &ControlGroupProfilePart::ID() const { return id_; } std::optional> ControlGroupProfilePart::provideImporter(Item const &i) { auto partIter = std::find_if( parts_.cbegin(), parts_.cend(), [&](auto const &part) { return part->ID() == i.ID() && part->instanceID() == i.instanceID(); }); if (partIter != parts_.cend()) { auto importer = dynamic_cast(partIter->get()); if (importer != nullptr) return *importer; } return {}; } bool ControlGroupProfilePart::provideActive() const { return active(); } void ControlGroupProfilePart::importProfilePart(IProfilePart::Importer &i) { for (auto &part : parts_) { part->importWith(i); // ensure that all parts are active part->activate(true); } } void ControlGroupProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { for (auto const &part : parts_) part->exportWith(e); } std::unique_ptr ControlGroupProfilePart::cloneProfilePart() const { auto clone = instance(); clone->parts_.reserve(parts_.size()); std::transform( parts_.cbegin(), parts_.cend(), std::back_inserter(clone->parts_), [](std::unique_ptr const &part) { return part->clone(); }); return std::move(clone); } corectrl-v1.4.2/src/core/components/controls/controlgroupprofilepart.h000066400000000000000000000025021467225065400264600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "controlgroup.h" #include "core/profilepart.h" #include #include #include #include class ControlGroupProfilePart : public ProfilePart , public ControlGroup::Importer { public: class Importer : public IProfilePart::Importer { }; class Exporter : public IProfilePart::Exporter { }; ControlGroupProfilePart(std::string_view id) noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) final override; std::unique_ptr initializer() final override; std::string const &ID() const final override; std::optional> provideImporter(Item const &i) final override; bool provideActive() const final override; protected: void importProfilePart(IProfilePart::Importer &i) final override; void exportProfilePart(IProfilePart::Exporter &e) const final override; std::unique_ptr cloneProfilePart() const final override; virtual std::unique_ptr instance() const = 0; private: class Factory; class Initializer; std::vector> parts_; std::string const id_; }; corectrl-v1.4.2/src/core/components/controls/controlgroupqmlitem.cpp000066400000000000000000000060631467225065400261420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlgroupqmlitem.h" #include "controlgroup.h" #include "icontrol.h" #include #include #include class ControlGroupQMLItem::Initializer final : public QMLItem::Initializer , public ControlGroup::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, ControlGroupQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; private: ControlGroupQMLItem &outer_; }; std::optional> ControlGroupQMLItem::Initializer::provideExporter(Item const &i) { return initializer(i.ID(), &outer_).first; } void ControlGroupQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } ControlGroupQMLItem::ControlGroupQMLItem(std::string_view id) noexcept { setName(tr(id.data())); } void ControlGroupQMLItem::activate(bool active) { takeActive(active); } std::optional> ControlGroupQMLItem::provideImporter(Item const &i) { auto item = findQQuickItem(i); if (item == nullptr) return {}; return dynamic_cast(*item); } std::optional> ControlGroupQMLItem::provideExporter(Item const &i) { auto item = findQQuickItem(i); if (item == nullptr) return {}; return dynamic_cast(*item); } bool ControlGroupQMLItem::provideActive() const { return active_; } void ControlGroupQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } QQuickItem *ControlGroupQMLItem::findQQuickItem(Item const &i) const { static std::string const instanceIDPropertyName{"instanceID"}; if (i.ID() != i.instanceID()) { // The control has multiple instances auto children = this->findChildren(QString::fromStdString(i.ID())); if (!children.empty()) { auto instanceID = QString::fromStdString(i.instanceID()); for (auto child : children) { auto instanceIDProperty = child->property(instanceIDPropertyName.c_str()); if (instanceIDProperty.isValid() && instanceIDProperty.toString() == instanceID) return child; } } } else { // The control has a single instance auto item = this->findChild(QString::fromStdString(i.ID())); if (item != nullptr) return item; } return nullptr; } std::unique_ptr ControlGroupQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } corectrl-v1.4.2/src/core/components/controls/controlgroupqmlitem.h000066400000000000000000000020471467225065400256050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "controlgroupprofilepart.h" #include "core/qmlitem.h" #include #include class QQuickItem; class ControlGroupQMLItem : public QMLItem , public ControlGroupProfilePart::Importer , public ControlGroupProfilePart::Exporter { Q_OBJECT public: explicit ControlGroupQMLItem(std::string_view id) noexcept; public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; QQuickItem *findQQuickItem(Item const &i) const; bool active_; }; corectrl-v1.4.2/src/core/components/controls/controlgroupxmlparser.cpp000066400000000000000000000114371467225065400265100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlgroupxmlparser.h" #include #include #include class ControlGroupXMLParser::Factory final : public ProfilePartXMLParser::Factory , public ControlGroupProfilePart::Exporter { public: Factory(IProfilePartXMLParserProvider const &profilePartParserProvider, ControlGroupXMLParser &outer) noexcept : ProfilePartXMLParser::Factory(profilePartParserProvider) , outer_(outer) { } void takePartParser(Item const &i, std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } private: ControlGroupXMLParser &outer_; }; void ControlGroupXMLParser::Factory::takePartParser( Item const &, std::unique_ptr &&part) { outer_.parsers_.emplace_back(std::move(part)); } std::optional> ControlGroupXMLParser::Factory::provideExporter(Item const &i) { return factory(i); } class ControlGroupXMLParser::Initializer final : public ControlGroupProfilePart::Exporter { public: Initializer(ControlGroupXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; private: ControlGroupXMLParser &outer_; std::unordered_map> initializers_; }; std::optional> ControlGroupXMLParser::Initializer::provideExporter(Item const &i) { for (auto &parser : outer_.parsers_) { if (parser->ID() == i.ID() && (parser->instanceID() == i.instanceID() || parser->instanceID().empty())) { // Each item instance must have its own initializer auto const id = i.ID() != i.instanceID() ? i.ID() + i.instanceID() : i.ID(); if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = parser->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } break; } } return {}; } void ControlGroupXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } ControlGroupXMLParser::ControlGroupXMLParser(std::string_view id) noexcept : ProfilePartXMLParser(id, *this, *this) { } std::unique_ptr ControlGroupXMLParser::factory( IProfilePartXMLParserProvider const &profilePartXMLParserProvider) { return std::make_unique( profilePartXMLParserProvider, *this); } std::unique_ptr ControlGroupXMLParser::initializer() { return std::make_unique(*this); } std::optional> ControlGroupXMLParser::provideExporter(Item const &i) { auto parserIt = std::find_if( parsers_.cbegin(), parsers_.cend(), [&](auto const &part) { return part->ID() == i.ID() && part->instanceID() == i.instanceID(); }); if (parserIt != parsers_.cend()) return (*parserIt)->profilePartExporter(); return {}; } std::optional> ControlGroupXMLParser::provideImporter(Item const &i) { auto parserIt = std::find_if( parsers_.cbegin(), parsers_.cend(), [&](auto const &part) { return part->ID() == i.ID() && part->instanceID() == i.instanceID(); }); if (parserIt != parsers_.cend()) return (*parserIt)->profilePartImporter(); return {}; } void ControlGroupXMLParser::takeActive(bool active) { active_ = active; } bool ControlGroupXMLParser::provideActive() const { return active_; } void ControlGroupXMLParser::appendTo(pugi::xml_node &parentNode) { auto node = parentNode.append_child(ID().c_str()); node.append_attribute("active") = active_; for (auto &parser : parsers_) parser->appendTo(node); } void ControlGroupXMLParser::resetAttributes() { active_ = activeDefault(); } void ControlGroupXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto node = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = node.attribute("active").as_bool(activeDefault()); loadComponents(node); } void ControlGroupXMLParser::loadComponents(pugi::xml_node const &parentNode) { for (auto &parser : parsers_) parser->loadFrom(parentNode); } bool ControlGroupXMLParser::activeDefault() const { return activeDefault_; } corectrl-v1.4.2/src/core/components/controls/controlgroupxmlparser.h000066400000000000000000000026071467225065400261540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "controlgroupprofilepart.h" #include "core/profilepartxmlparser.h" #include #include #include #include class ControlGroupXMLParser : public ProfilePartXMLParser , public ControlGroupProfilePart::Exporter , public ControlGroupProfilePart::Importer { public: ControlGroupXMLParser(std::string_view id) noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) final override; std::optional> provideImporter(Item const &i) final override; void takeActive(bool active) final override; bool provideActive() const final override; void appendTo(pugi::xml_node &parentNode) final override; protected: void resetAttributes() final override; void loadPartFrom(pugi::xml_node const &parentNode) override; void loadComponents(pugi::xml_node const &parentNode); bool activeDefault() const; private: class Factory; class Initializer; std::vector> parsers_; bool active_; bool activeDefault_; }; corectrl-v1.4.2/src/core/components/controls/controlmode.cpp000066400000000000000000000047121467225065400243400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlmode.h" #include #include ControlMode::ControlMode(std::string_view id, std::vector> &&controls, bool active) noexcept : Control(active, true) , id_(id) , controls_(std::move(controls)) { } void ControlMode::preInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->preInit(ctlCmds); } void ControlMode::postInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->postInit(ctlCmds); } void ControlMode::init() { // Set the first active control as the active mode // or the first one when no active controls are found. bool activeFound{false}; for (auto &control : controls_) { control->init(); if (!activeFound && control->active()) { mode_ = control->ID(); activeFound = true; } else if (activeFound && control->active()) control->activate(false); } if (!activeFound && !controls_.empty()) { auto &control = controls_.front(); control->activate(true); mode_ = control->ID(); } } std::string const &ControlMode::ID() const { return id_; } void ControlMode::importControl(IControl::Importer &i) { auto &pModeImporter = dynamic_cast(i); mode(pModeImporter.provideMode()); for (auto &control : controls_) { control->importWith(i); // ensure that only the selected mode is active control->activate(control->ID() == mode()); } } void ControlMode::exportControl(IControl::Exporter &e) const { std::vector modes; for (auto const &control : controls_) { modes.emplace_back(control->ID()); control->exportWith(e); } auto &pModeExporter = dynamic_cast(e); pModeExporter.takeModes(modes); pModeExporter.takeMode(mode()); } void ControlMode::cleanControl(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->clean(ctlCmds); } void ControlMode::syncControl(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->sync(ctlCmds); } std::string const &ControlMode::mode() const { return mode_; } void ControlMode::mode(std::string const &mode) { auto iter = std::find_if( controls_.cbegin(), controls_.cend(), [&](auto const &control) { return mode == control->ID(); }); if (iter != controls_.cend()) mode_ = mode; } corectrl-v1.4.2/src/core/components/controls/controlmode.h000066400000000000000000000027071467225065400240070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include #include #include #include /// A control that aggregates other controls, /// having only one of them active at the same time. class ControlMode : public Control { public: class Importer : public IControl::Importer { public: virtual std::string const &provideMode() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takeMode(std::string const &mode) = 0; virtual void takeModes(std::vector const &modes) = 0; }; ControlMode(std::string_view id, std::vector> &&controls, bool active) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::string const &mode() const; void mode(std::string const &mode); private: std::string const id_; std::vector> const controls_; std::string mode_; }; corectrl-v1.4.2/src/core/components/controls/controlmodeprofilepart.cpp000066400000000000000000000115671467225065400266160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlmodeprofilepart.h" #include "core/item.h" #include #include #include #include class ControlModeProfilePart::Factory final : public ProfilePart::Factory , public ControlMode::Exporter { public: Factory(IProfilePartProvider const &profilePartProvider, ControlModeProfilePart &outer) noexcept : ProfilePart::Factory(profilePartProvider) , outer_(outer) { } void takeProfilePart(std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takeMode(std::string const &) override { } void takeModes(std::vector const &) override { } private: ControlModeProfilePart &outer_; }; void ControlModeProfilePart::Factory::takeProfilePart( std::unique_ptr &&part) { outer_.parts_.emplace_back(std::move(part)); } std::optional> ControlModeProfilePart::Factory::provideExporter(Item const &i) { return factory(i.ID()); } class ControlModeProfilePart::Initializer final : public ControlMode::Exporter { public: Initializer(ControlModeProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool) override; void takeMode(std::string const &) override; void takeModes(std::vector const &) override { } private: ControlModeProfilePart &outer_; std::unordered_map> initializers_; }; std::optional> ControlModeProfilePart::Initializer::provideExporter(Item const &i) { for (auto &part : outer_.parts_) { auto &id = part->ID(); if (id == i.ID()) { if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = part->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } break; } } return {}; } void ControlModeProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void ControlModeProfilePart::Initializer::takeMode(std::string const &mode) { outer_.mode_ = mode; } ControlModeProfilePart::ControlModeProfilePart(std::string_view id) noexcept : id_(id) { } std::unique_ptr ControlModeProfilePart::factory(IProfilePartProvider const &profilePartProvider) { return std::make_unique(profilePartProvider, *this); } std::unique_ptr ControlModeProfilePart::initializer() { return std::make_unique(*this); } std::string const &ControlModeProfilePart::ID() const { return id_; } std::optional> ControlModeProfilePart::provideImporter(Item const &i) { auto &id = i.ID(); auto partIter = std::find_if( parts_.cbegin(), parts_.cend(), [&](auto const &part) { return part->ID() == id; }); if (partIter != parts_.cend()) { auto importer = dynamic_cast(partIter->get()); if (importer != nullptr) return *importer; } return {}; } bool ControlModeProfilePart::provideActive() const { return active(); } std::string const &ControlModeProfilePart::provideMode() const { return mode_; } void ControlModeProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &pmImporter = dynamic_cast(i); mode(pmImporter.provideMode()); for (auto &part : parts_) { part->importWith(i); // only the selected mode profile part can be active part->activate(part->ID() == mode_); } } void ControlModeProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &pmExporter = dynamic_cast(e); pmExporter.takeMode(mode_); for (auto const &part : parts_) part->exportWith(e); } std::unique_ptr ControlModeProfilePart::cloneProfilePart() const { auto clone = instance(); clone->parts_.reserve(parts_.size()); std::transform( parts_.cbegin(), parts_.cend(), std::back_inserter(clone->parts_), [](std::unique_ptr const &part) { return part->clone(); }); clone->mode_ = mode_; return std::move(clone); } void ControlModeProfilePart::mode(std::string const &mode) { auto iter = std::find_if(parts_.cbegin(), parts_.cend(), [&](auto const &part) { return mode == part->ID(); }); if (iter != parts_.cend()) mode_ = mode; } corectrl-v1.4.2/src/core/components/controls/controlmodeprofilepart.h000066400000000000000000000030701467225065400262510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "controlmode.h" #include "core/profilepart.h" #include #include #include #include class ControlModeProfilePart : public ProfilePart , public ControlMode::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &provideMode() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeMode(std::string const &mode) = 0; }; ControlModeProfilePart(std::string_view id) noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) final override; std::unique_ptr initializer() final override; std::string const &ID() const final override; std::optional> provideImporter(Item const &i) final override; bool provideActive() const final override; std::string const &provideMode() const final override; protected: void importProfilePart(IProfilePart::Importer &i) final override; void exportProfilePart(IProfilePart::Exporter &e) const final override; std::unique_ptr cloneProfilePart() const final override; virtual std::unique_ptr instance() const = 0; private: void mode(std::string const &mode); class Factory; class Initializer; std::vector> parts_; std::string const id_; std::string mode_; }; corectrl-v1.4.2/src/core/components/controls/controlmodeqmlitem.cpp000066400000000000000000000065361467225065400257370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlmodeqmlitem.h" #include "controlmode.h" #include "core/item.h" #include #include #include class ControlModeQMLItem::Initializer final : public QMLItem::Initializer , public ControlMode::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, ControlModeQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeMode(std::string const &mode) override; void takeModes(std::vector const &modes) override; private: ControlModeQMLItem &outer_; }; std::optional> ControlModeQMLItem::Initializer::provideExporter(Item const &i) { return initializer(i.ID(), &outer_).first; } void ControlModeQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void ControlModeQMLItem::Initializer::takeMode(std::string const &mode) { outer_.takeMode(mode); } void ControlModeQMLItem::Initializer::takeModes( std::vector const &modes) { outer_.takeModes(modes); } ControlModeQMLItem::ControlModeQMLItem(std::string_view id) noexcept { setName(tr(id.data())); } void ControlModeQMLItem::changeMode(QString const &mode) { auto newMode = mode.toStdString(); if (mode_ != newMode) { std::swap(mode_, newMode); emit modeChanged(mode); emit settingsChanged(); } } std::optional> ControlModeQMLItem::provideImporter(Item const &i) { auto item = this->findChild(QString::fromStdString(i.ID())); if (item == nullptr) return {}; return dynamic_cast(*item); } std::optional> ControlModeQMLItem::provideExporter(Item const &i) { auto item = this->findChild(QString::fromStdString(i.ID())); if (item == nullptr) return {}; return dynamic_cast(*item); } bool ControlModeQMLItem::provideActive() const { return active_; } std::string const &ControlModeQMLItem::provideMode() const { return mode_; } void ControlModeQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void ControlModeQMLItem::takeMode(std::string const &mode) { if (mode_ != mode) { mode_ = mode; emit modeChanged(QString::fromUtf8(mode_.data())); } } std::unique_ptr ControlModeQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } void ControlModeQMLItem::activate(bool active) { takeActive(active); } void ControlModeQMLItem::takeModes(std::vector const &modes) { QList modeTextVector; for (auto mode : modes) { modeTextVector.push_back(QString::fromStdString(mode)); modeTextVector.push_back(tr(mode.data())); } emit modesChanged(modeTextVector); } corectrl-v1.4.2/src/core/components/controls/controlmodeqmlitem.h000066400000000000000000000025661467225065400254030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "controlmodeprofilepart.h" #include "core/qmlitem.h" #include #include #include #include #include #include class ControlModeQMLItem : public QMLItem , public ControlModeProfilePart::Importer , public ControlModeProfilePart::Exporter { Q_OBJECT public: explicit ControlModeQMLItem(std::string_view id) noexcept; signals: void modeChanged(QString const &mode); void modesChanged(QList const &modes); public slots: void changeMode(QString const &mode); public: std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; std::string const &provideMode() const override; void takeActive(bool active) override; void takeMode(std::string const &mode) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; void activate(bool active) override; private: class Initializer; void takeModes(std::vector const &modes); bool active_; std::string mode_; }; corectrl-v1.4.2/src/core/components/controls/controlmodexmlparser.cpp000066400000000000000000000115141467225065400262740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "controlmodexmlparser.h" #include "core/item.h" #include class ControlModeXMLParser::Factory final : public ProfilePartXMLParser::Factory , public ControlModeProfilePart::Exporter { public: Factory(IProfilePartXMLParserProvider const &profilePartParserProvider, ControlModeXMLParser &outer) noexcept : ProfilePartXMLParser::Factory(profilePartParserProvider) , outer_(outer) { } void takePartParser(Item const &i, std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takeMode(std::string const &) override { } private: ControlModeXMLParser &outer_; }; void ControlModeXMLParser::Factory::takePartParser( Item const &i, std::unique_ptr &&part) { outer_.parsers_.emplace(i.ID(), std::move(part)); } std::optional> ControlModeXMLParser::Factory::provideExporter(Item const &i) { if (i.ID() == outer_.ID()) return *this; else return factory(i); } class ControlModeXMLParser::Initializer final : public ControlModeProfilePart::Exporter { public: Initializer(ControlModeXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeMode(std::string const &mode) override; private: ControlModeXMLParser &outer_; std::unordered_map> initializers_; }; std::optional> ControlModeXMLParser::Initializer::provideExporter(Item const &i) { auto &id = i.ID(); if (outer_.parsers_.count(id) > 0) { if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = outer_.parsers_.at(id)->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } } return {}; } void ControlModeXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void ControlModeXMLParser::Initializer::takeMode(std::string const &mode) { outer_.mode_ = outer_.modeDefault_ = mode; } ControlModeXMLParser::ControlModeXMLParser(std::string_view id) noexcept : ProfilePartXMLParser(id, *this, *this) { } std::unique_ptr ControlModeXMLParser::factory( IProfilePartXMLParserProvider const &profilePartXMLParserProvider) { return std::make_unique( profilePartXMLParserProvider, *this); } std::unique_ptr ControlModeXMLParser::initializer() { return std::make_unique(*this); } std::optional> ControlModeXMLParser::provideExporter(Item const &i) { auto parserIt = parsers_.find(i.ID()); if (parserIt != parsers_.cend()) return parserIt->second->profilePartExporter(); return {}; } std::optional> ControlModeXMLParser::provideImporter(Item const &i) { auto parserIt = parsers_.find(i.ID()); if (parserIt != parsers_.cend()) return parserIt->second->profilePartImporter(); return {}; } void ControlModeXMLParser::takeActive(bool active) { active_ = active; } bool ControlModeXMLParser::provideActive() const { return active_; } void ControlModeXMLParser::takeMode(std::string const &mode) { mode_ = mode; } std::string const &ControlModeXMLParser::provideMode() const { return mode_; } void ControlModeXMLParser::appendTo(pugi::xml_node &parentNode) { auto node = parentNode.append_child(ID().c_str()); node.append_attribute("active") = active_; node.append_attribute("mode") = mode_.c_str(); for (auto &[key, component] : parsers_) component->appendTo(node); } void ControlModeXMLParser::resetAttributes() { active_ = activeDefault(); mode_ = modeDefault(); } void ControlModeXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto node = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = node.attribute("active").as_bool(activeDefault()); mode_ = node.attribute("mode").as_string(modeDefault().c_str()); loadComponents(node); } void ControlModeXMLParser::loadComponents(pugi::xml_node const &parentNode) { for (auto &[key, component] : parsers_) component->loadFrom(parentNode); } bool ControlModeXMLParser::activeDefault() const { return activeDefault_; } std::string const &ControlModeXMLParser::modeDefault() const { return modeDefault_; } corectrl-v1.4.2/src/core/components/controls/controlmodexmlparser.h000066400000000000000000000032031467225065400257350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "controlmodeprofilepart.h" #include "core/profilepartxmlparser.h" #include #include #include #include #include class ControlModeXMLParser : public ProfilePartXMLParser , public ControlModeProfilePart::Exporter , public ControlModeProfilePart::Importer { public: ControlModeXMLParser(std::string_view id) noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) final override; std::optional> provideImporter(Item const &i) final override; void takeActive(bool active) final override; bool provideActive() const final override; void takeMode(std::string const &mode) final override; std::string const &provideMode() const final override; void appendTo(pugi::xml_node &parentNode) final override; protected: void resetAttributes() final override; void loadPartFrom(pugi::xml_node const &parentNode) override; void loadComponents(pugi::xml_node const &parentNode); bool activeDefault() const; std::string const &modeDefault() const; private: class Factory; class Initializer; std::unordered_map> parsers_; bool active_; bool activeDefault_; std::string mode_; std::string modeDefault_; }; corectrl-v1.4.2/src/core/components/controls/cpu/000077500000000000000000000000001467225065400220725ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/cpu/cpufreq.cpp000066400000000000000000000066271467225065400242560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpufreq.h" #include "core/icommandqueue.h" #include #include #include CPUFreq::CPUFreq(std::vector &&scalingGovernors, std::string const &defaultGovernor, std::vector>> &&scalingGovernorDataSources, std::unique_ptr &&eppHandler) noexcept : Control(true) , id_(CPUFreq::ItemID) , scalingGovernors_(std::move(scalingGovernors)) , scalingGovernorDataSources_(std::move(scalingGovernorDataSources)) , eppHandler_(std::move(eppHandler)) { scalingGovernor(defaultGovernor); if (scalingGovernor_.empty()) scalingGovernor(scalingGovernors_.front()); } void CPUFreq::preInit(ICommandQueue &ctlCmds) { if (eppHandler_) // We need to set the EPP scaling governor as the current scaling governor // before the initialization of the EPP handler. syncScalingGovernor(eppScalingGovernor_, ctlCmds); } void CPUFreq::postInit(ICommandQueue &) { } void CPUFreq::init() { if (eppHandler_) eppHandler_->init(); } std::string const &CPUFreq::ID() const { return id_; } void CPUFreq::importControl(IControl::Importer &i) { auto &importer = dynamic_cast(i); scalingGovernor(importer.provideCPUFreqScalingGovernor()); if (eppHandler_) { auto hint = importer.provideCPUFreqEPPHint(); assert(hint.has_value()); eppHandler_->hint(*hint); } } void CPUFreq::exportControl(IControl::Exporter &e) const { auto &exporter = dynamic_cast(e); exporter.takeCPUFreqScalingGovernors(scalingGovernors()); exporter.takeCPUFreqEPPHints(eppHints()); exporter.takeCPUFreqScalingGovernor(scalingGovernor()); exporter.takeCPUFreqEPPHint(eppHint()); } void CPUFreq::cleanControl(ICommandQueue &) { } void CPUFreq::syncControl(ICommandQueue &ctlCmds) { syncScalingGovernor(scalingGovernor(), ctlCmds); if (eppHandler_ && scalingGovernor() == eppScalingGovernor_) eppHandler_->sync(ctlCmds); } std::string const &CPUFreq::scalingGovernor() const { return scalingGovernor_; } void CPUFreq::scalingGovernor(std::string const &scalingGovernor) { // only assign known scalingGovernors auto iter = std::find_if(scalingGovernors().cbegin(), scalingGovernors().cend(), [&](auto const &availableScalingGovernor) { return scalingGovernor == availableScalingGovernor; }); if (iter != scalingGovernors().cend()) scalingGovernor_ = scalingGovernor; } std::vector const &CPUFreq::scalingGovernors() const { return scalingGovernors_; } std::optional CPUFreq::eppHint() const { return eppHandler_ ? std::make_optional(eppHandler_->hint()) : std::nullopt; } std::optional> CPUFreq::eppHints() const { return eppHandler_ ? std::make_optional(eppHandler_->hints()) : std::nullopt; } void CPUFreq::syncScalingGovernor(std::string const &governor, ICommandQueue &ctlCmds) { for (auto &scalingGovernorDataSource : scalingGovernorDataSources_) if (scalingGovernorDataSource->read(dataSourceEntry_)) { if (dataSourceEntry_ != governor) ctlCmds.add({scalingGovernorDataSource->source(), governor}); } } corectrl-v1.4.2/src/core/components/controls/cpu/cpufreq.h000066400000000000000000000047451467225065400237220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/control.h" #include "core/components/controls/cpu/handlers/iepphandler.h" #include "core/idatasource.h" #include #include #include #include #include class CPUFreq : public Control { public: static constexpr std::string_view ItemID{"CPU_CPUFREQ"}; class Importer : public IControl::Importer { public: virtual std::string const &provideCPUFreqScalingGovernor() const = 0; virtual std::optional const &provideCPUFreqEPPHint() const = 0; }; class Exporter : public IControl::Exporter { public: virtual void takeCPUFreqScalingGovernor(std::string const &governor) = 0; virtual void takeCPUFreqScalingGovernors(std::vector const &governors) = 0; virtual void takeCPUFreqEPPHint(std::optional const &hint) = 0; virtual void takeCPUFreqEPPHints(std::optional> const &hints) = 0; }; CPUFreq(std::vector &&scalingGovernors, std::string const &defaultGovernor, std::vector>> &&scalingGovernorDataSources, std::unique_ptr &&eppHandler = nullptr) noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; std::string const &scalingGovernor() const; void scalingGovernor(std::string const &governor); std::vector const &scalingGovernors() const; std::optional eppHint() const; std::optional> eppHints() const; private: void syncScalingGovernor(std::string const &governor, ICommandQueue &ctlCmds); std::string const id_; std::vector const scalingGovernors_; std::vector>> const scalingGovernorDataSources_; std::unique_ptr eppHandler_; std::string const eppScalingGovernor_{"powersave"}; std::string scalingGovernor_; std::string dataSourceEntry_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmode.h000066400000000000000000000007761467225065400245670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmode.h" #include #include #include #include class CPUFreqMode : public ControlMode { public: static constexpr std::string_view ItemID{"CPU_CPUFREQ_MODE"}; CPUFreqMode(std::vector> &&controls) noexcept : ControlMode(CPUFreqMode::ItemID, std::move(controls), true) { } }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodeprofilepart.cpp000066400000000000000000000012161467225065400273600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "cpufreqmodeprofilepart.h" #include "core/profilepartprovider.h" #include "cpufreqmode.h" #include CPUFreqModeProfilePart::CPUFreqModeProfilePart() noexcept : ControlModeProfilePart(CPUFreqMode::ItemID) { } std::unique_ptr CPUFreqModeProfilePart::instance() const { return std::make_unique(); } bool const CPUFreqModeProfilePart::registered_ = ProfilePartProvider::registerProvider(CPUFreqMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodeprofilepart.h000066400000000000000000000006471467225065400270340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmodeprofilepart.h" class CPUFreqModeProfilePart final : public ControlModeProfilePart { public: CPUFreqModeProfilePart() noexcept; protected: std::unique_ptr instance() const override; private: static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodeprovider.cpp000066400000000000000000000033261467225065400266670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "cpufreqmodeprovider.h" #include "core/components/controls/cpucontrolprovider.h" #include "core/components/controls/noop.h" #include "core/info/icpuinfo.h" #include "cpufreqmode.h" std::vector> CPUFreqModeProvider::provideCPUControls(ICPUInfo const &cpuInfo, ISWInfo const &swInfo) const { std::vector> modeControls; for (auto const &provider : cpuControlProviders()) { auto newControls = provider->provideCPUControls(cpuInfo, swInfo); modeControls.insert(modeControls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } if (modeControls.empty()) return {}; modeControls.emplace_back(std::make_unique()); std::vector> controls; controls.emplace_back(std::make_unique(std::move(modeControls))); return controls; } std::vector> const & CPUFreqModeProvider::cpuControlProviders() const { return providers_(); } bool CPUFreqModeProvider::registerProvider( std::unique_ptr &&provider) { providers_().emplace_back(std::move(provider)); return true; } std::vector> & CPUFreqModeProvider::providers_() { static std::vector> providers; return providers; } bool const CPUFreqModeProvider::registered_ = CPUControlProvider::registerProvider(std::make_unique()); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodeprovider.h000066400000000000000000000014641467225065400263350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/icpucontrolprovider.h" #include #include class CPUFreqModeProvider final : public ICPUControlProvider::IProvider , public ICPUControlProvider { public: std::vector> provideCPUControls(ICPUInfo const &cpuInfo, ISWInfo const &swInfo) const override; std::vector> const & cpuControlProviders() const final override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & providers_(); static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodeqmlitem.cpp000066400000000000000000000020251467225065400265000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "cpufreqmodeqmlitem.h" #include "core/qmlcomponentregistry.h" #include "cpufreqmode.h" #include #include #include #include #include CPUFreqModeQMLItem::CPUFreqModeQMLItem() noexcept : ControlModeQMLItem(CPUFreqMode::ItemID) { } bool CPUFreqModeQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, CPUFreqMode::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( CPUFreqMode::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/CPUFreqModeForm.qml")); return qobject_cast(component.create()); }); return true; } bool const CPUFreqModeQMLItem::registered_ = CPUFreqModeQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodeqmlitem.h000066400000000000000000000005431467225065400261500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmodeqmlitem.h" class CPUFreqModeQMLItem : public ControlModeQMLItem { public: explicit CPUFreqModeQMLItem() noexcept; private: static bool register_(); static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodexmlparser.cpp000066400000000000000000000021301467225065400270420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "cpufreqmodexmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "cpufreqmode.h" #include CPUFreqModeXMLParser::CPUFreqModeXMLParser() noexcept : ControlModeXMLParser(CPUFreqMode::ItemID) { } void CPUFreqModeXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto node = parentNode.find_child([&](pugi::xml_node const &node) { return node.name() == CPUFreqMode::ItemID; }); takeActive(node.attribute("active").as_bool(activeDefault())); takeMode(node.attribute("mode").as_string(modeDefault().c_str())); if (!node) { // Legacy control settings might be present in the profile. // The old control settings were attach to this node parent, // so we must pass it in order to load its settings. node = parentNode; } loadComponents(node); } bool const CPUFreqModeXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider(CPUFreqMode::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqmodexmlparser.h000066400000000000000000000006321467225065400265140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/components/controls/controlmodexmlparser.h" class CPUFreqModeXMLParser final : public ControlModeXMLParser { public: CPUFreqModeXMLParser() noexcept; protected: void loadPartFrom(pugi::xml_node const &parentNode) override; private: static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqprofilepart.cpp000066400000000000000000000077761467225065400265340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpufreqprofilepart.h" #include "core/profilepartprovider.h" #include #include #include class CPUFreqProfilePart::Initializer final : public CPUFreq::Exporter { public: Initializer(CPUFreqProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeCPUFreqScalingGovernor(std::string const &governor) override; void takeCPUFreqScalingGovernors(std::vector const &governors) override; void takeCPUFreqEPPHint(std::optional const &hint) override; void takeCPUFreqEPPHints(std::optional> const &hints) override; private: CPUFreqProfilePart &outer_; }; void CPUFreqProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } void CPUFreqProfilePart::Initializer::takeCPUFreqScalingGovernor( std::string const &governor) { outer_.governor_ = governor; } void CPUFreqProfilePart::Initializer::takeCPUFreqScalingGovernors( std::vector const &governors) { outer_.governors_ = governors; } void CPUFreqProfilePart::Initializer::takeCPUFreqEPPHint( std::optional const &hint) { outer_.eppHint_ = hint; } void CPUFreqProfilePart::Initializer::takeCPUFreqEPPHints( std::optional> const &hints) { outer_.eppHints_ = hints; } CPUFreqProfilePart::CPUFreqProfilePart() noexcept : id_(CPUFreq::ItemID) { } std::unique_ptr CPUFreqProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr CPUFreqProfilePart::initializer() { return std::make_unique(*this); } std::string const &CPUFreqProfilePart::ID() const { return id_; } std::optional> CPUFreqProfilePart::provideImporter(Item const &) { return {}; } bool CPUFreqProfilePart::provideActive() const { return active(); } std::string const &CPUFreqProfilePart::provideCPUFreqScalingGovernor() const { return governor_; } std::optional const &CPUFreqProfilePart::provideCPUFreqEPPHint() const { return eppHint_; } void CPUFreqProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &importer = dynamic_cast(i); governor(importer.provideCPUFreqScalingGovernor()); eppHint(importer.provideCPUFreqEPPHint()); } void CPUFreqProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &exporter = dynamic_cast(e); exporter.takeCPUFreqScalingGovernor(governor_); exporter.takeCPUFreqEPPHint(eppHint_); } std::unique_ptr CPUFreqProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->governors_ = governors_; clone->governor_ = governor_; clone->eppHint_ = eppHint_; clone->eppHints_ = eppHints_; return std::move(clone); } void CPUFreqProfilePart::governor(std::string const &governor) { // only import known governors auto iter = std::find_if(governors_.cbegin(), governors_.cend(), [&](auto const &availableGovernor) { return governor == availableGovernor; }); if (iter != governors_.cend()) governor_ = governor; } void CPUFreqProfilePart::eppHint(std::optional const &hint) { if (!hint || !eppHints_) return; // only import known hints auto iter = std::find_if( eppHints_->cbegin(), eppHints_->cend(), [&](auto const &availableHint) { return *hint == availableHint; }); if (iter != eppHints_->cend()) eppHint_ = hint; } bool const CPUFreqProfilePart::registered_ = ProfilePartProvider::registerProvider( CPUFreq::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqprofilepart.h000066400000000000000000000035311467225065400261620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include "cpufreq.h" #include #include #include class CPUFreqProfilePart final : public ProfilePart , public CPUFreq::Importer { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &provideCPUFreqScalingGovernor() const = 0; virtual std::optional const &provideCPUFreqEPPHint() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeCPUFreqScalingGovernor(std::string const &governor) = 0; virtual void takeCPUFreqEPPHint(std::optional const &hint) = 0; }; CPUFreqProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const final override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; std::string const &provideCPUFreqScalingGovernor() const override; std::optional const &provideCPUFreqEPPHint() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void governor(std::string const &governor); void eppHint(std::optional const &hint); class Initializer; std::string const id_; std::string governor_; std::vector governors_; std::optional eppHint_; std::optional> eppHints_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqprovider.cpp000066400000000000000000000126071467225065400260240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpufreqprovider.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/icpuinfo.h" #include "core/sysfsdatasource.h" #include "cpufreq.h" #include "cpufreqmodeprovider.h" #include "handlers/epphandler.h" #include #include #include std::vector> CPUFreqProvider::provideCPUControls(ICPUInfo const &cpuInfo, ISWInfo const &) const { if (!Utils::File::isDirectoryPathValid("/sys/devices/system/cpu/cpufreq")) return {}; auto &executionUnits = cpuInfo.executionUnits(); if (executionUnits.empty()) return {}; auto governors = availableGovernors(cpuInfo); if (governors.empty()) return {}; auto governor = defaultGovernor(cpuInfo, governors); auto scalingGovernorDataSources = createScalingGovernorDataSources(cpuInfo); if (scalingGovernorDataSources.empty()) return {}; std::vector> controls; controls.emplace_back(std::make_unique( std::move(governors), governor, std::move(scalingGovernorDataSources), createEPPHandler(cpuInfo))); return controls; } std::vector CPUFreqProvider::availableGovernors(ICPUInfo const &cpuInfo) const { std::string availableGovernorsPath{"cpufreq/scaling_available_governors"}; // get available governors from the first execution unit auto unitAvailableGovernorsPath = cpuInfo.executionUnits().front().sysPath / availableGovernorsPath; if (!Utils::File::isSysFSEntryValid(unitAvailableGovernorsPath)) return {}; auto lines = Utils::File::readFileLines(unitAvailableGovernorsPath); auto governors = Utils::String::split(lines.front()); // remove not implemented userspace option (see #175) std::erase(governors, "userspace"); return governors; } std::string CPUFreqProvider::defaultGovernor( ICPUInfo const &cpuInfo, std::vector const &governors) const { std::string scalingDriverPath{"cpufreq/scaling_driver"}; std::string fallbackGovernor = governors.front(); // get scaling driver from the first execution unit auto unitScalingDriverPath = cpuInfo.executionUnits().front().sysPath / scalingDriverPath; if (!Utils::File::isSysFSEntryValid(unitScalingDriverPath)) return fallbackGovernor; auto lines = Utils::File::readFileLines(unitScalingDriverPath); if (lines.empty()) return fallbackGovernor; std::string governor("ondemand"); auto driver = lines.front(); if (driver == "intel_pstate") governor = "powersave"; // clamp governor into available governors auto iter = std::find_if(governors.cbegin(), governors.cend(), [&](auto const &availableGovernor) { return governor == availableGovernor; }); if (iter == governors.cend()) return fallbackGovernor; return governor; } std::vector>> CPUFreqProvider::createScalingGovernorDataSources(ICPUInfo const &cpuInfo) const { std::vector>> scalingGovernorDataSources; std::string scalingGovernorPath{"cpufreq/scaling_governor"}; for (auto const &executionUnit : cpuInfo.executionUnits()) { auto unitScalingGovernorPath = executionUnit.sysPath / scalingGovernorPath; if (!Utils::File::isSysFSEntryValid(unitScalingGovernorPath)) continue; scalingGovernorDataSources.emplace_back( std::make_unique>(unitScalingGovernorPath)); } return scalingGovernorDataSources; } std::unique_ptr CPUFreqProvider::createEPPHandler(ICPUInfo const &cpuInfo) const { auto avaiableEPPHintsDataSource = createAvailableHintsDataSource(cpuInfo); if (!avaiableEPPHintsDataSource) return {}; auto eppHintDataSources = createHintDataSources(cpuInfo); if (eppHintDataSources.empty()) return {}; return std::make_unique(std::move(avaiableEPPHintsDataSource), std::move(eppHintDataSources)); } std::unique_ptr> CPUFreqProvider::createAvailableHintsDataSource(ICPUInfo const &cpuInfo) const { std::string availableGovernorsPath{ "cpufreq/energy_performance_available_preferences"}; // available hints will be read from the first execution unit auto availableHintsPath = cpuInfo.executionUnits().front().sysPath / availableGovernorsPath; if (!Utils::File::isSysFSEntryValid(availableHintsPath)) return {}; return std::make_unique>(availableHintsPath); } std::vector>> CPUFreqProvider::createHintDataSources(ICPUInfo const &cpuInfo) const { std::vector>> hintDataSources; std::string hintPath{"cpufreq/energy_performance_preference"}; for (auto const &executionUnit : cpuInfo.executionUnits()) { auto unitHintPath = executionUnit.sysPath / hintPath; if (!Utils::File::isSysFSEntryValid(unitHintPath)) continue; hintDataSources.emplace_back( std::make_unique>(unitHintPath)); } return hintDataSources; } bool const CPUFreqProvider::registered_ = CPUFreqModeProvider::registerProvider(std::make_unique()); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqprovider.h000066400000000000000000000022521467225065400254640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/icpucontrolprovider.h" #include "core/idatasource.h" #include #include #include class IEPPHandler; class CPUFreqProvider final : public ICPUControlProvider::IProvider { public: std::vector> provideCPUControls(ICPUInfo const &cpuInfo, ISWInfo const &swInfo) const override; private: std::vector availableGovernors(ICPUInfo const &cpuInfo) const; std::string defaultGovernor(ICPUInfo const &cpuInfo, std::vector const &governors) const; std::vector>> createScalingGovernorDataSources(ICPUInfo const &cpuInfo) const; std::unique_ptr createEPPHandler(ICPUInfo const &cpuInfo) const; std::unique_ptr> createAvailableHintsDataSource(ICPUInfo const &cpuInfo) const; std::vector>> createHintDataSources(ICPUInfo const &cpuInfo) const; static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqqmlitem.cpp000066400000000000000000000140461467225065400256410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpufreqqmlitem.h" #include "core/qmlcomponentregistry.h" #include "cpufreq.h" #include #include #include #include char const *const CPUFreqQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "CPU_CPUFREQ"), // XXX add cpufreq scaling governors here QT_TRANSLATE_NOOP("CPUFreqQMLItem", "performance"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "powersave"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "schedutil"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "ondemand"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "conservative"), // XXX add CPU EPP available hints here QT_TRANSLATE_NOOP("CPUFreqQMLItem", "default"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "performance"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "balance_performance"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "balance_power"), QT_TRANSLATE_NOOP("CPUFreqQMLItem", "power"), }; class CPUFreqQMLItem::Initializer final : public QMLItem::Initializer , public CPUFreq::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, CPUFreqQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeCPUFreqScalingGovernor(std::string const &governor) override; void takeCPUFreqScalingGovernors(std::vector const &governors) override; void takeCPUFreqEPPHint(std::optional const &hint) override; void takeCPUFreqEPPHints( std::optional> const &hints) override; private: CPUFreqQMLItem &outer_; }; void CPUFreqQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void CPUFreqQMLItem::Initializer::takeCPUFreqScalingGovernor( std::string const &governor) { outer_.takeCPUFreqScalingGovernor(governor); } void CPUFreqQMLItem::Initializer::takeCPUFreqScalingGovernors( std::vector const &governors) { outer_.takeCPUFreqScalingGovernors(governors); } void CPUFreqQMLItem::Initializer::takeCPUFreqEPPHint( std::optional const &hint) { outer_.takeCPUFreqEPPHint(hint); } void CPUFreqQMLItem::Initializer::takeCPUFreqEPPHints( std::optional> const &hints) { outer_.takeCPUFreqEPPHints(hints); } CPUFreqQMLItem::CPUFreqQMLItem() noexcept { setName(tr(CPUFreq::ItemID.data())); } void CPUFreqQMLItem::changeScalingGovernor(QString const &governor) { auto newScalingGovernor = governor.toStdString(); if (scalingGovernor_ != newScalingGovernor) { std::swap(scalingGovernor_, newScalingGovernor); emit scalingGovernorChanged(governor); emit toggleEppHint(enableEpp_ && scalingGovernor_ == eppScalingGovernor_); emit settingsChanged(); } } void CPUFreqQMLItem::changeEPPHint(QString const &hint) { auto newHint = hint.toStdString(); if (eppHint_ && eppHint_ != newHint) { std::swap(*eppHint_, newHint); emit eppHintChanged(hint); emit settingsChanged(); } } void CPUFreqQMLItem::activate(bool active) { takeActive(active); } std::optional> CPUFreqQMLItem::provideImporter(Item const &) { return {}; } std::optional> CPUFreqQMLItem::provideExporter(Item const &) { return {}; } bool CPUFreqQMLItem::provideActive() const { return active_; } std::string const &CPUFreqQMLItem::provideCPUFreqScalingGovernor() const { return scalingGovernor_; } std::optional const &CPUFreqQMLItem::provideCPUFreqEPPHint() const { return eppHint_; } void CPUFreqQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } void CPUFreqQMLItem::takeCPUFreqScalingGovernor(std::string const &governor) { if (scalingGovernor_ != governor) { scalingGovernor_ = governor; emit scalingGovernorChanged(QString::fromStdString(scalingGovernor_)); emit toggleEppHint(enableEpp_ && scalingGovernor_ == eppScalingGovernor_); } } void CPUFreqQMLItem::takeCPUFreqEPPHint(std::optional const &hint) { if (hint && eppHint_ != hint) { eppHint_ = hint; emit eppHintChanged(QString::fromStdString(*eppHint_)); } } std::unique_ptr CPUFreqQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } void CPUFreqQMLItem::takeCPUFreqScalingGovernors( std::vector const &governors) { QList governorTextVector; for (auto governor : governors) { governorTextVector.push_back(QString::fromStdString(governor)); governorTextVector.push_back(tr(governor.data())); } emit scalingGovernorsChanged(governorTextVector); } void CPUFreqQMLItem::takeCPUFreqEPPHints( std::optional> const &hints) { if (!hints) return; enableEpp_ = true; QList hintTextVector; for (auto hint : *hints) { hintTextVector.push_back(QString::fromStdString(hint)); hintTextVector.push_back(tr(hint.data())); } emit eppHintsChanged(hintTextVector); } bool CPUFreqQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, CPUFreq::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( CPUFreq::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/CPUFreqForm.qml")); return qobject_cast(component.create()); }); return true; } bool const CPUFreqQMLItem::registered_ = CPUFreqQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqqmlitem.h000066400000000000000000000040701467225065400253020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "cpufreqprofilepart.h" #include #include #include #include #include #include class CPUFreqQMLItem : public QMLItem , public CPUFreqProfilePart::Importer , public CPUFreqProfilePart::Exporter { Q_OBJECT public: explicit CPUFreqQMLItem() noexcept; signals: void scalingGovernorChanged(QString const &governor); void scalingGovernorsChanged(QList const &governors); void eppHintChanged(QString const &hint); void eppHintsChanged(QList const &hints); void toggleEppHint(bool enable); public slots: void changeScalingGovernor(QString const &governor); void changeEPPHint(QString const &hint); public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; std::string const &provideCPUFreqScalingGovernor() const override; std::optional const &provideCPUFreqEPPHint() const override; void takeActive(bool active) override; void takeCPUFreqScalingGovernor(std::string const &governor) override; void takeCPUFreqEPPHint(std::optional const &hint) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; void takeCPUFreqScalingGovernors(std::vector const &governors); void takeCPUFreqEPPHints(std::optional> const &hints); bool active_; std::string scalingGovernor_; std::string const eppScalingGovernor_{"powersave"}; std::optional eppHint_; bool enableEpp_{false}; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqxmlparser.cpp000066400000000000000000000066541467225065400262140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpufreqxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "cpufreq.h" #include class CPUFreqXMLParser::Initializer final : public CPUFreqProfilePart::Exporter { public: Initializer(CPUFreqXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeCPUFreqScalingGovernor(std::string const &governor) override; void takeCPUFreqEPPHint(std::optional const &hint) override; private: CPUFreqXMLParser &outer_; }; void CPUFreqXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void CPUFreqXMLParser::Initializer::takeCPUFreqScalingGovernor( std::string const &governor) { outer_.scalingGovernor_ = outer_.scalingGovernorDefault_ = governor; } void CPUFreqXMLParser::Initializer::takeCPUFreqEPPHint( std::optional const &hint) { outer_.eppHint_ = outer_.eppHintDefault_ = hint; } CPUFreqXMLParser::CPUFreqXMLParser() noexcept : ProfilePartXMLParser(CPUFreq::ItemID, *this, *this) { } std::unique_ptr CPUFreqXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr CPUFreqXMLParser::initializer() { return std::make_unique(*this); } std::optional> CPUFreqXMLParser::provideExporter(Item const &) { return {}; } std::optional> CPUFreqXMLParser::provideImporter(Item const &) { return {}; } void CPUFreqXMLParser::takeActive(bool active) { active_ = active; } bool CPUFreqXMLParser::provideActive() const { return active_; } void CPUFreqXMLParser::takeCPUFreqScalingGovernor(std::string const &governor) { scalingGovernor_ = governor; } std::string const &CPUFreqXMLParser::provideCPUFreqScalingGovernor() const { return scalingGovernor_; } void CPUFreqXMLParser::takeCPUFreqEPPHint(std::optional const &hint) { eppHint_ = hint; } std::optional const &CPUFreqXMLParser::provideCPUFreqEPPHint() const { return eppHint_; } void CPUFreqXMLParser::appendTo(pugi::xml_node &parentNode) { auto node = parentNode.append_child(ID().c_str()); node.append_attribute("active") = active_; node.append_attribute("scalingGovernor") = scalingGovernor_.c_str(); if (eppHintDefault_) node.append_attribute("eppHint") = eppHint_->c_str(); } void CPUFreqXMLParser::resetAttributes() { active_ = activeDefault_; scalingGovernor_ = scalingGovernorDefault_; eppHint_ = eppHintDefault_; } void CPUFreqXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto node = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = node.attribute("active").as_bool(activeDefault_); scalingGovernor_ = node.attribute("scalingGovernor").as_string(scalingGovernorDefault_.c_str()); if (eppHintDefault_) eppHint_ = node.attribute("eppHint").as_string(scalingGovernorDefault_.c_str()); } bool const CPUFreqXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( CPUFreq::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/cpu/cpufreqxmlparser.h000066400000000000000000000031561467225065400256530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "cpufreqprofilepart.h" #include #include class CPUFreqXMLParser final : public ProfilePartXMLParser , public CPUFreqProfilePart::Exporter , public CPUFreqProfilePart::Importer { public: CPUFreqXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takeCPUFreqScalingGovernor(std::string const &governor) override; std::string const &provideCPUFreqScalingGovernor() const override; void takeCPUFreqEPPHint(std::optional const &hint) override; std::optional const &provideCPUFreqEPPHint() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; std::string const id_; bool active_; bool activeDefault_; std::string scalingGovernor_; std::string scalingGovernorDefault_; std::optional eppHint_; std::optional eppHintDefault_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/cpu/handlers/000077500000000000000000000000001467225065400236725ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/controls/cpu/handlers/epphandler.cpp000066400000000000000000000031511467225065400265200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2024 Juan Palacios #include "epphandler.h" #include "common/stringutils.h" #include "core/icommandqueue.h" #include #include EPPHandler::EPPHandler( std::unique_ptr> &&avaiableEPPHintsDataSource, std::vector>> &&eppHintDataSources) noexcept : avaiableEPPHintsDataSource_(std::move(avaiableEPPHintsDataSource)) , eppHintDataSources_(std::move(eppHintDataSources)) { } std::string const &EPPHandler::hint() const { return hint_; } void EPPHandler::hint(std::string const &eppHint) { // only assign known EPP hints auto iter = std::find_if( hints().cbegin(), hints().cend(), [&](auto const &availableHint) { return eppHint == availableHint; }); if (iter != hints().cend()) hint_ = eppHint; } std::vector const &EPPHandler::hints() const { return hints_; } void EPPHandler::init() { if (avaiableEPPHintsDataSource_->read(dataSourceEntry_)) { // set available hints hints_ = Utils::String::split(dataSourceEntry_); // set default hint hint("default"); if (hint_.empty()) hint(hints_.front()); } } void EPPHandler::saveState() { } void EPPHandler::restoreState(ICommandQueue &) { } void EPPHandler::reset(ICommandQueue &) { } void EPPHandler::sync(ICommandQueue &ctlCmds) { for (auto &eppHintDataSource : eppHintDataSources_) if (eppHintDataSource->read(dataSourceEntry_)) { if (dataSourceEntry_ != hint()) ctlCmds.add({eppHintDataSource->source(), hint()}); } } corectrl-v1.4.2/src/core/components/controls/cpu/handlers/epphandler.h000066400000000000000000000021221467225065400261620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2024 Juan Palacios #pragma once #include "core/idatasource.h" #include "iepphandler.h" #include #include #include class EPPHandler : public IEPPHandler { public: EPPHandler(std::unique_ptr> &&avaiableEPPHintsDataSource, std::vector>> &&eppHintDataSources) noexcept; std::string const &hint() const override; void hint(std::string const &hint) override; std::vector const &hints() const override; virtual void init() override; void saveState() override; void restoreState(ICommandQueue &ctlCmds) override; void reset(ICommandQueue &ctlCmds) override; void sync(ICommandQueue &ctlCmds) override; private: std::unique_ptr> const avaiableEPPHintsDataSource_; std::vector>> const eppHintDataSources_; std::vector hints_; std::string hint_; std::string dataSourceEntry_; }; corectrl-v1.4.2/src/core/components/controls/cpu/handlers/iepphandler.h000066400000000000000000000007571467225065400263470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2024 Juan Palacios #pragma once #include "core/components/controls/idatasourcehandler.h" #include #include class IEPPHandler : public IDataSourceHandler { public: virtual std::vector const &hints() const = 0; virtual std::string const &hint() const = 0; virtual void hint(std::string const &hint) = 0; virtual void init() = 0; virtual ~IEPPHandler() = default; }; corectrl-v1.4.2/src/core/components/controls/cpucontrolprovider.cpp000066400000000000000000000013051467225065400257510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpucontrolprovider.h" #include std::vector> const & CPUControlProvider::cpuControlProviders() const { return cpuControlProviders_(); } std::vector> & CPUControlProvider::cpuControlProviders_() { static std::vector> providers; return providers; } bool CPUControlProvider::registerProvider( std::unique_ptr &&provider) { cpuControlProviders_().emplace_back(std::move(provider)); return true; } corectrl-v1.4.2/src/core/components/controls/cpucontrolprovider.h000066400000000000000000000011001467225065400254070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icpucontrolprovider.h" #include #include class CPUControlProvider final : public ICPUControlProvider { public: std::vector> const & cpuControlProviders() const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & cpuControlProviders_(); }; corectrl-v1.4.2/src/core/components/controls/gpucontrolprovider.cpp000066400000000000000000000013051467225065400257550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpucontrolprovider.h" #include std::vector> const & GPUControlProvider::gpuControlProviders() const { return gpuControlProviders_(); } std::vector> & GPUControlProvider::gpuControlProviders_() { static std::vector> providers; return providers; } bool GPUControlProvider::registerProvider( std::unique_ptr &&provider) { gpuControlProviders_().emplace_back(std::move(provider)); return true; } corectrl-v1.4.2/src/core/components/controls/gpucontrolprovider.h000066400000000000000000000011001467225065400254130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "igpucontrolprovider.h" #include #include class GPUControlProvider final : public IGPUControlProvider { public: std::vector> const & gpuControlProviders() const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & gpuControlProviders_(); }; corectrl-v1.4.2/src/core/components/controls/icontrol.h000066400000000000000000000020051467225065400233020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/exportable.h" #include "core/importable.h" #include "core/item.h" class ICommandQueue; class IControl : public Item , public Importable , public Exportable { public: class Importer : public Importable::Importer { public: virtual bool provideActive() const = 0; }; class Exporter : public Exportable::Exporter { public: virtual void takeActive(bool active) = 0; }; virtual void preInit(ICommandQueue &ctlCmds) = 0; virtual void postInit(ICommandQueue &ctlCmds) = 0; virtual void init() = 0; virtual bool active() const = 0; virtual void activate(bool active) = 0; /// Cleans the control unconditionally on the next clean method /// call, independently of its previous active state. virtual void cleanOnce() = 0; virtual void clean(ICommandQueue &ctlCmds) = 0; virtual void sync(ICommandQueue &ctlCmds) = 0; virtual ~IControl() = default; }; corectrl-v1.4.2/src/core/components/controls/icpucontrolprovider.h000066400000000000000000000014201467225065400255650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class IControl; class ICPUInfo; class ISWInfo; class ICPUControlProvider { public: /// Classes that provides instances of Control specializations must implement /// this interface. class IProvider { public: /// Returns a list with the CPU controls supported by the provider. virtual std::vector> provideCPUControls(ICPUInfo const &cpuInfo, ISWInfo const &swInfo) const = 0; virtual ~IProvider() = default; }; virtual std::vector> const & cpuControlProviders() const = 0; virtual ~ICPUControlProvider() = default; }; corectrl-v1.4.2/src/core/components/controls/idatasourcehandler.h000066400000000000000000000011661467225065400253210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once class ICommandQueue; class IDataSourceHandler { public: /// Save the state of the data source. virtual void saveState() = 0; /// Queue commands to restore the saved data surce state. virtual void restoreState(ICommandQueue &ctlCmds) = 0; /// Queue commands to reset the data source. virtual void reset(ICommandQueue &ctlCmds) = 0; /// Queue commands to sync the handler state with the data source. virtual void sync(ICommandQueue &ctlCmds) = 0; virtual ~IDataSourceHandler() = default; }; corectrl-v1.4.2/src/core/components/controls/igpucontrolprovider.h000066400000000000000000000014201467225065400255710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class IControl; class IGPUInfo; class ISWInfo; class IGPUControlProvider { public: /// Classes that provides instances of Control specializations must /// implement this interface. class IProvider { public: /// Returns a list with the GPU controls supported by the provider. virtual std::vector> provideGPUControls(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const = 0; virtual ~IProvider() = default; }; virtual std::vector> const & gpuControlProviders() const = 0; virtual ~IGPUControlProvider() = default; }; corectrl-v1.4.2/src/core/components/controls/noop.cpp000066400000000000000000000010421467225065400227570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "noop.h" Noop::Noop() noexcept : Control(true) , id_(Noop::ItemID) { } void Noop::preInit(ICommandQueue &) { } void Noop::postInit(ICommandQueue &) { } void Noop::init() { } std::string const &Noop::ID() const { return id_; } void Noop::importControl(IControl::Importer &) { } void Noop::exportControl(IControl::Exporter &) const { } void Noop::cleanControl(ICommandQueue &) { } void Noop::syncControl(ICommandQueue &) { } corectrl-v1.4.2/src/core/components/controls/noop.h000066400000000000000000000014141467225065400224270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "control.h" #include #include class Noop : public Control { public: static constexpr std::string_view ItemID{"NOOP"}; Noop() noexcept; void preInit(ICommandQueue &ctlCmds) final override; void postInit(ICommandQueue &ctlCmds) final override; void init() final override; std::string const &ID() const final override; protected: void importControl(IControl::Importer &i) final override; void exportControl(IControl::Exporter &e) const final override; void cleanControl(ICommandQueue &ctlCmds) final override; void syncControl(ICommandQueue &ctlCmds) final override; private: std::string const id_; }; corectrl-v1.4.2/src/core/components/controls/noopprofilepart.cpp000066400000000000000000000031601467225065400252320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "noopprofilepart.h" #include "core/profilepartprovider.h" #include class NoopProfilePart::Initializer final : public Noop::Exporter { public: Initializer(NoopProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: NoopProfilePart &outer_; }; void NoopProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } NoopProfilePart::NoopProfilePart() noexcept : id_(Noop::ItemID) { } std::unique_ptr NoopProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr NoopProfilePart::initializer() { return std::make_unique(*this); } std::string const &NoopProfilePart::ID() const { return id_; } std::optional> NoopProfilePart::provideImporter(Item const &) { return {}; } bool NoopProfilePart::provideActive() const { return active(); } void NoopProfilePart::importProfilePart(IProfilePart::Importer &) { } void NoopProfilePart::exportProfilePart(IProfilePart::Exporter &) const { } std::unique_ptr NoopProfilePart::cloneProfilePart() const { return std::make_unique(); } bool const NoopProfilePart::registered_ = ProfilePartProvider::registerProvider( Noop::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/noopprofilepart.h000066400000000000000000000020741467225065400247020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepart.h" #include "noop.h" #include class NoopProfilePart final : public ProfilePart , public Noop::Importer { public: class Importer : public IProfilePart::Importer { }; class Exporter : public IProfilePart::Exporter { }; NoopProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: class Initializer; std::string const id_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/controls/noopqmlitem.cpp000066400000000000000000000046701467225065400243620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "noopqmlitem.h" #include "core/qmlcomponentregistry.h" #include "noop.h" #include #include #include #include #include #include char const *const NoopQMLItem::trStrings[] = { QT_TRANSLATE_NOOP("ControlModeQMLItem", "NOOP"), }; class NoopQMLItem::Initializer final : public QMLItem::Initializer , public IControl::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, NoopQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: NoopQMLItem &outer_; }; void NoopQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } NoopQMLItem::NoopQMLItem() noexcept { setName(tr(Noop::ItemID.data())); } void NoopQMLItem::activate(bool active) { takeActive(active); } std::optional> NoopQMLItem::provideImporter(Item const &) { return {}; } std::optional> NoopQMLItem::provideExporter(Item const &) { return {}; } bool NoopQMLItem::provideActive() const { return active_; } void NoopQMLItem::takeActive(bool active) { active_ = active; setVisible(active); } std::unique_ptr NoopQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } bool NoopQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, Noop::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( Noop::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/NoopForm.qml")); return qobject_cast(component.create()); }); return true; } bool const NoopQMLItem::registered_ = NoopQMLItem::register_(); corectrl-v1.4.2/src/core/components/controls/noopqmlitem.h000066400000000000000000000017541467225065400240270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/qmlitem.h" #include "noopprofilepart.h" #include class NoopQMLItem : public QMLItem , public NoopProfilePart::Importer , public NoopProfilePart::Exporter { Q_OBJECT public: explicit NoopQMLItem() noexcept; void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; void takeActive(bool active) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; bool active_; static bool register_(); static bool const registered_; static char const *const trStrings[]; }; corectrl-v1.4.2/src/core/components/controls/noopxmlparser.cpp000066400000000000000000000040601467225065400247200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "noopxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "noop.h" #include class NoopXMLParser::Initializer final : public NoopProfilePart::Exporter { public: Initializer(NoopXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; private: NoopXMLParser &outer_; }; void NoopXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } NoopXMLParser::NoopXMLParser() noexcept : ProfilePartXMLParser(Noop::ItemID, *this, *this) { } std::unique_ptr NoopXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr NoopXMLParser::initializer() { return std::make_unique(*this); } std::optional> NoopXMLParser::provideExporter(Item const &) { return {}; } std::optional> NoopXMLParser::provideImporter(Item const &) { return {}; } void NoopXMLParser::takeActive(bool active) { active_ = active; } bool NoopXMLParser::provideActive() const { return active_; } void NoopXMLParser::appendTo(pugi::xml_node &parentNode) { auto pmFixedNode = parentNode.append_child(ID().c_str()); pmFixedNode.append_attribute("active") = active_; } void NoopXMLParser::resetAttributes() { active_ = activeDefault_; } void NoopXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto pmFixedNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = pmFixedNode.attribute("active").as_bool(activeDefault_); } bool const NoopXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( Noop::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/controls/noopxmlparser.h000066400000000000000000000021311467225065400243620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "noopprofilepart.h" class NoopXMLParser final : public ProfilePartXMLParser , public NoopProfilePart::Exporter , public NoopProfilePart::Importer { public: NoopXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/cpu.cpp000066400000000000000000000061211467225065400207330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpu.h" #include "controls/icontrol.h" #include "core/info/icpuinfo.h" #include "sensors/isensor.h" #include CPU::CPU(std::unique_ptr &&info, std::vector> &&controls, std::vector> &&sensors) noexcept : id_(ICPU::ItemID) , info_(std::move(info)) , controls_(std::move(controls)) , sensors_(std::move(sensors)) { key_ = "CPU" + std::to_string(info_->physicalId()); } bool CPU::active() const { return active_; } void CPU::activate(bool active) { active_ = active; } std::string const &CPU::key() const { return key_; } std::pair>> CPU::componentInfo() const { std::pair>> info; auto name(info_->info(ICPUInfo::Keys::modelName)); if (!name.empty()) name.append("\n"); name.append("[CPU ").append(std::to_string(info_->physicalId())).append("]"); info.first = name; auto infoKeys = info_->keys(); for (auto &infoKey : infoKeys) info.second.emplace_back(infoKey, info_->info(infoKey)); return info; } void CPU::init() { for (auto &control : controls_) control->init(); } void CPU::preInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->preInit(ctlCmds); } void CPU::postInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->postInit(ctlCmds); } void CPU::sync(ICommandQueue &ctlCmds) { if (active_) { // NOTE clean and sync commands generation cannot be interleaved. // Interleaving them could cause conflicts between clean and sync // commands of different controls, leading to an incorrect hardware // state. for (auto &control : controls_) control->clean(ctlCmds); for (auto &control : controls_) control->sync(ctlCmds); } } void CPU::updateSensors( std::unordered_map> const &ignored) { for (auto &sensor : sensors_) { if (ignored.count(key_) > 0 && ignored.at(key_).count(sensor->ID()) > 0) continue; // skip ignored sensors sensor->update(); } } ICPUInfo const &CPU::info() const { return *info_; } std::string const &CPU::ID() const { return id_; } void CPU::importWith(Importable::Importer &i) { auto importer = i.provideImporter(*this); if (importer.has_value()) { auto &cpuImporter = dynamic_cast(importer->get()); activate(cpuImporter.provideActive()); for (auto &control : controls_) control->importWith(*importer); } } void CPU::exportWith(Exportable::Exporter &e) const { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { auto &cpuExporter = dynamic_cast(exporter->get()); cpuExporter.takeActive(active()); cpuExporter.takeInfo(info()); for (auto const &sensor : sensors_) cpuExporter.takeSensor(*sensor); for (auto const &control : controls_) control->exportWith(*exporter); } } corectrl-v1.4.2/src/core/components/cpu.h000066400000000000000000000025511467225065400204030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icpu.h" #include #include #include class IControl; class ISensor; class CPU final : public ICPU { public: CPU(std::unique_ptr &&info, std::vector> &&controls, std::vector> &&sensors) noexcept; bool active() const override; void activate(bool active) override; std::string const &key() const override; std::pair>> componentInfo() const override; void init() override; void preInit(ICommandQueue &ctlCmds) override; void postInit(ICommandQueue &ctlCmds) override; void sync(ICommandQueue &ctlCmds) override; void updateSensors( std::unordered_map> const &ignored) override; ICPUInfo const &info() const override; std::string const &ID() const override; void importWith(Importable::Importer &i) override; void exportWith(Exportable::Exporter &e) const override; private: std::string const id_; std::unique_ptr const info_; std::vector> const controls_; std::vector> const sensors_; std::string key_; bool active_{true}; }; corectrl-v1.4.2/src/core/components/cpuprofilepart.cpp000066400000000000000000000122751467225065400232120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuprofilepart.h" #include "core/info/icpuinfo.h" #include "core/profilepart.h" #include "core/profilepartprovider.h" #include "sensors/isensor.h" #include #include #include #include class CPUProfilePart::Factory final : public ProfilePart::Factory , public ICPU::Exporter { public: Factory(IProfilePartProvider const &profilePartProvider, CPUProfilePart &outer) noexcept : ProfilePart::Factory(profilePartProvider) , outer_(outer) { } void takeProfilePart(std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takeInfo(ICPUInfo const &) override; void takeSensor(ISensor const &) override; private: CPUProfilePart &outer_; }; void CPUProfilePart::Factory::takeProfilePart(std::unique_ptr &&part) { outer_.parts_.emplace_back(std::move(part)); } std::optional> CPUProfilePart::Factory::provideExporter(Item const &i) { return factory(i.ID()); } void CPUProfilePart::Factory::takeInfo(ICPUInfo const &info) { // NOTE info and system component key must be initialized here outer_.physicalId_ = info.physicalId(); outer_.updateKey(); } void CPUProfilePart::Factory::takeSensor(ISensor const &sensor) { auto sensorProfilePart = createPart(sensor.ID()); if (sensorProfilePart != nullptr) outer_.parts_.emplace_back(std::move(sensorProfilePart)); } class CPUProfilePart::Initializer final : public ICPU::Exporter { public: Initializer(CPUProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(ICPUInfo const &) override { } void takeSensor(ISensor const &) override { } private: CPUProfilePart &outer_; std::unordered_map> initializers_; }; std::optional> CPUProfilePart::Initializer::provideExporter(Item const &i) { for (auto &part : outer_.parts_) { auto &id = part->ID(); if (id == i.ID()) { if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = part->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } break; } } return {}; } void CPUProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } CPUProfilePart::CPUProfilePart() noexcept : id_(ICPU::ItemID) { } std::unique_ptr CPUProfilePart::factory(IProfilePartProvider const &profilePartProvider) { return std::make_unique(profilePartProvider, *this); } std::unique_ptr CPUProfilePart::initializer() { return std::make_unique(*this); } std::string const &CPUProfilePart::ID() const { return id_; } bool CPUProfilePart::belongsTo(Item const &i) const { auto cpu = dynamic_cast(&i); if (cpu != nullptr) return cpu->info().physicalId() == physicalId_; return false; } std::string const &CPUProfilePart::key() const { return key_; } std::optional> CPUProfilePart::provideImporter(Item const &i) { auto &id = i.ID(); auto partIter = std::find_if( parts_.cbegin(), parts_.cend(), [&](auto const &part) { return part->ID() == id; }); if (partIter != parts_.cend()) { auto importer = dynamic_cast(partIter->get()); if (importer != nullptr) return *importer; } return {}; } bool CPUProfilePart::provideActive() const { return active(); } void CPUProfilePart::importProfilePart(IProfilePart::Importer &i) { int oldPhysicalId = physicalId_; auto &partImporter = dynamic_cast(i); physicalId_ = partImporter.providePhysicalId(); if (oldPhysicalId != physicalId_) updateKey(); for (auto &part : parts_) part->importWith(i); } void CPUProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &partExporter = dynamic_cast(e); partExporter.takePhysicalId(physicalId_); for (auto const &part : parts_) part->exportWith(e); } std::unique_ptr CPUProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->physicalId_ = physicalId_; clone->key_ = key_; clone->parts_.reserve(parts_.size()); std::transform(parts_.cbegin(), parts_.cend(), std::back_inserter(clone->parts_), [](auto const &part) { return part->clone(); }); return std::move(clone); } void CPUProfilePart::updateKey() { key_ = "CPU" + std::to_string(physicalId_); } bool const CPUProfilePart::registered_ = ProfilePartProvider::registerProvider( ICPU::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/cpuprofilepart.h000066400000000000000000000023121467225065400226460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icpu.h" #include "icpuprofilepart.h" #include #include #include class CPUProfilePart final : public ICPUProfilePart , public ICPU::Importer { public: CPUProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; bool belongsTo(Item const &i) const override; std::string const &key() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void updateKey(); class Factory; class Initializer; std::vector> parts_; std::string const id_; int physicalId_; std::string key_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/cpuqmlitem.cpp000066400000000000000000000075241467225065400223340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuqmlitem.h" #include "core/info/icpuinfo.h" #include "core/iqmlcomponentfactory.h" #include "core/qmlcomponentregistry.h" #include "icpu.h" #include "sensors/graphitem.h" #include "sensors/isensor.h" #include #include #include #include #include #include #include #include #include class CPUQMLItem::Initializer final : public QMLItem::Initializer , public ICPU::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, CPUQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(ICPUInfo const &info) override; void takeSensor(ISensor const &sensor) override; private: CPUQMLItem &outer_; }; std::optional> CPUQMLItem::Initializer::provideExporter(Item const &i) { return initializer(i.ID(), &outer_).first; } void CPUQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void CPUQMLItem::Initializer::takeInfo(ICPUInfo const &info) { auto name(info.info(ICPUInfo::Keys::modelName)); if (!name.empty()) name.append("\n"); name.append("[CPU ").append(std::to_string(info.physicalId())).append("]"); outer_.setName(QString::fromStdString(name)); outer_.takePhysicalId(info.physicalId()); } void CPUQMLItem::Initializer::takeSensor(ISensor const &sensor) { auto graphItem = dynamic_cast( qmlComponentFactory_.createQuickItem(sensor.ID(), &outer_, "SensorGraph")); if (graphItem != nullptr) { connect(graphItem, &GraphItem::settingsChanged, &outer_, &QMLItem::settingsChanged, Qt::UniqueConnection); graphItem->init(&sensor); emit outer_.newGraphItem(graphItem); } } void CPUQMLItem::activate(bool active) { takeActive(active); } std::optional> CPUQMLItem::provideImporter(Item const &i) { auto item = this->findChild(QString::fromStdString(i.ID())); if (item == nullptr) return {}; return dynamic_cast(*item); } std::optional> CPUQMLItem::provideExporter(Item const &i) { auto item = this->findChild(QString::fromStdString(i.ID())); if (item == nullptr) return {}; return dynamic_cast(*item); } bool CPUQMLItem::provideActive() const { return active_; } int CPUQMLItem::providePhysicalId() const { return physicalId_; } void CPUQMLItem::takeActive(bool active) { active_ = active; setEnabled(active); } void CPUQMLItem::takePhysicalId(int id) { physicalId_ = id; } std::unique_ptr CPUQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } bool CPUQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, ICPU::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( ICPU::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/CPUForm.qml")); return qobject_cast(component.create()); }); return true; } bool const CPUQMLItem::registered_ = CPUQMLItem::register_(); corectrl-v1.4.2/src/core/components/cpuqmlitem.h000066400000000000000000000021741467225065400217750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "icpuprofilepart.h" #include class QQuickItem; class CPUQMLItem : public QMLItem , public ICPUProfilePart::Importer , public ICPUProfilePart::Exporter { Q_OBJECT Q_PROPERTY(int physicalId READ providePhysicalId) public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; int providePhysicalId() const override; void takeActive(bool active) override; void takePhysicalId(int id) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; signals: void newGraphItem(QQuickItem *item); private: class Initializer; bool active_; int physicalId_; static bool register_(); static bool const registered_; }; corectrl-v1.4.2/src/core/components/cpuutils.cpp000066400000000000000000000063011467225065400220140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuutils.h" #include "common/stringutils.h" #include #include #include namespace Utils::CPU { std::optional parseProcCpuInfo(std::vector const &procCpuInfoLines, int cpuId, std::string_view target) { static constexpr std::string_view cpuIdStr{"processor"}; auto lineIt = std::find_if( procCpuInfoLines.cbegin(), procCpuInfoLines.cend(), [=](std::string const &line) { if (line.find(cpuIdStr) != std::string::npos) { int value; auto idPos = line.find_first_not_of("\t: ", cpuIdStr.size()); return idPos != std::string::npos && Utils::String::toNumber(value, line.substr(idPos)) && value == cpuId; } return false; }); if (lineIt != procCpuInfoLines.cend()) { lineIt = std::next(lineIt); for (; lineIt != procCpuInfoLines.cend(); lineIt = std::next(lineIt)) { if (lineIt->empty()) break; // target not found on this processor section auto targetPos = lineIt->find(target); if (targetPos != std::string::npos) { auto dataPos = lineIt->find_first_not_of("\t: ", target.size()); if (dataPos != std::string::npos) return lineIt->substr(dataPos); } } } return {}; } std::optional parseProcStat(std::vector const &procStatLines) { // CPU aggregate line columns: // cpu user nice system idle io_wait irq soft_irq steal guest guest_nice // // NOTE guest and guest_nice values are already included into user and nice. // https://github.com/torvalds/linux/blob/master/kernel/sched/cputime.c#L143?h=5.0 static std::regex const regex( R"(^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+\s+\d+\s*$)", std::regex::icase); for (auto const &line : procStatLines) { std::smatch result; if (std::regex_match(line, result, regex)) { std::uint64_t user{0}, nice{0}, system{0}, idle{0}, ioWait{0}, irq{0}, softIrq{0}, steal{0}, total{0}; if (Utils::String::toNumber(user, result[1]) && Utils::String::toNumber(nice, result[2]) && Utils::String::toNumber(system, result[3]) && Utils::String::toNumber(idle, result[4]) && Utils::String::toNumber(ioWait, result[5]) && Utils::String::toNumber(irq, result[6]) && Utils::String::toNumber(softIrq, result[7]) && Utils::String::toNumber(steal, result[8])) { total = user + nice + system + idle + ioWait + irq + softIrq + steal; return Stat{user, nice, system, idle, ioWait, irq, softIrq, steal, total}; } } } return {}; } unsigned int computeCPUUsage(Stat const &statT0, Stat const &statT1) { auto total = statT1.total - statT0.total; auto idle = (statT1.idle + statT1.ioWait) - (statT0.idle + statT0.ioWait); auto used = total - idle; return (100.0 * used) / total; } } // namespace Utils::CPU corectrl-v1.4.2/src/core/components/cpuutils.h000066400000000000000000000027611467225065400214670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include namespace Utils::CPU { /// Returns a piece of information from /proc/cpuinfo. /// @param procCpuInfoLines /proc/cpuinfo data source contents lines /// @param cpuId cpu id from which the info will be retrieved /// @param target label that describes the information to retrieve std::optional parseProcCpuInfo(std::vector const &procCpuInfoLines, int cpuId, std::string_view target); /// CPU Stat captured from /proc/stat. struct Stat { std::uint64_t user; std::uint64_t nice; std::uint64_t system; std::uint64_t idle; std::uint64_t ioWait; std::uint64_t irq; std::uint64_t softIrq; std::uint64_t steal; std::uint64_t total; }; /// Returns the aggregate CPU Stat from /proc/stat. /// @param procStatLines /proc/stat data. /// @returns CPU stat or none when the CPU stat cannot be parsed from the input data. std::optional parseProcStat(std::vector const &procStatLines); /// Computes the used CPU in a time interval defined by statT0 and statT1. /// @param statT0 CPU stat captured in time 0. /// @param statT1 CPU stat captured in time 1 (some time after statT0). /// @returns percentage of the CPU used in the time interval. unsigned int computeCPUUsage(Stat const &statT0, Stat const &statT1); } // namespace Utils::CPU corectrl-v1.4.2/src/core/components/cpuxmlparser.cpp000066400000000000000000000115201467225065400226700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuxmlparser.h" #include "core/info/icpuinfo.h" #include "core/profilepartxmlparserprovider.h" #include "icpu.h" #include class CPUXMLParser::Factory final : public ProfilePartXMLParser::Factory , public ICPUProfilePart::Exporter { public: Factory(IProfilePartXMLParserProvider const &profilePartParserProvider, CPUXMLParser &parser) noexcept : ProfilePartXMLParser::Factory(profilePartParserProvider) , outer_(parser) { } void takePartParser(Item const &i, std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takePhysicalId(int) override { } private: CPUXMLParser &outer_; }; void CPUXMLParser::Factory::takePartParser( Item const &i, std::unique_ptr &&part) { outer_.parsers_.emplace(i.ID(), std::move(part)); } std::optional> CPUXMLParser::Factory::provideExporter(Item const &i) { if (i.ID() == ICPU::ItemID) return *this; else return factory(i); } class CPUXMLParser::Initializer final : public ICPUProfilePart::Exporter { public: Initializer(CPUXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takePhysicalId(int id) override; private: CPUXMLParser &outer_; std::unordered_map> initializers_; }; std::optional> CPUXMLParser::Initializer::provideExporter(Item const &i) { auto &id = i.ID(); if (outer_.parsers_.count(id) > 0) { if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = outer_.parsers_.at(id)->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } } return {}; } void CPUXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void CPUXMLParser::Initializer::takePhysicalId(int id) { outer_.physicalId_ = outer_.physicalIdDefault_ = id; } CPUXMLParser::CPUXMLParser() noexcept : ProfilePartXMLParser(ICPU::ItemID, *this, *this) { } std::unique_ptr CPUXMLParser::factory( IProfilePartXMLParserProvider const &profilePartParserProvider) { return std::make_unique(profilePartParserProvider, *this); } std::unique_ptr CPUXMLParser::initializer() { return std::make_unique(*this); } std::optional> CPUXMLParser::provideExporter(Item const &i) { auto parserIt = parsers_.find(i.ID()); if (parserIt != parsers_.cend()) return parserIt->second->profilePartExporter(); return {}; } std::optional> CPUXMLParser::provideImporter(Item const &i) { auto parserIt = parsers_.find(i.ID()); if (parserIt != parsers_.cend()) return parserIt->second->profilePartImporter(); return {}; } void CPUXMLParser::takeActive(bool active) { active_ = active; } bool CPUXMLParser::provideActive() const { return active_; } void CPUXMLParser::takePhysicalId(int id) { physicalId_ = id; } int CPUXMLParser::providePhysicalId() const { return physicalId_; } void CPUXMLParser::appendTo(pugi::xml_node &parentNode) { auto cpuNode = parentNode.append_child(ID().c_str()); cpuNode.append_attribute("active") = active_; cpuNode.append_attribute("physicalId") = physicalId_; for (auto &[key, component] : parsers_) component->appendTo(cpuNode); } void CPUXMLParser::resetAttributes() { active_ = activeDefault_; physicalId_ = physicalIdDefault_; } void CPUXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto cpuNode = parentNode.find_child([&](pugi::xml_node const &node) { // match cpu node if (node.name() != ID()) return false; // match specific cpu auto physicalIdAttr = node.attribute("physicalId"); if (physicalIdAttr.empty()) // try the legacy "socketId" attribute node physicalIdAttr = node.attribute("socketId"); return physicalIdAttr.as_int(-1) == physicalId_; }); active_ = cpuNode.attribute("active").as_bool(activeDefault_); for (auto &[key, component] : parsers_) component->loadFrom(cpuNode); } bool const CPUXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( ICPU::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/cpuxmlparser.h000066400000000000000000000026221467225065400223400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "icpuprofilepart.h" #include #include #include #include class CPUXMLParser final : public ProfilePartXMLParser , public ICPUProfilePart::Exporter , public ICPUProfilePart::Importer { public: CPUXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takePhysicalId(int id) override; int providePhysicalId() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Factory; class Initializer; std::unordered_map> parsers_; bool active_; bool activeDefault_; int physicalId_; int physicalIdDefault_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/gpu.cpp000066400000000000000000000061131467225065400207400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpu.h" #include "controls/icontrol.h" #include "core/info/igpuinfo.h" #include "sensors/isensor.h" #include GPU::GPU(std::unique_ptr &&info, std::vector> &&controls, std::vector> &&sensors) noexcept : id_(IGPU::ItemID) , info_(std::move(info)) , controls_(std::move(controls)) , sensors_(std::move(sensors)) { key_ = "GPU" + std::to_string(info_->index()); } bool GPU::active() const { return active_; } void GPU::activate(bool active) { active_ = active; } std::string const &GPU::key() const { return key_; } std::pair>> GPU::componentInfo() const { std::pair>> info; auto name(info_->info(IGPUInfo::Keys::subdeviceName)); if (!name.empty()) name.append("\n"); name.append("[GPU ").append(std::to_string(info_->index())).append("]"); info.first = name; auto infoKeys = info_->keys(); for (auto &infoKey : infoKeys) info.second.emplace_back(infoKey, info_->info(infoKey)); return info; } void GPU::init() { for (auto &control : controls_) control->init(); } void GPU::preInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->preInit(ctlCmds); } void GPU::postInit(ICommandQueue &ctlCmds) { for (auto &control : controls_) control->postInit(ctlCmds); } void GPU::sync(ICommandQueue &ctlCmds) { if (active_) { // NOTE clean and sync commands generation cannot be interleaved. // Interleaving them could cause conflicts between clean and sync // commands of different controls, leading to an incorrect hardware // state. for (auto &control : controls_) control->clean(ctlCmds); for (auto &control : controls_) control->sync(ctlCmds); } } void GPU::updateSensors( std::unordered_map> const &ignored) { for (auto &sensor : sensors_) { if (ignored.count(key_) > 0 && ignored.at(key_).count(sensor->ID()) > 0) continue; // skip ignored sensors sensor->update(); } } IGPUInfo const &GPU::info() const { return *info_; } std::string const &GPU::ID() const { return id_; } void GPU::importWith(Importable::Importer &i) { auto importer = i.provideImporter(*this); if (importer.has_value()) { auto &gpuImporter = dynamic_cast(importer->get()); activate(gpuImporter.provideActive()); for (auto &control : controls_) control->importWith(*importer); } } void GPU::exportWith(Exportable::Exporter &e) const { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { auto &gpuExporter = dynamic_cast(exporter->get()); gpuExporter.takeActive(active()); gpuExporter.takeInfo(info()); for (auto const &sensor : sensors_) gpuExporter.takeSensor(*sensor); for (auto const &control : controls_) control->exportWith(*exporter); } } corectrl-v1.4.2/src/core/components/gpu.h000066400000000000000000000025511467225065400204070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "igpu.h" #include #include #include class IControl; class ISensor; class GPU final : public IGPU { public: GPU(std::unique_ptr &&info, std::vector> &&controls, std::vector> &&sensors) noexcept; bool active() const override; void activate(bool active) override; std::string const &key() const override; std::pair>> componentInfo() const override; void init() override; void preInit(ICommandQueue &ctlCmds) override; void postInit(ICommandQueue &ctlCmds) override; void sync(ICommandQueue &ctlCmds) override; void updateSensors( std::unordered_map> const &ignored) override; IGPUInfo const &info() const override; std::string const &ID() const override; void importWith(Importable::Importer &i) override; void exportWith(Exportable::Exporter &e) const override; private: std::string const id_; std::unique_ptr const info_; std::vector> const controls_; std::vector> const sensors_; std::string key_; bool active_{true}; }; corectrl-v1.4.2/src/core/components/gpuprofilepart.cpp000066400000000000000000000137371467225065400232220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuprofilepart.h" #include "core/info/igpuinfo.h" #include "core/profilepart.h" #include "core/profilepartprovider.h" #include "sensors/isensor.h" #include #include #include #include class GPUProfilePart::Factory final : public ProfilePart::Factory , public IGPU::Exporter { public: Factory(IProfilePartProvider const &profilePartProvider, GPUProfilePart &outer) noexcept : ProfilePart::Factory(profilePartProvider) , outer_(outer) { } void takeProfilePart(std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takeInfo(IGPUInfo const &) override; void takeSensor(ISensor const &) override; private: GPUProfilePart &outer_; }; void GPUProfilePart::Factory::takeProfilePart(std::unique_ptr &&part) { outer_.parts_.emplace_back(std::move(part)); } std::optional> GPUProfilePart::Factory::provideExporter(Item const &i) { return factory(i.ID()); } void GPUProfilePart::Factory::takeInfo(IGPUInfo const &info) { // NOTE info and system component key must be initialized here outer_.deviceID_ = info.info(IGPUInfo::Keys::deviceID); outer_.revision_ = info.info(IGPUInfo::Keys::revision); auto uniqueID = info.info(IGPUInfo::Keys::uniqueID); if (!uniqueID.empty()) outer_.uniqueID_ = uniqueID; outer_.index_ = info.index(); outer_.updateKey(); } void GPUProfilePart::Factory::takeSensor(ISensor const &sensor) { auto sensorProfilePart = createPart(sensor.ID()); if (sensorProfilePart != nullptr) outer_.parts_.emplace_back(std::move(sensorProfilePart)); } class GPUProfilePart::Initializer final : public IGPU::Exporter { public: Initializer(GPUProfilePart &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(IGPUInfo const &) override { } void takeSensor(ISensor const &) override { } private: GPUProfilePart &outer_; std::unordered_map> initializers_; }; std::optional> GPUProfilePart::Initializer::provideExporter(Item const &i) { for (auto &part : outer_.parts_) { auto &id = part->ID(); if (id == i.ID()) { if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = part->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } break; } } return {}; } void GPUProfilePart::Initializer::takeActive(bool active) { outer_.activate(active); } GPUProfilePart::GPUProfilePart() noexcept : id_(IGPU::ItemID) { } std::unique_ptr GPUProfilePart::factory(IProfilePartProvider const &profilePartProvider) { return std::make_unique(profilePartProvider, *this); } std::unique_ptr GPUProfilePart::initializer() { return std::make_unique(*this); } std::string const &GPUProfilePart::ID() const { return id_; } bool GPUProfilePart::belongsTo(Item const &i) const { auto gpu = dynamic_cast(&i); if (gpu != nullptr) { auto &info = gpu->info(); // when available, use the GPU unique ID auto uniqueID = info.info(IGPUInfo::Keys::uniqueID); if (!uniqueID.empty()) return uniqueID == uniqueID_; return info.index() == index_ && info.info(IGPUInfo::Keys::deviceID) == deviceID_ && info.info(IGPUInfo::Keys::revision) == revision_; } return false; } std::string const &GPUProfilePart::key() const { return key_; } std::optional> GPUProfilePart::provideImporter(Item const &i) { auto &id = i.ID(); auto partIter = std::find_if( parts_.cbegin(), parts_.cend(), [&](auto const &part) { return part->ID() == id; }); if (partIter != parts_.cend()) { auto importer = dynamic_cast(partIter->get()); if (importer != nullptr) return *importer; } return {}; } bool GPUProfilePart::provideActive() const { return active(); } void GPUProfilePart::importProfilePart(IProfilePart::Importer &i) { int oldIndex = index_; auto &gImporter = dynamic_cast(i); index_ = gImporter.provideIndex(); deviceID_ = gImporter.provideDeviceID(); revision_ = gImporter.provideRevision(); uniqueID_ = gImporter.provideUniqueID(); if (oldIndex != index_) updateKey(); for (auto &part : parts_) part->importWith(i); } void GPUProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &gExporter = dynamic_cast(e); gExporter.takeIndex(index_); gExporter.takeDeviceID(deviceID_); gExporter.takeRevision(revision_); gExporter.takeUniqueID(uniqueID_); for (auto const &part : parts_) part->exportWith(e); } std::unique_ptr GPUProfilePart::cloneProfilePart() const { auto clone = std::make_unique(); clone->deviceID_ = deviceID_; clone->revision_ = revision_; clone->uniqueID_ = uniqueID_; clone->index_ = index_; clone->key_ = key_; clone->parts_.reserve(parts_.size()); std::transform(parts_.cbegin(), parts_.cend(), std::back_inserter(clone->parts_), [](auto const &part) { return part->clone(); }); return std::move(clone); } void GPUProfilePart::updateKey() { key_ = "GPU" + std::to_string(index_); } bool const GPUProfilePart::registered_ = ProfilePartProvider::registerProvider( IGPU::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/gpuprofilepart.h000066400000000000000000000024651467225065400226630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "igpu.h" #include "igpuprofilepart.h" #include #include #include #include class GPUProfilePart final : public IGPUProfilePart , public IGPU::Importer { public: GPUProfilePart() noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; bool belongsTo(Item const &i) const override; std::string const &key() const override; std::optional> provideImporter(Item const &i) override; bool provideActive() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: void updateKey(); class Factory; class Initializer; std::vector> parts_; std::string const id_; std::string deviceID_; std::string revision_; std::string key_; int index_{0}; std::optional uniqueID_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/gpuqmlitem.cpp000066400000000000000000000105031467225065400223270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuqmlitem.h" #include "core/info/igpuinfo.h" #include "core/iqmlcomponentfactory.h" #include "core/qmlcomponentregistry.h" #include "igpu.h" #include "sensors/graphitem.h" #include "sensors/isensor.h" #include #include #include #include #include #include #include #include #include class GPUQMLItem::Initializer final : public QMLItem::Initializer , public IGPU::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, GPUQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(IGPUInfo const &info) override; void takeSensor(ISensor const &sensor) override; private: GPUQMLItem &outer_; }; std::optional> GPUQMLItem::Initializer::provideExporter(Item const &i) { return initializer(i.ID(), &outer_).first; } void GPUQMLItem::Initializer::takeActive(bool active) { outer_.takeActive(active); } void GPUQMLItem::Initializer::takeInfo(IGPUInfo const &info) { auto name(info.info(IGPUInfo::Keys::subdeviceName)); if (!name.empty()) name.append("\n"); name.append("[GPU ").append(std::to_string(info.index())).append("]"); outer_.setName(QString::fromStdString(name)); outer_.takeIndex(info.index()); } void GPUQMLItem::Initializer::takeSensor(ISensor const &sensor) { auto graphItem = dynamic_cast( qmlComponentFactory_.createQuickItem(sensor.ID(), &outer_, "SensorGraph")); if (graphItem != nullptr) { connect(graphItem, &GraphItem::settingsChanged, &outer_, &QMLItem::settingsChanged, Qt::UniqueConnection); graphItem->init(&sensor); emit outer_.newGraphItem(graphItem); } } void GPUQMLItem::activate(bool active) { takeActive(active); } std::optional> GPUQMLItem::provideImporter(Item const &i) { auto item = this->findChild(QString::fromStdString(i.ID())); if (item == nullptr) return {}; return dynamic_cast(*item); } std::optional> GPUQMLItem::provideExporter(Item const &i) { auto item = this->findChild(QString::fromStdString(i.ID())); if (item == nullptr) return {}; return dynamic_cast(*item); } bool GPUQMLItem::provideActive() const { return active_; } int GPUQMLItem::provideIndex() const { return index_; } std::string const &GPUQMLItem::provideDeviceID() const { return deviceID_; } std::string const &GPUQMLItem::provideRevision() const { return revision_; } std::optional GPUQMLItem::provideUniqueID() const { return uniqueID_; } void GPUQMLItem::takeActive(bool active) { active_ = active; setEnabled(active); } void GPUQMLItem::takeIndex(int index) { index_ = index; } void GPUQMLItem::takeDeviceID(std::string const &deviceID) { deviceID_ = deviceID; } void GPUQMLItem::takeRevision(std::string const &revision) { revision_ = revision; } void GPUQMLItem::takeUniqueID(std::optional uniqueID) { uniqueID_ = uniqueID; } std::unique_ptr GPUQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } bool GPUQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, IGPU::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( IGPU::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/GPUForm.qml")); return qobject_cast(component.create()); }); return true; } bool const GPUQMLItem::registered_ = GPUQMLItem::register_(); corectrl-v1.4.2/src/core/components/gpuqmlitem.h000066400000000000000000000030701467225065400217750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/qmlitem.h" #include "igpuprofilepart.h" #include #include class QQuickItem; class GPUQMLItem : public QMLItem , public IGPUProfilePart::Importer , public IGPUProfilePart::Exporter { Q_OBJECT Q_PROPERTY(int index READ provideIndex) public: void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; int provideIndex() const override; std::string const &provideDeviceID() const override; std::string const &provideRevision() const override; std::optional provideUniqueID() const override; void takeActive(bool active) override; void takeIndex(int index) override; void takeDeviceID(std::string const &deviceID) override; void takeRevision(std::string const &revision) override; void takeUniqueID(std::optional uniqueID) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; signals: void newGraphItem(QQuickItem *item); private: class Initializer; bool active_; std::string deviceID_; std::string revision_; std::optional uniqueID_; int index_; static bool register_(); static bool const registered_; }; corectrl-v1.4.2/src/core/components/gpuxmlparser.cpp000066400000000000000000000150261467225065400227010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuxmlparser.h" #include "core/profilepartxmlparserprovider.h" #include "igpu.h" #include class GPUXMLParser::Factory final : public ProfilePartXMLParser::Factory , public IGPUProfilePart::Exporter { public: Factory(IProfilePartXMLParserProvider const &profilePartParserProvider, GPUXMLParser &parser) noexcept : ProfilePartXMLParser::Factory(profilePartParserProvider) , outer_(parser) { } void takePartParser(Item const &i, std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takeIndex(int) override { } void takeDeviceID(std::string const &) override { } void takeRevision(std::string const &) override { } void takeUniqueID(std::optional) override { } private: GPUXMLParser &outer_; }; void GPUXMLParser::Factory::takePartParser( Item const &i, std::unique_ptr &&part) { outer_.parsers_.emplace(i.ID(), std::move(part)); } std::optional> GPUXMLParser::Factory::provideExporter(Item const &i) { if (i.ID() == IGPU::ItemID) return *this; else return factory(i); } class GPUXMLParser::Initializer final : public IGPUProfilePart::Exporter { public: Initializer(GPUXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeIndex(int index) override; void takeDeviceID(std::string const &deviceID) override; void takeRevision(std::string const &revision) override; void takeUniqueID(std::optional uniqueID) override; private: GPUXMLParser &outer_; std::unordered_map> initializers_; }; std::optional> GPUXMLParser::Initializer::provideExporter(Item const &i) { auto &id = i.ID(); if (outer_.parsers_.count(id) > 0) { if (initializers_.count(id) > 0) return *initializers_.at(id); else { auto initializer = outer_.parsers_.at(id)->initializer(); if (initializer != nullptr) { initializers_.emplace(id, std::move(initializer)); return *initializers_.at(id); } } } return {}; } void GPUXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void GPUXMLParser::Initializer::takeIndex(int index) { outer_.index_ = outer_.indexDefault_ = index; } void GPUXMLParser::Initializer::takeDeviceID(std::string const &deviceID) { outer_.deviceID_ = outer_.deviceIDDefault_ = deviceID; } void GPUXMLParser::Initializer::takeRevision(std::string const &revision) { outer_.revision_ = outer_.revisionDefault_ = revision; } void GPUXMLParser::Initializer::takeUniqueID(std::optional uniqueID) { outer_.uniqueID_ = outer_.uniqueIDDefault_ = uniqueID; } GPUXMLParser::GPUXMLParser() noexcept : ProfilePartXMLParser(IGPU::ItemID, *this, *this) { } std::unique_ptr GPUXMLParser::factory( IProfilePartXMLParserProvider const &profilePartParserProvider) { return std::make_unique(profilePartParserProvider, *this); } std::unique_ptr GPUXMLParser::initializer() { return std::make_unique(*this); } std::optional> GPUXMLParser::provideExporter(Item const &i) { auto parserIt = parsers_.find(i.ID()); if (parserIt != parsers_.cend()) return parserIt->second->profilePartExporter(); return {}; } std::optional> GPUXMLParser::provideImporter(Item const &i) { auto parserIt = parsers_.find(i.ID()); if (parserIt != parsers_.cend()) return parserIt->second->profilePartImporter(); return {}; } void GPUXMLParser::takeActive(bool active) { active_ = active; } bool GPUXMLParser::provideActive() const { return active_; } void GPUXMLParser::takeIndex(int index) { index_ = index; } int GPUXMLParser::provideIndex() const { return index_; } void GPUXMLParser::takeDeviceID(std::string const &deviceID) { deviceID_ = deviceID; } std::string const &GPUXMLParser::provideDeviceID() const { return deviceID_; } void GPUXMLParser::takeRevision(std::string const &revision) { revision_ = revision; } std::string const &GPUXMLParser::provideRevision() const { return revision_; } void GPUXMLParser::takeUniqueID(std::optional uniqueID) { uniqueID_ = uniqueID; } std::optional GPUXMLParser::provideUniqueID() const { return uniqueID_; } void GPUXMLParser::appendTo(pugi::xml_node &parentNode) { auto gpuNode = parentNode.append_child(ID().c_str()); gpuNode.append_attribute("active") = active_; gpuNode.append_attribute("index") = index_; gpuNode.append_attribute("deviceid") = deviceID_.c_str(); gpuNode.append_attribute("revision") = revision_.c_str(); if (uniqueID_.has_value()) gpuNode.append_attribute("uniqueid") = uniqueID_->c_str(); for (auto &[key, component] : parsers_) component->appendTo(gpuNode); } void GPUXMLParser::resetAttributes() { active_ = activeDefault_; index_ = indexDefault_; deviceID_ = deviceIDDefault_; revision_ = revisionDefault_; uniqueID_ = uniqueIDDefault_; } void GPUXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto gpuNode = parentNode.find_child([&](pugi::xml_node const &node) { // match gpu node if (node.name() != ID()) return false; // try to match specific gpu by uniqueid attribute auto uniqueID = node.attribute("uniqueid").as_string(); if (*uniqueID != 0 && uniqueID_.has_value()) return uniqueID_ == uniqueID; // match specific gpu by index, deviceid and revision attributes return node.attribute("index").as_int(-1) == index_ && node.attribute("deviceid").as_string() == deviceID_ && node.attribute("revision").as_string() == revision_; }); active_ = gpuNode.attribute("active").as_bool(activeDefault_); for (auto &[key, component] : parsers_) component->loadFrom(gpuNode); } bool const GPUXMLParser::registered_ = ProfilePartXMLParserProvider::registerProvider( IGPU::ItemID, []() { return std::make_unique(); }); corectrl-v1.4.2/src/core/components/gpuxmlparser.h000066400000000000000000000037551467225065400223540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "igpuprofilepart.h" #include #include #include #include #include class IProfilePartXMLParserProvider; class GPUXMLParser final : public ProfilePartXMLParser , public IGPUProfilePart::Exporter , public IGPUProfilePart::Importer { public: GPUXMLParser() noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; bool provideActive() const override; void takeIndex(int index) override; int provideIndex() const override; void takeDeviceID(std::string const &deviceID) override; std::string const &provideDeviceID() const override; void takeRevision(std::string const &revision) override; std::string const &provideRevision() const override; void takeUniqueID(std::optional uniqueID) override; std::optional provideUniqueID() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Factory; class Initializer; std::unordered_map> parsers_; bool active_; bool activeDefault_; std::string deviceID_; std::string deviceIDDefault_; std::string revision_; std::string revisionDefault_; std::optional uniqueID_; std::optional uniqueIDDefault_; int index_; int indexDefault_; static bool const registered_; }; corectrl-v1.4.2/src/core/components/icpu.h000066400000000000000000000010571467225065400205540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/isyscomponent.h" #include class ICPUInfo; class ISensor; class ICPU : public ISysComponent { public: static constexpr std::string_view ItemID{"CPU"}; class Exporter : public ISysComponent::Exporter { public: virtual void takeInfo(ICPUInfo const &info) = 0; virtual void takeSensor(ISensor const &sensor) = 0; }; virtual ICPUInfo const &info() const = 0; virtual ~ICPU() = default; }; corectrl-v1.4.2/src/core/components/icpuprofilepart.h000066400000000000000000000010261467225065400230200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/iprofilepart.h" #include "core/isyscomponentprofilepart.h" class ICPUProfilePart : public ISysComponentProfilePart { public: class Importer : public IProfilePart::Importer { public: virtual int providePhysicalId() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takePhysicalId(int id) = 0; }; virtual ~ICPUProfilePart() = default; }; corectrl-v1.4.2/src/core/components/igpu.h000066400000000000000000000010571467225065400205600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/isyscomponent.h" #include class IGPUInfo; class ISensor; class IGPU : public ISysComponent { public: static constexpr std::string_view ItemID{"GPU"}; class Exporter : public ISysComponent::Exporter { public: virtual void takeInfo(IGPUInfo const &info) = 0; virtual void takeSensor(ISensor const &sensor) = 0; }; virtual IGPUInfo const &info() const = 0; virtual ~IGPU() = default; }; corectrl-v1.4.2/src/core/components/igpuprofilepart.h000066400000000000000000000016711467225065400230320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/iprofilepart.h" #include "core/isyscomponentprofilepart.h" #include #include class IGPUProfilePart : public ISysComponentProfilePart { public: class Importer : public IProfilePart::Importer { public: virtual int provideIndex() const = 0; virtual std::string const &provideDeviceID() const = 0; virtual std::string const &provideRevision() const = 0; virtual std::optional provideUniqueID() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeIndex(int index) = 0; virtual void takeDeviceID(std::string const &deviceID) = 0; virtual void takeRevision(std::string const &revision) = 0; virtual void takeUniqueID(std::optional uniqueID) = 0; }; virtual ~IGPUProfilePart() = default; }; corectrl-v1.4.2/src/core/components/sensors/000077500000000000000000000000001467225065400211345ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/sensors/amd/000077500000000000000000000000001467225065400216755ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/sensors/amd/activity.cpp000066400000000000000000000051041467225065400242350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "activity.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "core/components/amdutils.h" #include "core/devfsdatasource.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include #include #include #include #include namespace AMD::Activity { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::unique_ptr sensor; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver == "amdgpu") sensor = createSensor(gpuInfo); if (!sensor) return {}; std::vector> sensors; sensors.emplace_back(std::move(sensor)); return sensors; } private: std::unique_ptr createSensor(IGPUInfo const &gpuInfo) const { #if defined(AMDGPU_INFO_SENSOR_GPU_LOAD) std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { unsigned int value; bool success = Utils::AMD::readAMDGPUInfoSensor( fd, &value, AMDGPU_INFO_SENSOR_GPU_LOAD); return success ? value : 0; })); return std::make_unique>( AMD::Activity::ItemID, std::move(dataSources), std::make_pair(units::dimensionless::scalar_t(0), units::dimensionless::scalar_t(100))); #else return {}; #endif } }; static bool register_() { GPUSensorProvider::registerProvider( std::make_unique()); ProfilePartProvider::registerProvider(AMD::Activity::ItemID, []() { return std::make_unique(AMD::Activity::ItemID, "yellowgreen"); }); ProfilePartXMLParserProvider::registerProvider(AMD::Activity::ItemID, []() { return std::make_unique(AMD::Activity::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::Activity corectrl-v1.4.2/src/core/components/sensors/amd/activity.h000066400000000000000000000004001467225065400236740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::Activity { static constexpr std::string_view ItemID{"AMD_ACTIVITY"}; } // namespace AMD::Activity corectrl-v1.4.2/src/core/components/sensors/amd/activitygraphitem.cpp000066400000000000000000000011471467225065400261410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "activity.h" #include "core/qmlcomponentregistry.h" #include #include namespace AMD::Activity { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::Activity::ItemID, []() { return new SensorGraphItem( AMD::Activity::ItemID, "%"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_ACTIVITY"), }; } // namespace AMD::Activity corectrl-v1.4.2/src/core/components/sensors/amd/fanspeedperc.cpp000066400000000000000000000065201467225065400250430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanspeedperc.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace AMD::FanSpeedPerc { // NOTE FanSpeedPerc is a last resort fan speed sensor. // // It will be used only on systems without proper support of fan1_input // (typically old hardware using radeon driver and some specific hardware supported // by the amdgpu driver). // // See #184. class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; unsigned int value; // When available, prefer fanspeedrpm sensor over this one auto fanInput = path.value() / "fan1_input"; if (Utils::File::isSysFSEntryValid(fanInput) && Utils::String::toNumber( value, Utils::File::readFileLines(fanInput).front())) return {}; auto pwm = path.value() / "pwm1"; if (!Utils::File::isSysFSEntryValid(pwm)) return {}; auto fileLines = Utils::File::readFileLines(pwm); if (!Utils::String::toNumber(value, fileLines.front())) { SPDLOG_WARN("Unknown data format on {}", pwm.string()); SPDLOG_DEBUG(fileLines.front()); return {}; } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( pwm, [](std::string const &data, unsigned int &output) { unsigned int value; Utils::String::toNumber(value, data); output = value / 2.55; })); std::vector> sensors; sensors.emplace_back( std::make_unique>( AMD::FanSpeedPerc::ItemID, std::move(dataSources), std::make_pair(units::dimensionless::scalar_t(0), units::dimensionless::scalar_t(100)))); return sensors; } }; static bool register_() { GPUSensorProvider::registerProvider( std::make_unique()); ProfilePartProvider::registerProvider(AMD::FanSpeedPerc::ItemID, []() { return std::make_unique(AMD::FanSpeedPerc::ItemID, "lightskyblue"); }); ProfilePartXMLParserProvider::registerProvider(AMD::FanSpeedPerc::ItemID, []() { return std::make_unique(AMD::FanSpeedPerc::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::FanSpeedPerc corectrl-v1.4.2/src/core/components/sensors/amd/fanspeedperc.h000066400000000000000000000004161467225065400245060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::FanSpeedPerc { static constexpr std::string_view ItemID{"AMD_FAN_SPEED_PERC"}; } // namespace AMD::FanSpeedPerc corectrl-v1.4.2/src/core/components/sensors/amd/fanspeedpercgraphitem.cpp000066400000000000000000000012011467225065400267330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "fanspeedperc.h" #include #include namespace AMD::FanSpeedPerc { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::FanSpeedPerc::ItemID, []() { return new SensorGraphItem( AMD::FanSpeedPerc::ItemID, "%"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_FAN_SPEED_PERC"), }; } // namespace AMD::FanSpeedPerc corectrl-v1.4.2/src/core/components/sensors/amd/fanspeedrpm.cpp000066400000000000000000000115501467225065400247070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "fanspeedrpm.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace AMD::FanSpeedRPM { // NOTE FanSpeedRPM is the preferred fan speed sensor. // // It will be used on any system with proper fan1_input and pwm1 support // (most hardware using the amdgpu driver). // // pwm1 sensor is used to report 0 fan speed when the fans are stopped, as // fan1_input could report bad values in this case. // Related bug report: https://gitlab.freedesktop.org/drm/amd/-/issues/335 // // See #184. class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { std::vector> sensors; if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; std::vector fileLines; auto fanInput = path.value() / "fan1_input"; if (!Utils::File::isSysFSEntryValid(fanInput)) return {}; unsigned int value; fileLines = Utils::File::readFileLines(fanInput); if (!Utils::String::toNumber(value, fileLines.front())) { SPDLOG_WARN("Unknown data format on {}", fanInput.string()); SPDLOG_DEBUG(fileLines.front()); return {}; } auto pwm = path.value() / "pwm1"; if (!Utils::File::isSysFSEntryValid(pwm)) return {}; fileLines = Utils::File::readFileLines(pwm); if (!Utils::String::toNumber(value, fileLines.front())) { SPDLOG_WARN("Unknown data format on {}", pwm.string()); SPDLOG_DEBUG(fileLines.front()); return {}; } // fallback sensor range std::optional> range({units::angular_velocity::revolutions_per_minute_t(0), units::angular_velocity::revolutions_per_minute_t(2200)}); // when supported, read the sensor range auto minPath = path.value() / "fan1_min"; auto maxPath = path.value() / "fan1_max"; if (Utils::File::isSysFSEntryValid(minPath) && Utils::File::isSysFSEntryValid(maxPath)) { auto min = Utils::File::readFileLines(minPath); auto max = Utils::File::readFileLines(maxPath); unsigned int minValue; unsigned int maxValue; if (Utils::String::toNumber(minValue, min.front()) && Utils::String::toNumber(maxValue, max.front())) if (min < max) { range = {units::angular_velocity::revolutions_per_minute_t(minValue), units::angular_velocity::revolutions_per_minute_t(maxValue)}; } } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( fanInput, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); })); dataSources.emplace_back(std::make_unique>( pwm, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); })); sensors.emplace_back( std::make_unique>( AMD::FanSpeedRPM::ItemID, std::move(dataSources), std::move(range), [](std::vector const &input) { return input[1] > 0 ? input[0] : 0; })); return sensors; } }; static bool register_() { GPUSensorProvider::registerProvider( std::make_unique()); ProfilePartProvider::registerProvider(AMD::FanSpeedRPM::ItemID, []() { return std::make_unique(AMD::FanSpeedRPM::ItemID, "lightskyblue"); }); ProfilePartXMLParserProvider::registerProvider(AMD::FanSpeedRPM::ItemID, []() { return std::make_unique(AMD::FanSpeedRPM::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::FanSpeedRPM corectrl-v1.4.2/src/core/components/sensors/amd/fanspeedrpm.h000066400000000000000000000004131467225065400243500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::FanSpeedRPM { static constexpr std::string_view ItemID{"AMD_FAN_SPEED_RPM"}; } // namespace AMD::FanSpeedRPM corectrl-v1.4.2/src/core/components/sensors/amd/fanspeedrpmgraphitem.cpp000066400000000000000000000013701467225065400266070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "fanspeedrpm.h" #include #include namespace AMD::FanSpeedRPM { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::FanSpeedRPM::ItemID, []() { return new SensorGraphItem( AMD::FanSpeedRPM::ItemID, units::angular_velocity::revolutions_per_minute_t().abbreviation()); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_FAN_SPEED_RPM"), }; } // namespace AMD::FanSpeedRPM corectrl-v1.4.2/src/core/components/sensors/amd/gpufreq.cpp000066400000000000000000000103471467225065400240570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpufreq.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/devfsdatasource.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include #include #include #include #include #include #include #include namespace AMD::GPUFreq { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::unique_ptr sensor; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver == "amdgpu") sensor = createAMDGPUSensor(gpuInfo); else if (driver == "radeon") sensor = createRadeonSensor(gpuInfo); if (!sensor) return {}; std::vector> sensors; sensors.emplace_back(std::move(sensor)); return sensors; } private: std::unique_ptr createAMDGPUSensor(IGPUInfo const &gpuInfo) const { #if defined(AMDGPU_INFO_SENSOR_GFX_SCLK) std::optional< std::pair> range; // get range from dpm sclk states (4.6+) auto dpmData = Utils::File::readFileLines(gpuInfo.path().sys / "pp_dpm_sclk"); auto gpuStates = Utils::AMD::parseDPMStates(dpmData); if (gpuStates.has_value() && !gpuStates->empty()) range = {gpuStates->front().second, gpuStates->back().second}; // expand range using dpm mclk states dpmData = Utils::File::readFileLines(gpuInfo.path().sys / "pp_dpm_mclk"); auto memStates = Utils::AMD::parseDPMStates(dpmData); if (memStates.has_value() && !memStates->empty()) { if (range.has_value()) range = {std::min(memStates->front().second, range->first), std::max(memStates->back().second, range->second)}; else // gpu clock range not available range = {memStates->front().second, memStates->back().second}; } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { unsigned int value; bool success = Utils::AMD::readAMDGPUInfoSensor( fd, &value, AMDGPU_INFO_SENSOR_GFX_SCLK); return success ? value : 0; })); return std::make_unique>( AMD::GPUFreq::ItemID, std::move(dataSources), std::move(range)); #else return {}; #endif } std::unique_ptr createRadeonSensor(IGPUInfo const &gpuInfo) const { #if defined(RADEON_INFO_CURRENT_GPU_SCLK) std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { unsigned int value; bool success = Utils::AMD::readRadeonInfoSensor( fd, &value, RADEON_INFO_CURRENT_GPU_SCLK); return success ? value : 0; })); return std::make_unique>( AMD::GPUFreq::ItemID, std::move(dataSources)); #else return {}; #endif } }; static bool register_() { GPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(AMD::GPUFreq::ItemID, []() { return std::make_unique(AMD::GPUFreq::ItemID, "fuchsia"); }); ProfilePartXMLParserProvider::registerProvider(AMD::GPUFreq::ItemID, []() { return std::make_unique(AMD::GPUFreq::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::GPUFreq corectrl-v1.4.2/src/core/components/sensors/amd/gpufreq.h000066400000000000000000000003761467225065400235250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::GPUFreq { static constexpr std::string_view ItemID{"AMD_GPU_FREQ"}; } // namespace AMD::GPUFreq corectrl-v1.4.2/src/core/components/sensors/amd/gpufreqgraphitem.cpp000066400000000000000000000012141467225065400257510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "gpufreq.h" #include #include namespace AMD::GPUFreq { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::GPUFreq::ItemID, []() { return new SensorGraphItem( AMD::GPUFreq::ItemID, units::frequency::megahertz_t().abbreviation()); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_GPU_FREQ"), }; } // namespace AMD::GPUFreq corectrl-v1.4.2/src/core/components/sensors/amd/gputemp.cpp000066400000000000000000000063471467225065400240740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gputemp.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace AMD::GPUTemp { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; std::optional< std::pair> range; auto critFilePath = path.value() / "temp1_crit"; if (Utils::File::isFilePathValid(critFilePath)) { auto data = Utils::File::readFileLines(critFilePath); if (!data.empty()) { int value; if (Utils::String::toNumber(value, data.front()) && // do not use bogus values, see #103 (value >= 0 && value < 150000)) { range = {units::temperature::celsius_t(0), units::temperature::celsius_t(value / 1000.0)}; } } } auto tempInput = path.value() / "temp1_input"; if (!Utils::File::isSysFSEntryValid(tempInput)) return {}; int value; auto tempInputLines = Utils::File::readFileLines(tempInput); if (!Utils::String::toNumber(value, tempInputLines.front())) { SPDLOG_WARN("Unknown data format on {}", tempInput.string()); SPDLOG_DEBUG(tempInputLines.front()); return {}; } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( tempInput, [](std::string const &data, int &output) { int value; Utils::String::toNumber(value, data); output = value / 1000; })); std::vector> sensors; sensors.emplace_back( std::make_unique>( AMD::GPUTemp::ItemID, std::move(dataSources), std::move(range))); return sensors; } }; static bool register_() { GPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(AMD::GPUTemp::ItemID, []() { return std::make_unique(AMD::GPUTemp::ItemID, "crimson"); }); ProfilePartXMLParserProvider::registerProvider(AMD::GPUTemp::ItemID, []() { return std::make_unique(AMD::GPUTemp::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::GPUTemp corectrl-v1.4.2/src/core/components/sensors/amd/gputemp.h000066400000000000000000000003761467225065400235350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::GPUTemp { static constexpr std::string_view ItemID{"AMD_GPU_TEMP"}; } // namespace AMD::GPUTemp corectrl-v1.4.2/src/core/components/sensors/amd/gputempgraphitem.cpp000066400000000000000000000011361467225065400257640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "gputemp.h" #include #include namespace AMD::GPUTemp { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::GPUTemp::ItemID, []() { return new SensorGraphItem( AMD::GPUTemp::ItemID, "\u00B0C"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_GPU_TEMP"), }; } // namespace AMD::GPUTemp corectrl-v1.4.2/src/core/components/sensors/amd/gpuvolt.cpp000066400000000000000000000053021467225065400241010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "gpuvolt.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace AMD::GPUVolt { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path.has_value()) return {}; auto voltInput = path.value() / "in0_input"; if (!Utils::File::isSysFSEntryValid(voltInput)) return {}; int value; auto voltInputLines = Utils::File::readFileLines(voltInput); if (!Utils::String::toNumber(value, voltInputLines.front())) { SPDLOG_WARN("Unknown data format on {}", voltInput.string()); SPDLOG_DEBUG(voltInputLines.front()); return {}; } // auto scaling range std::optional> range; std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( voltInput, [](std::string const &data, int &output) { Utils::String::toNumber(output, data); })); std::vector> sensors; sensors.emplace_back( std::make_unique>( AMD::GPUVolt::ItemID, std::move(dataSources), std::move(range))); return sensors; } }; static bool register_() { GPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(AMD::GPUVolt::ItemID, []() { return std::make_unique(AMD::GPUVolt::ItemID, "darkorange"); }); ProfilePartXMLParserProvider::registerProvider(AMD::GPUVolt::ItemID, []() { return std::make_unique(AMD::GPUVolt::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::GPUVolt corectrl-v1.4.2/src/core/components/sensors/amd/gpuvolt.h000066400000000000000000000003761467225065400235540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include namespace AMD::GPUVolt { static constexpr std::string_view ItemID{"AMD_GPU_VOLT"}; } // namespace AMD::GPUVolt corectrl-v1.4.2/src/core/components/sensors/amd/gpuvoltgraphitem.cpp000066400000000000000000000011271467225065400260030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "gpuvolt.h" #include #include namespace AMD::GPUVolt { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::GPUVolt::ItemID, []() { return new SensorGraphItem( AMD::GPUVolt::ItemID, "mV"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_GPU_VOLT"), }; } // namespace AMD::GPUVolt corectrl-v1.4.2/src/core/components/sensors/amd/junctiontemp.cpp000066400000000000000000000061531467225065400251250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "junctiontemp.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace AMD::JunctionTemp { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path) return {}; auto tempInput = path.value() / "temp2_input"; if (!Utils::File::isSysFSEntryValid(tempInput)) return {}; int value; auto data = Utils::File::readFileLines(tempInput); if (!Utils::String::toNumber(value, data.front())) { SPDLOG_WARN("Unknown data format on {}", tempInput.string()); SPDLOG_DEBUG(data.front()); return {}; } std::optional< std::pair> range; data = Utils::File::readFileLines(path.value() / "temp2_crit"); if (!data.empty()) { if (Utils::String::toNumber(value, data.front()) && // do not use bogus values, see #103 (value >= 0 && value < 150000)) { range = {units::temperature::celsius_t(0), units::temperature::celsius_t(value / 1000.0)}; } } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( tempInput, [](std::string const &data, int &output) { int value; Utils::String::toNumber(value, data); output = value / 1000; })); std::vector> sensors; sensors.emplace_back( std::make_unique>( AMD::JunctionTemp::ItemID, std::move(dataSources), std::move(range))); return sensors; } }; static bool register_() { GPUSensorProvider::registerProvider( std::make_unique()); ProfilePartProvider::registerProvider(AMD::JunctionTemp::ItemID, []() { return std::make_unique(AMD::JunctionTemp::ItemID, "red"); }); ProfilePartXMLParserProvider::registerProvider(AMD::JunctionTemp::ItemID, []() { return std::make_unique(AMD::JunctionTemp::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::JunctionTemp corectrl-v1.4.2/src/core/components/sensors/amd/junctiontemp.h000066400000000000000000000004211467225065400245620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include namespace AMD::JunctionTemp { static constexpr std::string_view ItemID{"AMD_GPU_JUNCTION_TEMP"}; } // namespace AMD::JunctionTemp corectrl-v1.4.2/src/core/components/sensors/amd/junctiontempgraphitem.cpp000066400000000000000000000012001467225065400270120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "junctiontemp.h" #include #include namespace AMD::JunctionTemp { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::JunctionTemp::ItemID, []() { return new SensorGraphItem( AMD::JunctionTemp::ItemID, "\u00B0C"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_GPU_JUNCTION_TEMP"), }; } // namespace AMD::JunctionTemp corectrl-v1.4.2/src/core/components/sensors/amd/memfreq.cpp000066400000000000000000000103511467225065400240350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "memfreq.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/devfsdatasource.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include #include #include #include #include #include #include #include namespace AMD::MemFreq { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::unique_ptr sensor; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver == "amdgpu") sensor = createAMDGPUSensor(gpuInfo); else if (driver == "radeon") sensor = createRadeonSensor(gpuInfo); if (!sensor) return {}; std::vector> sensors; sensors.emplace_back(std::move(sensor)); return sensors; } private: std::unique_ptr createAMDGPUSensor(IGPUInfo const &gpuInfo) const { #if defined(AMDGPU_INFO_SENSOR_GFX_MCLK) std::optional< std::pair> range; // get range from dpm mclk states (4.6+) auto dpmData = Utils::File::readFileLines(gpuInfo.path().sys / "pp_dpm_mclk"); auto memStates = Utils::AMD::parseDPMStates(dpmData); if (memStates.has_value() && !memStates->empty()) range = {memStates->front().second, memStates->back().second}; // expand range using dpm sclk states dpmData = Utils::File::readFileLines(gpuInfo.path().sys / "pp_dpm_sclk"); auto gpuStates = Utils::AMD::parseDPMStates(dpmData); if (gpuStates.has_value() && !gpuStates->empty()) { if (range.has_value()) range = {std::min(gpuStates->front().second, range->first), std::max(gpuStates->back().second, range->second)}; else // memory clock range not available range = {gpuStates->front().second, gpuStates->back().second}; } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { unsigned int value; bool success = Utils::AMD::readAMDGPUInfoSensor( fd, &value, AMDGPU_INFO_SENSOR_GFX_MCLK); return success ? value : 0; })); return std::make_unique>( AMD::MemFreq::ItemID, std::move(dataSources), std::move(range)); #else return {}; #endif } std::unique_ptr createRadeonSensor(IGPUInfo const &gpuInfo) const { #if defined(RADEON_INFO_CURRENT_GPU_MCLK) std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { unsigned int value; bool success = Utils::AMD::readRadeonInfoSensor( fd, &value, RADEON_INFO_CURRENT_GPU_MCLK); return success ? value : 0; })); return std::make_unique>( AMD::MemFreq::ItemID, std::move(dataSources)); #else return {}; #endif } }; static bool register_() { GPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(AMD::MemFreq::ItemID, []() { return std::make_unique(AMD::MemFreq::ItemID, "orchid"); }); ProfilePartXMLParserProvider::registerProvider(AMD::MemFreq::ItemID, []() { return std::make_unique(AMD::MemFreq::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::MemFreq corectrl-v1.4.2/src/core/components/sensors/amd/memfreq.h000066400000000000000000000003761467225065400235100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::MemFreq { static constexpr std::string_view ItemID{"AMD_MEM_FREQ"}; } // namespace AMD::MemFreq corectrl-v1.4.2/src/core/components/sensors/amd/memfreqgraphitem.cpp000066400000000000000000000012141467225065400257340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "memfreq.h" #include #include namespace AMD::MemFreq { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::MemFreq::ItemID, []() { return new SensorGraphItem( AMD::MemFreq::ItemID, units::frequency::megahertz_t().abbreviation()); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_MEM_FREQ"), }; } // namespace AMD::MemFreq corectrl-v1.4.2/src/core/components/sensors/amd/memorytemp.cpp000066400000000000000000000061511467225065400246020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "memorytemp.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace AMD::MemoryTemp { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; auto path = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (!path.has_value()) return {}; auto tempInput = path.value() / "temp3_input"; if (!Utils::File::isSysFSEntryValid(tempInput)) return {}; int value; auto data = Utils::File::readFileLines(tempInput); if (!Utils::String::toNumber(value, data.front())) { SPDLOG_WARN("Unknown data format on {}", tempInput.string()); SPDLOG_DEBUG(data.front()); return {}; } std::optional< std::pair> range; data = Utils::File::readFileLines(path.value() / "temp3_crit"); if (!data.empty()) { if (Utils::String::toNumber(value, data.front()) && // do not use bogus values, see #103 (value >= 0 && value < 150000)) { range = {units::temperature::celsius_t(0), units::temperature::celsius_t(value / 1000.0)}; } } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( tempInput, [](std::string const &data, int &output) { int value; Utils::String::toNumber(value, data); output = value / 1000; })); std::vector> sensors; sensors.emplace_back( std::make_unique>( AMD::MemoryTemp::ItemID, std::move(dataSources), std::move(range))); return sensors; } }; static bool register_() { GPUSensorProvider::registerProvider( std::make_unique()); ProfilePartProvider::registerProvider(AMD::MemoryTemp::ItemID, []() { return std::make_unique(AMD::MemoryTemp::ItemID, "darkred"); }); ProfilePartXMLParserProvider::registerProvider(AMD::MemoryTemp::ItemID, []() { return std::make_unique(AMD::MemoryTemp::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::MemoryTemp corectrl-v1.4.2/src/core/components/sensors/amd/memorytemp.h000066400000000000000000000004131467225065400242420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include namespace AMD::MemoryTemp { static constexpr std::string_view ItemID{"AMD_GPU_MEMORY_TEMP"}; } // namespace AMD::MemoryTemp corectrl-v1.4.2/src/core/components/sensors/amd/memorytempgraphitem.cpp000066400000000000000000000011641467225065400265020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "memorytemp.h" #include #include namespace AMD::MemoryTemp { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::MemoryTemp::ItemID, []() { return new SensorGraphItem( AMD::MemoryTemp::ItemID, "\u00B0C"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_GPU_MEMORY_TEMP"), }; } // namespace AMD::MemoryTemp corectrl-v1.4.2/src/core/components/sensors/amd/memusage.cpp000066400000000000000000000077261467225065400242200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "memusage.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/stringutils.h" #include "core/components/amdutils.h" #include "core/devfsdatasource.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include #include #include #include #include #include #include #include namespace AMD::MemUsage { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::optional> range; auto memInfo = gpuInfo.info(IGPUInfo::Keys::memory); if (!memInfo.empty()) { unsigned int memorySize; if (Utils::String::toNumber(memorySize, memInfo)) range = {units::data::megabyte_t(0), units::data::megabyte_t(memorySize)}; } std::unique_ptr sensor; auto driver = gpuInfo.info(IGPUInfo::Keys::driver); if (driver == "amdgpu") sensor = createAMDGPUSensor(gpuInfo, std::move(range)); else if (driver == "radeon") sensor = createRadeonSensor(gpuInfo, std::move(range)); if (!sensor) return {}; std::vector> sensors; sensors.emplace_back(std::move(sensor)); return sensors; } private: std::unique_ptr createAMDGPUSensor( IGPUInfo const &gpuInfo, std::optional> &&range) const { #if defined(AMDGPU_INFO_VRAM_USAGE) std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { std::uint64_t value; bool success = Utils::AMD::readAMDGPUInfo(fd, &value, AMDGPU_INFO_VRAM_USAGE); return success ? value / (1024 * 1024) : 0; })); return std::make_unique>( AMD::MemUsage::ItemID, std::move(dataSources), std::move(range)); #else return {}; #endif } std::unique_ptr createRadeonSensor( IGPUInfo const &gpuInfo, std::optional> &&range) const { #if defined(RADEON_INFO_VRAM_USAGE) std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { std::uint64_t value; bool success = Utils::AMD::readRadeonInfoSensor( fd, &value, RADEON_INFO_VRAM_USAGE); return success ? value / (1024 * 1024) : 0; })); return std::make_unique>( AMD::MemUsage::ItemID, std::move(dataSources), std::move(range)); #else return {}; #endif } }; static bool register_() { GPUSensorProvider::registerProvider( std::make_unique()); ProfilePartProvider::registerProvider(AMD::MemUsage::ItemID, []() { return std::make_unique(AMD::MemUsage::ItemID, "forestgreen"); }); ProfilePartXMLParserProvider::registerProvider(AMD::MemUsage::ItemID, []() { return std::make_unique(AMD::MemUsage::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::MemUsage corectrl-v1.4.2/src/core/components/sensors/amd/memusage.h000066400000000000000000000004011467225065400236440ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::MemUsage { static constexpr std::string_view ItemID{"AMD_MEM_USAGE"}; } // namespace AMD::MemUsage corectrl-v1.4.2/src/core/components/sensors/amd/memusagegraphitem.cpp000066400000000000000000000012061467225065400261040ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "memusage.h" #include #include namespace AMD::MemUsage { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::MemUsage::ItemID, []() { return new SensorGraphItem( AMD::MemUsage::ItemID, units::data::megabyte_t().abbreviation()); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_MEM_USAGE"), }; } // namespace AMD::MemUsage corectrl-v1.4.2/src/core/components/sensors/amd/power.cpp000066400000000000000000000123401467225065400235350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "power.h" #include "../gpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/components/amdutils.h" #include "core/devfsdatasource.h" #include "core/info/igpuinfo.h" #include "core/info/vendor.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include namespace AMD::Power { class Provider final : public IGPUSensorProvider::IProvider { public: std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &) const override { if (gpuInfo.vendor() != Vendor::AMD) return {}; std::optional>>> dataSource; std::optional> range; auto hwmonPath = Utils::File::findHWMonXDirectory(gpuInfo.path().sys / "hwmon"); if (hwmonPath) { range = getRange(*hwmonPath); dataSource = createHWMonDataSource(*hwmonPath); } // The hwmon data source is not available. Try the ioctl data source. if (!dataSource) dataSource = createIOCtlDataSource(gpuInfo); if (!dataSource) return {}; std::vector> sensors; sensors.emplace_back( std::make_unique>( AMD::Power::ItemID, std::move(*dataSource), std::move(range))); return sensors; } private: std::optional>>> createIOCtlDataSource(IGPUInfo const &gpuInfo) const { #if defined(AMDGPU_INFO_SENSOR_GPU_AVG_POWER) std::vector>> dataSource; dataSource.emplace_back(std::make_unique>( gpuInfo.path().dev, [](int fd) { unsigned int value; bool success = Utils::AMD::readAMDGPUInfoSensor( fd, &value, AMDGPU_INFO_SENSOR_GPU_AVG_POWER); return success ? value : 0; })); return dataSource; #else return {}; #endif } std::optional>>> createHWMonDataSource(std::filesystem::path const &hwmonPath) const { // Try average power. auto powerPath = hwmonPath / "power1_average"; if (!Utils::File::isSysFSEntryValid(powerPath)) { // Some older models don't support average power. // Use instantaneous power instead. powerPath = hwmonPath / "power1_input"; if (!Utils::File::isSysFSEntryValid(powerPath)) return {}; } unsigned long data; auto powerLines = Utils::File::readFileLines(powerPath); if (!Utils::String::toNumber(data, powerLines.front())) return {}; std::vector>> dataSource; dataSource.emplace_back(std::make_unique>( powerPath, [](std::string const &data, unsigned int &output) { unsigned int power; Utils::String::toNumber(power, data); // Data source power unit is microwatt. Convert it to watt. output = power / 1000000; })); return dataSource; } std::optional> getRange(std::filesystem::path const &hwmonPath) const { auto power1CapMinPath = hwmonPath / "power1_cap_min"; auto power1CapMaxPath = hwmonPath / "power1_cap_max"; if (!(Utils::File::isSysFSEntryValid(power1CapMinPath) && Utils::File::isSysFSEntryValid(power1CapMaxPath))) return {}; unsigned long power1CapMinValue = 0; unsigned long power1CapMaxValue = 0; auto power1CapMinLines = Utils::File::readFileLines(power1CapMinPath); auto power1CapMaxLines = Utils::File::readFileLines(power1CapMaxPath); if (!(Utils::String::toNumber(power1CapMinValue, power1CapMinLines.front()) && Utils::String::toNumber(power1CapMaxValue, power1CapMaxLines.front()))) return {}; if (power1CapMaxValue <= power1CapMinValue) return {}; return std::make_optional( std::make_pair(units::power::microwatt_t(power1CapMinValue), units::power::microwatt_t(power1CapMaxValue))); } }; static bool register_() { GPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(AMD::Power::ItemID, []() { return std::make_unique(AMD::Power::ItemID, "gold"); }); ProfilePartXMLParserProvider::registerProvider(AMD::Power::ItemID, []() { return std::make_unique(AMD::Power::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace AMD::Power corectrl-v1.4.2/src/core/components/sensors/amd/power.h000066400000000000000000000003671467225065400232100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include namespace AMD::Power { static constexpr std::string_view ItemID{"AMD_POWER"}; } // namespace AMD::Power corectrl-v1.4.2/src/core/components/sensors/amd/powergraphitem.cpp000066400000000000000000000011551467225065400254400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "power.h" #include #include namespace AMD::Power { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( AMD::Power::ItemID, []() { return new SensorGraphItem( AMD::Power::ItemID, units::power::watt_t().abbreviation()); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "AMD_POWER"), }; } // namespace AMD::Power corectrl-v1.4.2/src/core/components/sensors/cpu/000077500000000000000000000000001467225065400217235ustar00rootroot00000000000000corectrl-v1.4.2/src/core/components/sensors/cpu/cpucoretemp.cpp000066400000000000000000000064651467225065400247700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Milan Cermak #include "cpucoretemp.h" #include "../cpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/idatasource.h" #include "core/info/icpuinfo.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include #include #include namespace CPUCoreTemp { class Provider final : public ICPUSensorProvider::IProvider { public: std::vector> provideCPUSensors(ICPUInfo const &cpuInfo, ISWInfo const &) const override { auto hwmonPath = std::format("/sys/devices/platform/coretemp.{}/hwmon", cpuInfo.physicalId()); auto path = Utils::File::findHWMonXDirectory(hwmonPath); if (!path) return {}; std::optional< std::pair> range; auto critFilePath = path.value() / "temp1_crit"; if (Utils::File::isFilePathValid(critFilePath)) { auto data = Utils::File::readFileLines(critFilePath); if (!data.empty()) { int value; if (Utils::String::toNumber(value, data.front()) && // do not use bogus values, see #103 (value >= 0 && value < 150000)) { range = {units::temperature::celsius_t(0), units::temperature::celsius_t(value / 1000.0)}; } } } auto tempInput = path.value() / "temp1_input"; if (!Utils::File::isSysFSEntryValid(tempInput)) return {}; int value; auto tempInputLines = Utils::File::readFileLines(tempInput); if (!Utils::String::toNumber(value, tempInputLines.front())) { SPDLOG_WARN("Unknown data format on {}", tempInput.string()); SPDLOG_DEBUG(tempInputLines.front()); return {}; } std::vector>> dataSources; dataSources.emplace_back(std::make_unique>( tempInput, [](std::string const &data, int &output) { int value; Utils::String::toNumber(value, data); output = value / 1000; })); std::vector> sensors; sensors.emplace_back( std::make_unique>( CPUCoreTemp::ItemID, std::move(dataSources), std::move(range))); return sensors; } }; static bool register_() { CPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(CPUCoreTemp::ItemID, []() { return std::make_unique(CPUCoreTemp::ItemID, "crimson"); }); ProfilePartXMLParserProvider::registerProvider(CPUCoreTemp::ItemID, []() { return std::make_unique(CPUCoreTemp::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace CPUCoreTemp corectrl-v1.4.2/src/core/components/sensors/cpu/cpucoretemp.h000066400000000000000000000006171467225065400244260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Milan Cermak #pragma once #include /// A sensor that monitors the temperature of Intel CPUs. /// /// This sensor uses the coretemp driver: /// https://docs.kernel.org/hwmon/coretemp.html namespace CPUCoreTemp { static constexpr std::string_view ItemID{"CPU_CORE_TEMP"}; } // namespace CPUCoreTemp corectrl-v1.4.2/src/core/components/sensors/cpu/cpucoretempgraphitem.cpp000066400000000000000000000011311467225065400266520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Milan Cermak #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "cpucoretemp.h" #include #include namespace CPUCoreTemp { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( CPUCoreTemp::ItemID, []() { return new SensorGraphItem( CPUCoreTemp::ItemID, "\u00B0C"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "CPU_CORE_TEMP"), }; } // namespace CPUCoreTemp corectrl-v1.4.2/src/core/components/sensors/cpu/cpufreqpack.cpp000066400000000000000000000103001467225065400247250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpufreqpack.h" #include "../cpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "core/idatasource.h" #include "core/info/icpuinfo.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include #include namespace CPUFreqPack { class Provider final : public ICPUSensorProvider::IProvider { public: std::vector> provideCPUSensors(ICPUInfo const &cpuInfo, ISWInfo const &) const override { if (!Utils::File::isDirectoryPathValid("/sys/devices/system/cpu/cpufreq")) return {}; auto &executionUnits = cpuInfo.executionUnits(); if (executionUnits.empty()) return {}; std::optional< std::pair> range; auto minFreqPath = executionUnits.front().sysPath / "cpufreq/cpuinfo_min_freq"; auto maxFreqPath = executionUnits.front().sysPath / "cpufreq/cpuinfo_max_freq"; if (Utils::File::isSysFSEntryValid(minFreqPath) && Utils::File::isSysFSEntryValid(maxFreqPath)) { auto minFreqLines = Utils::File::readFileLines(minFreqPath); auto maxFreqLines = Utils::File::readFileLines(maxFreqPath); unsigned int minFreq{0}; unsigned int maxFreq{0}; if (Utils::String::toNumber(minFreq, minFreqLines.front()) && Utils::String::toNumber(maxFreq, maxFreqLines.front())) { if (minFreq < maxFreq) range = {units::frequency::kilohertz_t(minFreq), units::frequency::kilohertz_t(maxFreq)}; } } std::vector>> dataSources; for (auto const &executionUnit : cpuInfo.executionUnits()) { auto curFreqPath = executionUnit.sysPath / "cpufreq/scaling_cur_freq"; if (!Utils::File::isSysFSEntryValid(curFreqPath)) continue; unsigned int value; auto curFreqLines = Utils::File::readFileLines(curFreqPath); if (!Utils::String::toNumber(value, curFreqLines.front())) { SPDLOG_WARN("Unknown data format on {}", curFreqPath.string()); SPDLOG_DEBUG(curFreqLines.front()); continue; } dataSources.emplace_back(std::make_unique>( curFreqPath, [](std::string const &data, unsigned int &output) { Utils::String::toNumber(output, data); })); } if (dataSources.empty()) return {}; std::vector> sensors; sensors.emplace_back( std::make_unique>( CPUFreqPack::ItemID, std::move(dataSources), std::move(range), [](std::vector const &input) { auto maxIter = std::max_element(input.cbegin(), input.cend()); if (maxIter != input.cend()) { units::frequency::kilohertz_t maxKHz(*maxIter); return maxKHz.convert() .to(); } else return 0u; })); return sensors; } }; static bool register_() { CPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(CPUFreqPack::ItemID, []() { return std::make_unique(CPUFreqPack::ItemID, "fuchsia"); }); ProfilePartXMLParserProvider::registerProvider(CPUFreqPack::ItemID, []() { return std::make_unique(CPUFreqPack::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace CPUFreqPack corectrl-v1.4.2/src/core/components/sensors/cpu/cpufreqpack.h000066400000000000000000000007011467225065400243760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include /// A sensor that monitors the operation frequency of a physical cpu package. /// The reported frequency is computed as the highest operation frequency /// of all its execution units at the time. namespace CPUFreqPack { static constexpr std::string_view ItemID{"CPU_FREQ_PACK"}; } // namespace CPUFreqPack corectrl-v1.4.2/src/core/components/sensors/cpu/cpufreqpackgraphitem.cpp000066400000000000000000000012151467225065400266330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "cpufreqpack.h" #include #include namespace CPUFreqPack { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( CPUFreqPack::ItemID, []() { return new SensorGraphItem( CPUFreqPack::ItemID, units::frequency::megahertz_t().abbreviation()); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "CPU_FREQ_PACK"), }; } // namespace CPUFreqPack corectrl-v1.4.2/src/core/components/sensors/cpu/cpuusage.cpp000066400000000000000000000054471467225065400242550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Milan Cermak // Copyright 2023 Juan Palacios #include "cpuusage.h" #include "../cpusensorprovider.h" #include "../graphitemprofilepart.h" #include "../graphitemxmlparser.h" #include "../sensor.h" #include "core/components/cpuutils.h" #include "core/idatasource.h" #include "core/info/icpuinfo.h" #include "core/iprofilepart.h" #include "core/iprofilepartxmlparser.h" #include "core/profilepartprovider.h" #include "core/profilepartxmlparserprovider.h" #include "core/sysfsdatasource.h" #include #include #include #include #include #include #include #include namespace CPUUsage { class CPUUsageDataSource : public IDataSource { public: CPUUsageDataSource() noexcept : procStatDataSource_("/proc/stat") { } std::string source() const override { return procStatDataSource_.source(); } bool read(unsigned int &usedCPU) override { if (procStatDataSource_.read(rawData_)) { auto stat = Utils::CPU::parseProcStat(rawData_); rawData_.clear(); if (stat.has_value()) { if (prevStat_.has_value()) usedCPU = Utils::CPU::computeCPUUsage(*prevStat_, *stat); else usedCPU = 0; prevStat_.swap(stat); return true; } } return false; } private: SysFSDataSource> procStatDataSource_; std::vector rawData_; std::optional prevStat_; }; class Provider final : public ICPUSensorProvider::IProvider { public: std::vector> provideCPUSensors(ICPUInfo const &, ISWInfo const &) const override { std::vector> sensors; std::vector>> dataSources; dataSources.emplace_back(std::make_unique()); sensors.emplace_back( std::make_unique>( CPUUsage::ItemID, std::move(dataSources), std::make_pair(units::dimensionless::scalar_t(0), units::dimensionless::scalar_t(100)))); return sensors; } }; static bool register_() { CPUSensorProvider::registerProvider(std::make_unique()); ProfilePartProvider::registerProvider(CPUUsage::ItemID, []() { return std::make_unique(CPUUsage::ItemID, "yellowgreen"); }); ProfilePartXMLParserProvider::registerProvider(CPUUsage::ItemID, []() { return std::make_unique(CPUUsage::ItemID); }); return true; } static bool const registered_ = register_(); } // namespace CPUUsage corectrl-v1.4.2/src/core/components/sensors/cpu/cpuusage.h000066400000000000000000000004271467225065400237130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Milan Cermak #pragma once #include /// A sensor that monitors the CPU usage. namespace CPUUsage { static constexpr std::string_view ItemID{"CPU_USAGE"}; } // namespace CPUUsage corectrl-v1.4.2/src/core/components/sensors/cpu/cpuusagegraphitem.cpp000066400000000000000000000011121467225065400261370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Milan Cermak #include "../sensorgraphitem.h" #include "core/qmlcomponentregistry.h" #include "cpuusage.h" #include #include namespace CPUUsage { bool const registered_ = QMLComponentRegistry::addQuickItemProvider( CPUUsage::ItemID, []() { return new SensorGraphItem( CPUUsage::ItemID, "%"); }); char const *const trStrings[] = { QT_TRANSLATE_NOOP("SensorGraph", "CPU_USAGE"), }; } // namespace CPUUsage corectrl-v1.4.2/src/core/components/sensors/cpusensorprovider.cpp000066400000000000000000000012711467225065400254350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpusensorprovider.h" #include std::vector> const & CPUSensorProvider::cpuSensorProviders() const { return cpuSensorProviders_(); } std::vector> & CPUSensorProvider::cpuSensorProviders_() { static std::vector> providers; return providers; } bool CPUSensorProvider::registerProvider( std::unique_ptr &&provider) { cpuSensorProviders_().emplace_back(std::move(provider)); return true; } corectrl-v1.4.2/src/core/components/sensors/cpusensorprovider.h000066400000000000000000000010701467225065400250770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icpusensorprovider.h" #include #include class CPUSensorProvider final : public ICPUSensorProvider { public: std::vector> const & cpuSensorProviders() const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & cpuSensorProviders_(); }; corectrl-v1.4.2/src/core/components/sensors/gpusensorprovider.cpp000066400000000000000000000012711467225065400254410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpusensorprovider.h" #include std::vector> const & GPUSensorProvider::gpuSensorProviders() const { return gpuSensorProviders_(); } std::vector> & GPUSensorProvider::gpuSensorProviders_() { static std::vector> providers; return providers; } bool GPUSensorProvider::registerProvider( std::unique_ptr &&provider) { gpuSensorProviders_().emplace_back(std::move(provider)); return true; } corectrl-v1.4.2/src/core/components/sensors/gpusensorprovider.h000066400000000000000000000010701467225065400251030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "igpusensorprovider.h" #include #include class GPUSensorProvider final : public IGPUSensorProvider { public: std::vector> const & gpuSensorProviders() const override; static bool registerProvider(std::unique_ptr &&provider); private: static std::vector> & gpuSensorProviders_(); }; corectrl-v1.4.2/src/core/components/sensors/graphitem.cpp000066400000000000000000000077171467225065400236340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "graphitem.h" #include #include #include #include unsigned short const GraphItem::PointsCount = 120; GraphItem::GraphItem(std::string_view name, std::string_view unit) : QQuickItem() , name_(name.data()) , unit_(unit.data()) , yMin_(std::numeric_limits::max()) , yMax_(std::numeric_limits::min()) { setObjectName(name_); points_.reserve(GraphItem::PointsCount); connect(this, &GraphItem::visibleChanged, this, &GraphItem::refreshSeriePoints); } QString const &GraphItem::name() const { return name_; } QString const &GraphItem::unit() const { return unit_; } QString GraphItem::color() const { return QString::fromStdString(color_); } qreal GraphItem::value() const { return value_; } void GraphItem::initialRange(qreal min, qreal max) { if (max > min) { yMin_ = min; yMax_ = max; } } void GraphItem::updateGraph(qreal value) { if (series_ != nullptr && !ignored()) { if (points_.size() == PointsCount) points_.removeFirst(); qreal newX; auto lastX = points_.empty() ? PointsCount : points_.last().x(); if (static_cast(lastX) == std::numeric_limits::max()) { // 65535 * 0.5 / 60 / 60 ~> 9h 10min @ 0.5s refresh rate between restarts restartXPoints(); newX = PointsCount; } else { newX = lastX + 1; } points_.append(QPointF(newX, value)); QTimer::singleShot(0, this, &GraphItem::refreshSeriePoints); // update axes xAxis_->setRange(newX - PointsCount + 1, newX); updateYAxis(value); value_ = value; emit valueChanged(value); } } std::optional> GraphItem::provideImporter(Item const &) { return {}; } std::optional> GraphItem::provideExporter(Item const &) { return {}; } bool GraphItem::provideActive() const { return active_; } std::string const &GraphItem::provideColor() const { return color_; } void GraphItem::takeActive(bool active) { if (active_ != active) { active_ = active; if (series_ != nullptr) series_->setVisible(active); emit activeChanged(active); } } void GraphItem::takeColor(std::string const &color) { if (!color.empty() && color_ != color) { color_ = color; if (series_ != nullptr) series_->setColor(color_.c_str()); emit colorChanged(QString::fromStdString(color_)); } } void GraphItem::configure(QAbstractSeries *series, QAbstractAxis *xAxis, QAbstractAxis *yAxis) { series_ = dynamic_cast(series); series_->setColor(color_.c_str()); series_->setVisible(active_); xAxis_ = xAxis; yAxis_ = yAxis; xAxis_->setRange(1, PointsCount); yAxis_->setRange(yMin_, yMax_); } void GraphItem::updateYAxisRange(qreal min, qreal max) { yMin_ = std::min(yMin_, min); yMax_ = std::max(yMax_, (max > yMin_) ? max : yMin_ + 1); yAxis_->setRange(yMin_, yMax_); } void GraphItem::refreshSeriePoints() { if (isVisible() && series_ != nullptr) series_->replace(points_); } bool GraphItem::active() const { return provideActive(); } void GraphItem::active(bool active) { if (active_ != active) { active_ = active; if (series_ != nullptr) series_->setVisible(active); emit settingsChanged(); } } bool GraphItem::ignored() const { return ignored_; } void GraphItem::ignored(bool ignored) { if (ignored_ != ignored) { ignored_ = ignored; if (series_ != nullptr) series_->setVisible(active_ && !ignored_); emit ignoredChanged(ignored); } } void GraphItem::updateYAxis(qreal value) { if (value < yMin_ || value > yMax_) { updateYAxisRange(value, value); emit yAxisRangeChanged(yMin_, yMax_); } } void GraphItem::restartXPoints() { int pointX = 1; for (auto &point : points_) point.rx() = pointX++; } corectrl-v1.4.2/src/core/components/sensors/graphitem.h000066400000000000000000000050361467225065400232710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "graphitemprofilepart.h" #include #include #include #include #include #include #include #include #include #include QT_CHARTS_USE_NAMESPACE class GraphItem : public QQuickItem , public GraphItemProfilePart::Importer , public GraphItemProfilePart::Exporter { Q_OBJECT Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(qreal value READ value NOTIFY valueChanged) Q_PROPERTY(bool active READ active WRITE active NOTIFY activeChanged) Q_PROPERTY(bool ignored READ ignored WRITE ignored NOTIFY ignoredChanged) Q_PROPERTY(QString unit READ unit) Q_PROPERTY(QString color READ color) public: GraphItem(std::string_view name, std::string_view unit); QString const &name() const; QString const &unit() const; QString color() const; qreal value() const; void initialRange(qreal min, qreal max); void updateGraph(qreal value); std::optional> provideImporter(Item const &i) final override; std::optional> provideExporter(Item const &i) final override; bool provideActive() const final override; std::string const &provideColor() const final override; void takeActive(bool active) override; void takeColor(std::string const &color) override; virtual void init(Exportable const *e) = 0; public slots: void configure(QAbstractSeries *series, QAbstractAxis *xAxis, QAbstractAxis *yAxis); void updateYAxisRange(qreal min, qreal max); void refreshSeriePoints(); virtual void update() = 0; signals: void settingsChanged(); void nameChanged(); void valueChanged(qreal value); void activeChanged(bool active); void colorChanged(QString const &color); void ignoredChanged(bool ignored); void yAxisRangeChanged(qreal min, qreal max); private: bool active() const; void active(bool active); bool ignored() const; void ignored(bool ignored); void updateYAxis(qreal value); void restartXPoints(); static unsigned short const PointsCount; QString const name_; QString const unit_; std::string color_{"white"}; bool active_{true}; bool ignored_{false}; qreal value_{0}; QList points_; QLineSeries *series_{nullptr}; QAbstractAxis *xAxis_; QAbstractAxis *yAxis_; qreal yMin_; qreal yMax_; }; corectrl-v1.4.2/src/core/components/sensors/graphitemprofilepart.cpp000066400000000000000000000021661467225065400260750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "graphitemprofilepart.h" #include GraphItemProfilePart::GraphItemProfilePart(std::string_view id, std::string_view color) noexcept : id_(id) , color_(color) { } std::unique_ptr GraphItemProfilePart::factory(IProfilePartProvider const &) { return nullptr; } std::unique_ptr GraphItemProfilePart::initializer() { return nullptr; } std::string const &GraphItemProfilePart::ID() const { return id_; } void GraphItemProfilePart::importProfilePart(IProfilePart::Importer &i) { auto &itemImporter = dynamic_cast(i); color_ = itemImporter.provideColor(); } void GraphItemProfilePart::exportProfilePart(IProfilePart::Exporter &e) const { auto &itemExporter = dynamic_cast(e); itemExporter.takeColor(color_); } std::unique_ptr GraphItemProfilePart::cloneProfilePart() const { return std::make_unique(id_, color_); } corectrl-v1.4.2/src/core/components/sensors/graphitemprofilepart.h000066400000000000000000000020471467225065400255400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepart.h" #include #include class GraphItemProfilePart : public ProfilePart { public: class Importer : public IProfilePart::Importer { public: virtual std::string const &provideColor() const = 0; }; class Exporter : public IProfilePart::Exporter { public: virtual void takeColor(std::string const &color) = 0; }; GraphItemProfilePart(std::string_view id, std::string_view color) noexcept; std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) override; std::unique_ptr initializer() override; std::string const &ID() const override; protected: void importProfilePart(IProfilePart::Importer &i) override; void exportProfilePart(IProfilePart::Exporter &e) const override; std::unique_ptr cloneProfilePart() const override; private: std::string id_; std::string color_; }; corectrl-v1.4.2/src/core/components/sensors/graphitemxmlparser.cpp000066400000000000000000000043301467225065400255560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "graphitemxmlparser.h" #include class GraphItemXMLParser::Initializer final : public GraphItemProfilePart::Exporter { public: Initializer(GraphItemXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &) override { return {}; } void takeActive(bool active) override; void takeColor(std::string const &color) override; private: GraphItemXMLParser &outer_; }; void GraphItemXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void GraphItemXMLParser::Initializer::takeColor(std::string const &color) { outer_.colorDefault_ = color; } GraphItemXMLParser::GraphItemXMLParser(std::string_view id) noexcept : ProfilePartXMLParser(id, *this, *this) { } std::unique_ptr GraphItemXMLParser::factory(IProfilePartXMLParserProvider const &) { return nullptr; } std::unique_ptr GraphItemXMLParser::initializer() { return std::make_unique(*this); } std::optional> GraphItemXMLParser::provideExporter(Item const &) { return {}; } std::optional> GraphItemXMLParser::provideImporter(Item const &) { return {}; } void GraphItemXMLParser::takeActive(bool active) { active_ = active; } bool GraphItemXMLParser::provideActive() const { return active_; } void GraphItemXMLParser::takeColor(const std::string &) { } std::string const &GraphItemXMLParser::provideColor() const { return colorDefault_; } void GraphItemXMLParser::appendTo(pugi::xml_node &parentNode) { auto itemNode = parentNode.append_child(ID().c_str()); itemNode.append_attribute("active") = active_; } void GraphItemXMLParser::resetAttributes() { active_ = activeDefault_; } void GraphItemXMLParser::loadPartFrom(pugi::xml_node const &parentNode) { auto itemNode = parentNode.find_child( [&](pugi::xml_node const &node) { return node.name() == ID(); }); active_ = itemNode.attribute("active").as_bool(activeDefault_); } corectrl-v1.4.2/src/core/components/sensors/graphitemxmlparser.h000066400000000000000000000024531467225065400252270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/profilepartxmlparser.h" #include "graphitemprofilepart.h" #include #include #include class GraphItemXMLParser final : public ProfilePartXMLParser , public GraphItemProfilePart::Exporter , public GraphItemProfilePart::Importer { public: GraphItemXMLParser(std::string_view id) noexcept; std::unique_ptr factory( IProfilePartXMLParserProvider const &profilePartParserProvider) override; std::unique_ptr initializer() override; std::optional> provideImporter(const Item &i) override; std::optional> provideExporter(const Item &i) override; void takeActive(bool active) override; bool provideActive() const override; void takeColor(const std::string &color) override; std::string const &provideColor() const override; void appendTo(pugi::xml_node &parentNode) override; protected: void resetAttributes() override; void loadPartFrom(pugi::xml_node const &parentNode) override; private: class Initializer; bool active_; bool activeDefault_; std::string colorDefault_; }; corectrl-v1.4.2/src/core/components/sensors/icpusensorprovider.h000066400000000000000000000014071467225065400252540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class ISensor; class ICPUInfo; class ISWInfo; class ICPUSensorProvider { public: /// Classes that provides instances of Sensor specializations must /// implement this interface. class IProvider { public: /// Returns a list with the CPU sensors supported by the provider. virtual std::vector> provideCPUSensors(ICPUInfo const &cpuInfo, ISWInfo const &swInfo) const = 0; virtual ~IProvider() = default; }; virtual std::vector> const & cpuSensorProviders() const = 0; virtual ~ICPUSensorProvider() = default; }; corectrl-v1.4.2/src/core/components/sensors/igpusensorprovider.h000066400000000000000000000014071467225065400252600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class ISensor; class IGPUInfo; class ISWInfo; class IGPUSensorProvider { public: /// Classes that provides instances of Sensor specializations must /// implement this interface. class IProvider { public: /// Returns a list with the GPU sensors supported by the provider. virtual std::vector> provideGPUSensors(IGPUInfo const &gpuInfo, ISWInfo const &swInfo) const = 0; virtual ~IProvider() = default; }; virtual std::vector> const & gpuSensorProviders() const = 0; virtual ~IGPUSensorProvider() = default; }; corectrl-v1.4.2/src/core/components/sensors/isensor.h000066400000000000000000000004461467225065400227730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/exportable.h" #include "core/item.h" class ISensor : public Item , public Exportable { public: virtual void update() = 0; virtual ~ISensor() = default; }; corectrl-v1.4.2/src/core/components/sensors/sensor.h000066400000000000000000000043251467225065400226220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/sensors/isensor.h" #include "core/idatasource.h" #include #include #include #include #include #include #include #include #include template class Sensor : public ISensor { public: class Exporter : public ISensor::Exporter { public: virtual void takeValue(Unit value) = 0; virtual void takeRange(std::optional> const &range) = 0; }; Sensor( std::string_view id, std::vector>> &&dataSources, std::optional> &&range = std::nullopt, std::function const &)> &&transform = [](std::vector const &input) { return input[0]; }) noexcept : id_(id) , dataSources_(std::move(dataSources)) , range_(std::move(range)) , transform_(std::move(transform)) , value_(units::make_unit(0)) { transformValues_.resize(dataSources_.size(), 0); } std::string const &ID() const override { return id_; } void exportWith(ISensor::Exporter &e) const override { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { auto &sensorExporter = dynamic_cast::Exporter &>(exporter->get()); sensorExporter.takeValue(value()); sensorExporter.takeRange(range_); } } void update() override { if (!dataSources_.empty()) { for (size_t i = 0; i < dataSources_.size(); ++i) dataSources_[i]->read(transformValues_[i]); value(transform_(transformValues_)); } } protected: Unit value() const { return value_.load(std::memory_order_relaxed); } void value(T value) { value_.store(units::make_unit(value), std::memory_order_relaxed); } private: std::string const id_; std::vector>> const dataSources_; std::optional> const range_; std::function const &)> const transform_; std::vector transformValues_; std::atomic value_; }; corectrl-v1.4.2/src/core/components/sensors/sensorgraphitem.h000066400000000000000000000041511467225065400245200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/exportable.h" #include "graphitem.h" #include "sensor.h" #include #include #include #include #include template class SensorReader final : public Sensor::Exporter { public: SensorReader( std::string_view id, std::function &&onValue, std::function> const &)> &&onRange) : id_(id) , onValue_(std::move(onValue)) , onRange_(std::move(onRange)) { } std::optional> provideExporter(Item const &i) override { if (i.ID() == id_) return *this; return {}; } void takeValue(Unit value) override { onValue_(value); } void takeRange(std::optional> const &range) override { onRange_(range); } private: std::string_view const id_; std::function const onValue_; std::function> const &)> const onRange_; }; template class SensorGraphItem final : public GraphItem { public: SensorGraphItem(std::string_view id, std::string_view unit) noexcept : GraphItem(id, unit) , valueReader_( id, [&](Unit value) { this->updateGraph(value.template to()); }, [](std::optional> const &) {}) , rangeReader_( id, [&](Unit) {}, [&](std::optional> const &range) { if (range.has_value()) { this->initialRange(range.value().first.template to(), range.value().second.template to()); } }) { } void init(Exportable const *sensor) override { sensor_ = sensor; sensor_->exportWith(rangeReader_); } void update() override { sensor_->exportWith(valueReader_); } private: SensorReader valueReader_; SensorReader rangeReader_; Exportable const *sensor_; }; corectrl-v1.4.2/src/core/devfsdatasource.h000066400000000000000000000017111467225065400206060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include #include #include #include #include #include #include template class DevFSDataSource : public IDataSource { public: DevFSDataSource(std::filesystem::path const &path, std::function &&reader) noexcept : path_(path.string()) , reader_(std::move(reader)) { fd_ = open(path.c_str(), O_RDONLY); if (fd_ < 0) SPDLOG_DEBUG("Cannot open {}", path.c_str()); } ~DevFSDataSource() override { if (fd_ > 0) close(fd_); } std::string source() const override { return path_; } bool read(T &data) override { data = reader_(fd_); return true; } private: std::string const path_; std::function const reader_; int fd_; }; corectrl-v1.4.2/src/core/exportable.h000066400000000000000000000007501467225065400175730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class Item; class Exportable { public: class Exporter { public: virtual std::optional> provideExporter(Item const &i) = 0; virtual ~Exporter() = default; }; virtual void exportWith(Exportable::Exporter &e) const = 0; virtual ~Exportable() = default; }; corectrl-v1.4.2/src/core/filecache.cpp000066400000000000000000000052541467225065400176700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "filecache.h" #include "common/fileutils.h" #include #include #include #include #include namespace fs = std::filesystem; FileCache::FileCache(std::filesystem::path &&path) noexcept : path_(std::move(path)) { } void FileCache::init() { if (!fs::exists(path_)) { fs::create_directories(path_); fs::permissions(path_, fs::perms::owner_all | fs::perms::group_read | fs::perms::group_exec | fs::perms::others_read | fs::perms::others_exec); } if (!fs::is_directory(path_)) throw std::runtime_error( std::format("{} is not a directory.", path_.c_str())); } std::optional FileCache::add(std::filesystem::path const &path, std::string const &name) { if (cacheDirectoryExist()) { if (Utils::File::isFilePathValid(path)) { auto target = path_ / name; if (path != target) { try { fs::copy_file(path, target, fs::copy_options::overwrite_existing); return {target}; } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } else // file is on cache return {target}; } else SPDLOG_DEBUG("Cannot add {} to cache. Invalid or missing file.", path.c_str()); } return {}; } std::optional FileCache::add(std::vector const &data, std::string const &name) { if (cacheDirectoryExist()) { auto target = path_ / name; if (Utils::File::writeFile(target, data)) return {target}; } return {}; } void FileCache::remove(std::string const &name) { if (cacheDirectoryExist()) { auto target = path_ / name; try { fs::remove(target); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } } std::optional FileCache::get(std::string const &name, std::filesystem::path const &defaultPath) const { if (cacheDirectoryExist()) { auto target = path_ / name; if (Utils::File::isFilePathValid(target)) return {target}; else SPDLOG_WARN("Cannot get {} from cache. Invalid or missing file.", target.c_str()); } if (!defaultPath.empty()) return {defaultPath}; else return {}; } std::filesystem::path FileCache::path() const { return path_; } bool FileCache::cacheDirectoryExist() const { if (Utils::File::isDirectoryPathValid(path_)) return true; SPDLOG_DEBUG("Missing or invalid cache directory {}", path_.c_str()); return false; } corectrl-v1.4.2/src/core/filecache.h000066400000000000000000000016221467225065400173300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "ifilecache.h" #include class FileCache : public IFileCache { public: FileCache(std::filesystem::path &&path) noexcept; void init() override; std::optional add(std::filesystem::path const &path, std::string const &name) override; std::optional add(std::vector const &data, std::string const &name) override; void remove(std::string const &name) override; std::optional get(std::string const &name, std::filesystem::path const &defaultPath) const override; std::filesystem::path path() const override; private: bool cacheDirectoryExist() const; std::filesystem::path const path_; }; corectrl-v1.4.2/src/core/icommandqueue.h000066400000000000000000000023361467225065400202640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include class QByteArray; class ICommandQueue { public: /// Activates or deactivates command packing. /// When command packing is activated, all subsequent queued /// commands writing to the same file will be packed together. /// Activation only have effect the first time it's used. /// @param activate whether to activate command packing virtual void pack(bool activate) = 0; /// When command packing is active, returns whether the pack /// contains any command that writes to the specified file. /// If packing mode is not active, the optional will be null. /// @param file file to search for in the pack virtual std::optional packWritesTo(std::string const &file) = 0; /// Adds a command to the end of the queue. /// If the command was already queued, there is no effect in the queue. /// @param cmd command to queue virtual void add(std::pair &&cmd) = 0; /// Transform all commands into raw data, cleaning the command queue. virtual QByteArray toRawData() = 0; virtual ~ICommandQueue() = default; }; corectrl-v1.4.2/src/core/idatasink.h000066400000000000000000000010011467225065400173630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include /// Interface of a data sink. /// A data sink only receives data. template class IDataSink { public: /// Where the data goes to. /// @returns sink name virtual std::string sink() const = 0; /// Write the data to the sink. /// @return true when the operation succeed virtual bool write(Ts const &...args) = 0; virtual ~IDataSink() = default; }; corectrl-v1.4.2/src/core/idatasource.h000066400000000000000000000011121467225065400177220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include /// Interface of a data source. /// A data source only provides data. template class IDataSource { public: /// Where the data comes from. /// @returns source name virtual std::string source() const = 0; /// Read the data from the source. The readed data is stored into /// this function arguments. /// @return true when the operation succeed virtual bool read(Ts &...args) = 0; virtual ~IDataSource() = default; }; corectrl-v1.4.2/src/core/ifilecache.h000066400000000000000000000031171467225065400175020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include class IFileCache { public: /// Initializes the file chache. virtual void init() = 0; /// Adds an existing file to the cache. /// @param path to the file to be cached /// @param name target name for the cached file /// @return path to the cached file when succeed virtual std::optional add(std::filesystem::path const &path, std::string const &name) = 0; /// Adds a new file containing data to the cache. /// @param data new file data to be cached /// @param name target name for the cached file /// @return path to the cached file when succeed virtual std::optional add(std::vector const &data, std::string const &name) = 0; /// Removes a cached file. /// @param name name of the cached file to remove virtual void remove(std::string const &name) = 0; /// Gets the path of a file in the cache. /// @param name name of the file /// @param defaultPath path to be returned if no file exists on the cache /// @return path to the file or defaultPath is set and no file with that name exists /// on the cache virtual std::optional get(std::string const &name, std::filesystem::path const &defaultPath = "") const = 0; /// Gets the path to the cache. virtual std::filesystem::path path() const = 0; virtual ~IFileCache() = default; }; corectrl-v1.4.2/src/core/importable.h000066400000000000000000000007421467225065400175650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class Item; class Importable { public: class Importer { public: virtual std::optional> provideImporter(Item const &i) = 0; virtual ~Importer() = default; }; virtual void importWith(Importable::Importer &i) = 0; virtual ~Importable() = default; }; corectrl-v1.4.2/src/core/info/000077500000000000000000000000001467225065400162065ustar00rootroot00000000000000corectrl-v1.4.2/src/core/info/amd/000077500000000000000000000000001467225065400167475ustar00rootroot00000000000000corectrl-v1.4.2/src/core/info/amd/gpuinfoodfanctrl.cpp000066400000000000000000000023301467225065400230150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "gpuinfoodfanctrl.h" #include "common/fileutils.h" #include "core/info/infoproviderregistry.h" #include #include #include #include AMD::GPUInfoOdFanCtrl::GPUInfoOdFanCtrl() noexcept { } std::vector> AMD::GPUInfoOdFanCtrl::provideInfo(Vendor, int, IGPUInfo::Path const &, IHWIDTranslator const &) const { return {}; } std::vector AMD::GPUInfoOdFanCtrl::provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const { std::vector cap; if (vendor == Vendor::AMD) { auto fanCtlPath = path.sys / "gpu_od" / "fan_ctrl"; try { if (Utils::File::isDirectoryPathValid(fanCtlPath) && !std::filesystem::is_empty(fanCtlPath)) { cap.emplace_back(GPUInfoOdFanCtrl::ID); } } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } return cap; } bool AMD::GPUInfoOdFanCtrl::registered_ = InfoProviderRegistry::add(std::make_unique()); corectrl-v1.4.2/src/core/info/amd/gpuinfoodfanctrl.h000066400000000000000000000014301467225065400224620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include "../igpuinfo.h" #include #include namespace AMD { /// AMD GPU overdrive fan control info class GPUInfoOdFanCtrl final : public IGPUInfo::IProvider { public: static constexpr std::string_view ID{"odfanctrl"}; GPUInfoOdFanCtrl() noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path) const override; private: static bool registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/info/amd/gpuinfopm.cpp000066400000000000000000000057031467225065400214640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfopm.h" #include "common/fileutils.h" #include "core/info/infoproviderregistry.h" #include #include namespace AMD { class GPUInfoPMLegacyDataSource : public IDataSource { public: std::string source() const override { return "power_method"; } bool read(std::string &data, std::filesystem::path const &path) override { auto const filePath = path / source(); if (Utils::File::isFilePathValid(filePath)) { auto const lines = Utils::File::readFileLines(filePath); if (!lines.empty()) { data = lines.front(); return true; } else { SPDLOG_WARN("Cannot retrieve device power_method from {}", filePath.c_str()); } } return false; } }; class GPUInfoPMDPMDataSource : public IDataSource { public: std::string source() const override { return "power_dpm_force_performance_level"; } bool read(std::string &, std::filesystem::path const &path) override { // newer gpus uses 'power_dpm_force_performance_level' file auto const filePath = path / source(); if (Utils::File::isSysFSEntryValid(filePath)) return true; return false; } }; } // namespace AMD AMD::GPUInfoPM::GPUInfoPM( std::vector>> &&dataSources) noexcept : dataSources_(std::move(dataSources)) { } std::vector> AMD::GPUInfoPM::provideInfo(Vendor, int, IGPUInfo::Path const &, IHWIDTranslator const &) const { return {}; } std::vector AMD::GPUInfoPM::provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const { std::vector caps; if (vendor == Vendor::AMD) { for (auto &dataSource : dataSources_) { std::string data; if (dataSource->read(data, path.sys)) { // Older gpus have 'power_method' file if (dataSource->source() == "power_method") { if (data == "dynpm" || data == "profile") caps.emplace_back(GPUInfoPM::Legacy); else if (data == "dpm") caps.emplace_back(GPUInfoPM::Radeon); } // Newer gpus uses 'power_dpm_force_performance_level' file else if (dataSource->source() == "power_dpm_force_performance_level") { caps.emplace_back(GPUInfoPM::Amdgpu); } } } } return caps; } bool AMD::GPUInfoPM::registered_ = InfoProviderRegistry::add(std::make_unique( std::vector< std::shared_ptr>>( {std::make_shared(), std::make_shared()}))); corectrl-v1.4.2/src/core/info/amd/gpuinfopm.h000066400000000000000000000022761467225065400211330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include #include namespace AMD { /// AMD Power management GPU info class GPUInfoPM final : public IGPUInfo::IProvider { public: static constexpr std::string_view Legacy{"pmlegacy"}; static constexpr std::string_view Radeon{"pmradeon"}; static constexpr std::string_view Amdgpu{"pmamdgpu"}; GPUInfoPM(std::vector< std::shared_ptr>> &&dataSources) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path) const override; private: std::vector>> const dataSources_; static bool registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/info/amd/gpuinfopmoverdrive.cpp000066400000000000000000000043611467225065400234110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfopmoverdrive.h" #include "common/fileutils.h" #include "core/components/amdutils.h" #include "core/info/infoproviderregistry.h" #include #include namespace AMD { class GPUInfoPMOverdriveDataSource : public IDataSource, std::filesystem::path const> { public: std::string source() const override { return "pp_od_clk_voltage"; } bool read(std::vector &data, std::filesystem::path const &path) override { auto const filePath = path / source(); if (Utils::File::isSysFSEntryValid(filePath)) { auto lines = Utils::File::readFileLines(filePath); if (!lines.empty()) { data = lines; return true; } } return false; } }; } // namespace AMD AMD::GPUInfoPMOverdrive::GPUInfoPMOverdrive( std::unique_ptr, std::filesystem::path const>> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> AMD::GPUInfoPMOverdrive::provideInfo(Vendor, int, IGPUInfo::Path const &, IHWIDTranslator const &) const { return {}; } std::vector AMD::GPUInfoPMOverdrive::provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const { std::vector cap; if (vendor == Vendor::AMD) { std::vector data; if (dataSource_->read(data, path.sys)) { if (Utils::AMD::hasOverdriveClkVoltControl(data)) cap.emplace_back(GPUInfoPMOverdrive::ClkVolt); else if (Utils::AMD::hasOverdriveClkControl(data)) cap.emplace_back(GPUInfoPMOverdrive::Clk); if (Utils::AMD::hasOverdriveVoltCurveControl(data)) cap.emplace_back(GPUInfoPMOverdrive::VoltCurve); if (Utils::AMD::hasOverdriveVoltOffsetControl(data)) cap.emplace_back(GPUInfoPMOverdrive::VoltOffset); } } return cap; } bool AMD::GPUInfoPMOverdrive::registered_ = InfoProviderRegistry::add(std::make_unique( std::make_unique())); corectrl-v1.4.2/src/core/info/amd/gpuinfopmoverdrive.h000066400000000000000000000024561467225065400230610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include #include namespace AMD { /// AMD power management overdrive GPU info class GPUInfoPMOverdrive final : public IGPUInfo::IProvider { public: static constexpr std::string_view ClkVolt{"pmodclkvolt"}; static constexpr std::string_view Clk{"pmodclk"}; static constexpr std::string_view VoltCurve{"pmodvoltcurve"}; static constexpr std::string_view VoltOffset{"pmodvoltoffset"}; GPUInfoPMOverdrive( std::unique_ptr, std::filesystem::path const>> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path) const override; private: std::unique_ptr, std::filesystem::path const>> const dataSource_; static bool registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/info/amd/gpuinfouniqueid.cpp000066400000000000000000000035341467225065400226730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Juan Palacios #include "gpuinfouniqueid.h" #include "common/fileutils.h" #include "core/info/infoproviderregistry.h" #include #include #include namespace AMD { class GPUInfoUniqueIDDataSource : public IDataSource { public: std::string source() const override { return "unique_id"; } bool read(std::string &data, std::filesystem::path const &path) override { auto const filePath = path / source(); if (Utils::File::isFilePathValid(filePath)) { auto const lines = Utils::File::readFileLines(filePath); if (!lines.empty()) { data = lines.front(); return true; } } return false; } }; } // namespace AMD AMD::GPUInfoUniqueID::GPUInfoUniqueID( std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> AMD::GPUInfoUniqueID::provideInfo(Vendor vendor, int, IGPUInfo::Path const &path, IHWIDTranslator const &) const { std::vector> info; if (vendor == Vendor::AMD) { std::string data; if (dataSource_->read(data, path.sys)) { std::transform(data.cbegin(), data.cend(), data.begin(), ::toupper); info.emplace_back(IGPUInfo::Keys::uniqueID, std::move(data)); } } return info; } std::vector AMD::GPUInfoUniqueID::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } bool AMD::GPUInfoUniqueID::registered_ = InfoProviderRegistry::add(std::make_unique( std::make_unique())); corectrl-v1.4.2/src/core/info/amd/gpuinfouniqueid.h000066400000000000000000000016741467225065400223430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include namespace AMD { class GPUInfoUniqueID final : public IGPUInfo::IProvider { public: GPUInfoUniqueID( std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::unique_ptr> const dataSource_; static bool registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/info/amd/gpuinfovbios.cpp000066400000000000000000000034711467225065400221720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfovbios.h" #include "common/fileutils.h" #include "core/info/infoproviderregistry.h" #include #include #include #include namespace AMD { class GPUInfoVbiosDataSource : public IDataSource { public: std::string source() const override { return "vbios_version"; } bool read(std::string &data, std::filesystem::path const &path) override { auto const filePath = path / source(); auto const lines = Utils::File::readFileLines(filePath); if (!lines.empty()) { data = lines.front(); return true; } SPDLOG_WARN("Cannot retrieve bios version from {}", filePath.c_str()); return false; } }; } // namespace AMD AMD::GPUInfoVbios::GPUInfoVbios( std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> AMD::GPUInfoVbios::provideInfo(Vendor vendor, int, IGPUInfo::Path const &path, IHWIDTranslator const &) const { std::vector> info; if (vendor == Vendor::AMD) { std::string data; if (dataSource_->read(data, path.sys)) { std::transform(data.cbegin(), data.cend(), data.begin(), ::toupper); info.emplace_back(GPUInfoVbios::version, std::move(data)); } } return info; } std::vector AMD::GPUInfoVbios::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } bool AMD::GPUInfoVbios::registered_ = InfoProviderRegistry::add(std::make_unique( std::make_unique())); corectrl-v1.4.2/src/core/info/amd/gpuinfovbios.h000066400000000000000000000017551467225065400216420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include namespace AMD { class GPUInfoVbios final : public IGPUInfo::IProvider { public: static constexpr std::string_view version{"biosv"}; GPUInfoVbios( std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::unique_ptr> const dataSource_; static bool registered_; }; } // namespace AMD corectrl-v1.4.2/src/core/info/amd/gpuinfovram.cpp000066400000000000000000000112421467225065400220100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include "gpuinfovram.h" #include "../common/gpuinfoueventdatasource.h" #include "../common/swinfokerneldatasource.h" #include "common/stringutils.h" #include "core/components/amdutils.h" #include "core/devfsdatasource.h" #include "core/info/infoproviderregistry.h" #include #include #include #include class AMDGPUInfoVRamDataSource : public IDataSource { public: std::string source() const override { return ""; } bool read(units::data::megabyte_t &data, std::filesystem::path const &path) override { auto vramDataSource = DevFSDataSource( path, [](int fd) { units::data::megabyte_t size; Utils::AMD::readAMDGPUVRamSize(fd, &size); return size; }); if (vramDataSource.read(data)) return true; SPDLOG_WARN("Cannot retrieve device memory size from {}", path.c_str()); return false; } }; class RadeonGPUInfoVRamDataSource : public IDataSource { public: std::string source() const override { return ""; } bool read(units::data::megabyte_t &data, std::filesystem::path const &path) override { auto vramDataSource = DevFSDataSource( path, [](int fd) { units::data::megabyte_t size; Utils::AMD::readRadeonVRamSize(fd, &size); return size; }); if (vramDataSource.read(data)) return true; SPDLOG_WARN("Cannot retrieve device memory size from {}", path.c_str()); return false; } }; GPUInfoVRam::GPUInfoVRam( std::unique_ptr> &&kernelVersionDataSource, std::unique_ptr, std::filesystem::path const>> &&driverDataSource, std::unique_ptr> &&radeonDataSource, std::unique_ptr> &&amdgpuDataSource) noexcept : kernelVersionDataSource_(std::move(kernelVersionDataSource)) , driverDataSource_(std::move(driverDataSource)) , radeonDataSource_(std::move(radeonDataSource)) , amdgpuDataSource_(std::move(amdgpuDataSource)) { } std::vector> GPUInfoVRam::provideInfo(Vendor, int, IGPUInfo::Path const &path, IHWIDTranslator const &) const { std::vector> info; auto kernel = readKernelVersion(); auto driver = readDriver(path.sys); if ((driver == "radeon" && kernel >= std::make_tuple(2, 6, 31)) || (driver == "amdgpu" && kernel >= std::make_tuple(4, 10, 0))) { units::data::megabyte_t memory; bool success = false; if (driver == "radeon") success = radeonDataSource_->read(memory, path.dev); else if (driver == "amdgpu") success = amdgpuDataSource_->read(memory, path.dev); else SPDLOG_WARN("Cannot retrieve vram size: unsupported driver"); if (success) info.emplace_back(IGPUInfo::Keys::memory, std::format("{} {}", memory.template to(), memory.abbreviation())); } return info; } std::tuple GPUInfoVRam::readKernelVersion() const { std::string data; if (kernelVersionDataSource_->read(data)) { auto version = Utils::String::parseKernelProcVersion(data).value_or("0.0.0"); return Utils::String::parseVersion(version); } return std::make_tuple(0, 0, 0); } std::string GPUInfoVRam::readDriver(std::filesystem::path const &path) const { std::string driver; std::vector data; if (driverDataSource_->read(data, path)) { static constexpr std::string_view driverStr{"DRIVER"}; for (auto &line : data) { if (line.find(driverStr) == 0) { driver = line.substr(driverStr.length() + 1, std::string::npos); break; } } if (driver.empty()) SPDLOG_DEBUG("Cannot retrieve driver"); } return driver; } std::vector GPUInfoVRam::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } bool GPUInfoVRam::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique(), std::make_unique(), std::make_unique(), std::make_unique())); corectrl-v1.4.2/src/core/info/amd/gpuinfovram.h000066400000000000000000000032541467225065400214610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include #include class GPUInfoVRam final : public IGPUInfo::IProvider { public: GPUInfoVRam( std::unique_ptr> &&kernelVersionDataSource, std::unique_ptr, std::filesystem::path const>> &&driverDataSource, std::unique_ptr> &&radeonDataSource, std::unique_ptr> &&amdgpuDataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::tuple readKernelVersion() const; std::string readDriver(std::filesystem::path const &path) const; std::unique_ptr> const kernelVersionDataSource_; std::unique_ptr, std::filesystem::path const>> const driverDataSource_; std::unique_ptr> const radeonDataSource_; std::unique_ptr> const amdgpuDataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/000077500000000000000000000000001467225065400174765ustar00rootroot00000000000000corectrl-v1.4.2/src/core/info/common/cpuinfolscpu.cpp000066400000000000000000000055771467225065400227320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuinfolscpu.h" #include "../infoproviderregistry.h" #include "common/stringutils.h" #include #include #include #include class CPUInfoLsCpuDataSource : public IDataSource> { public: std::string source() const override { return "lscpu"; } bool read(std::vector &data) override { auto env = QProcessEnvironment::systemEnvironment(); env.insert("LC_ALL", "C"); QProcess cmd; cmd.setProcessChannelMode(QProcess::MergedChannels); cmd.setProcessEnvironment(env); cmd.start(source().c_str(), QStringList()); if (cmd.waitForFinished()) { auto rawData = cmd.readAllStandardOutput().toStdString(); data = Utils::String::split(rawData, '\n'); return true; } SPDLOG_WARN("lscpu command failed"); return false; } }; CPUInfoLsCpu::CPUInfoLsCpu( std::unique_ptr>> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> CPUInfoLsCpu::provideInfo(int, std::vector const &) { std::vector> info; std::vector data; if (dataSource_->read(data)) { addInfo("Architecture", Keys::arch, info, data); addInfo("CPU op-mode(s)", Keys::opMode, info, data); addInfo("Byte Order", Keys::byteOrder, info, data); addInfo("Virtualization", Keys::virt, info, data); addInfo("L1d cache", Keys::l1dCache, info, data); addInfo("L1i cache", Keys::l1iCache, info, data); addInfo("L2 cache", Keys::l2Cache, info, data); } return info; } std::vector CPUInfoLsCpu::provideCapabilities(int, std::vector const &) { return {}; } std::string CPUInfoLsCpu::extractLineData(std::string const &line) const { auto colonPos = line.find(':'); if (colonPos != std::string::npos) { auto dataPos = line.find_first_not_of("\t: ", colonPos); if (dataPos != std::string::npos) return line.substr(dataPos); } return {}; } void CPUInfoLsCpu::addInfo(std::string_view target, std::string_view key, std::vector> &info, std::vector const &data) const { auto keyIt = std::find_if(data.cbegin(), data.cend(), [=](std::string const &line) { return line.find(target) != std::string::npos; }); if (keyIt != data.cend()) info.emplace_back(key, extractLineData(*keyIt)); } bool CPUInfoLsCpu::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique())); corectrl-v1.4.2/src/core/info/common/cpuinfolscpu.h000066400000000000000000000030231467225065400223570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../icpuinfo.h" #include "core/idatasource.h" #include #include #include #include #include class CPUInfoLsCpu final : public ICPUInfo::IProvider { public: struct Keys { static constexpr std::string_view arch{"arch"}; static constexpr std::string_view opMode{"opmode"}; static constexpr std::string_view byteOrder{"byteorder"}; static constexpr std::string_view virt{"virt"}; static constexpr std::string_view l1dCache{"l1dcache"}; static constexpr std::string_view l1iCache{"l1icache"}; static constexpr std::string_view l2Cache{"l2cache"}; }; CPUInfoLsCpu(std::unique_ptr>> &&dataSource) noexcept; std::vector> provideInfo( int physicalId, std::vector const &executionUnits) override; std::vector provideCapabilities( int physicalId, std::vector const &executionUnits) override; private: std::string extractLineData(std::string const &line) const; void addInfo(std::string_view target, std::string_view key, std::vector> &info, std::vector const &data) const; std::unique_ptr>> const dataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/cpuinfoproccpuinfo.cpp000066400000000000000000000053351467225065400241230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuinfoproccpuinfo.h" #include "../infoproviderregistry.h" #include "common/fileutils.h" #include "core/components/cpuutils.h" #include class CPUInfoProcCpuInfoDataSource : public IDataSource> { public: std::string source() const override { return "/proc/cpuinfo"; } bool read(std::vector &data) override { auto lines = Utils::File::readFileLines(source()); if (!lines.empty()) { std::swap(data, lines); return true; } SPDLOG_WARN("Cannot retrieve device information from {}", source()); return false; } }; CPUInfoProcCpuInfo::CPUInfoProcCpuInfo( std::unique_ptr>> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> CPUInfoProcCpuInfo::provideInfo( int, std::vector const &executionUnits) { std::vector> info; std::vector data; if (!executionUnits.empty() && dataSource_->read(data)) { info.emplace_back(ICPUInfo::Keys::executionUnits, std::to_string(executionUnits.size())); auto cpuId = executionUnits.front().cpuId; addInfo("vendor_id", ICPUInfo::Keys::vendorId, cpuId, info, data); addInfo("cpu family", ICPUInfo::Keys::cpuFamily, cpuId, info, data); addInfo("model", ICPUInfo::Keys::model, cpuId, info, data); addInfo("model name", ICPUInfo::Keys::modelName, cpuId, info, data); addInfo("stepping", ICPUInfo::Keys::stepping, cpuId, info, data); addInfo("microcode", ICPUInfo::Keys::ucode, cpuId, info, data); addInfo("cache size", ICPUInfo::Keys::l3Cache, cpuId, info, data); addInfo("cpu cores", ICPUInfo::Keys::cores, cpuId, info, data); addInfo("flags", ICPUInfo::Keys::flags, cpuId, info, data); addInfo("bugs", ICPUInfo::Keys::bugs, cpuId, info, data); addInfo("bogomips", ICPUInfo::Keys::bogomips, cpuId, info, data); } return info; } std::vector CPUInfoProcCpuInfo::provideCapabilities( int, std::vector const &) { return {}; } void CPUInfoProcCpuInfo::addInfo( std::string_view target, std::string_view key, int cpuId, std::vector> &info, std::vector const &lines) const { auto data = Utils::CPU::parseProcCpuInfo(lines, cpuId, target); if (data.has_value()) info.emplace_back(key, *data); } bool CPUInfoProcCpuInfo::registered_ = InfoProviderRegistry::add(std::make_unique( std::make_unique())); corectrl-v1.4.2/src/core/info/common/cpuinfoproccpuinfo.h000066400000000000000000000021121467225065400235560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../icpuinfo.h" #include "core/idatasource.h" #include #include #include #include #include class CPUInfoProcCpuInfo final : public ICPUInfo::IProvider { public: CPUInfoProcCpuInfo(std::unique_ptr>> &&dataSource) noexcept; std::vector> provideInfo( int physicalId, std::vector const &executionUnits) override; std::vector provideCapabilities( int physicalId, std::vector const &executionUnits) override; private: void addInfo(std::string_view target, std::string_view key, int cpuId, std::vector> &info, std::vector const &lines) const; std::unique_ptr>> const dataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/gpuinfoopengl.cpp000066400000000000000000000073561467225065400230710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfoopengl.h" #include "../infoproviderregistry.h" #include #include #include #include #include class GPUInfoOpenGLDataSource : public IDataSource { public: std::string source() const override { return "glxinfo"; } bool read(std::string &data, int const &gpuIndex) override { static constexpr std::string_view libGLErrorStr( "libGL error: failed to load driver"); auto env = QProcessEnvironment::systemEnvironment(); env.insert("LC_ALL", "C"); env.insert("DRI_PRIME", QString::number(gpuIndex)); QProcess cmd; cmd.setProcessChannelMode(QProcess::MergedChannels); cmd.setProcessEnvironment(env); cmd.start(source().c_str(), QStringList("-B")); if (cmd.waitForFinished()) { auto output = cmd.readAllStandardOutput().toStdString(); auto libGLErrorPos = output.find(libGLErrorStr); if (libGLErrorPos == std::string::npos) { data = output; return true; } // extract libGL error auto endLinePos = output.find("\n", libGLErrorPos); auto libGLError = output.substr( libGLErrorPos + libGLErrorStr.length(), endLinePos - libGLErrorPos - libGLErrorStr.length()); SPDLOG_WARN("glxinfo command failed for GPU{} with error '{}{}'", gpuIndex, libGLErrorStr.data(), libGLError); } SPDLOG_WARN("glxinfo command failed"); return false; } }; GPUInfoOpenGL::GPUInfoOpenGL( std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> GPUInfoOpenGL::provideInfo(Vendor, int gpuIndex, IGPUInfo::Path const &, IHWIDTranslator const &) const { std::vector> info; static constexpr std::string_view queryRendererStr("GLX_MESA_query_renderer"); static constexpr std::string_view coreVerStr("Max core profile version: "); static constexpr std::string_view compatVerStr( "Max compat profile version: "); std::string data; if (dataSource_->read(data, gpuIndex)) { auto queryRendererPos = data.find(queryRendererStr); if (queryRendererPos != std::string::npos) { auto coreVer = findItem(data, coreVerStr, queryRendererPos); if (!coreVer.empty()) info.emplace_back(GPUInfoOpenGL::Keys::coreVersion, std::move(coreVer)); else SPDLOG_DEBUG("Cannot find '{}' in glxinfo output", coreVerStr.data()); auto compatVer = findItem(data, compatVerStr, queryRendererPos); if (!compatVer.empty()) info.emplace_back(GPUInfoOpenGL::Keys::compatVersion, std::move(compatVer)); else SPDLOG_DEBUG("Cannot find '{}' in glxinfo output", compatVerStr.data()); } else SPDLOG_DEBUG("Cannot find '{}' in glxinfo output", queryRendererStr.data()); } return info; } std::vector GPUInfoOpenGL::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } std::string GPUInfoOpenGL::findItem(std::string const &src, std::string_view itemStr, size_t pos) const { auto itemPos = src.find(itemStr, pos); if (itemPos != std::string::npos) { auto endLinePos = src.find("\n", itemPos); auto item = src.substr(itemPos + itemStr.length(), endLinePos - itemPos - itemStr.length()); return item; } return std::string{}; } bool GPUInfoOpenGL::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique())); corectrl-v1.4.2/src/core/info/common/gpuinfoopengl.h000066400000000000000000000021701467225065400225230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include #include class GPUInfoOpenGL final : public IGPUInfo::IProvider { public: struct Keys { static constexpr std::string_view coreVersion{"glcorev"}; static constexpr std::string_view compatVersion{"glcompv"}; }; GPUInfoOpenGL( std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::string findItem(std::string const &src, std::string_view itemStr, size_t pos) const; std::unique_ptr> const dataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/gpuinforevision.cpp000066400000000000000000000034651467225065400234400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinforevision.h" #include "../infoproviderregistry.h" #include "common/fileutils.h" #include "common/stringutils.h" #include #include #include #include class GPUInfoRevisionDataSource : public IDataSource { public: std::string source() const override { return "revision"; } bool read(std::string &data, std::filesystem::path const &path) override { auto const filePath = path / source(); auto const lines = Utils::File::readFileLines(filePath); if (!lines.empty()) { data = lines.front(); return true; } SPDLOG_WARN("Cannot retrieve device revision from {}", filePath.c_str()); return false; } }; GPUInfoRevision::GPUInfoRevision( std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> GPUInfoRevision::provideInfo(Vendor, int, IGPUInfo::Path const &path, IHWIDTranslator const &) const { std::vector> info; std::string data; if (dataSource_->read(data, path.sys)) { std::string rev(Utils::String::cleanPrefix(data, "0x")); std::transform(rev.cbegin(), rev.cend(), rev.begin(), ::toupper); info.emplace_back(IGPUInfo::Keys::revision, std::move(rev)); } return info; } std::vector GPUInfoRevision::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } bool GPUInfoRevision::registered_ = InfoProviderRegistry::add(std::make_unique( std::make_unique())); corectrl-v1.4.2/src/core/info/common/gpuinforevision.h000066400000000000000000000016001467225065400230720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include class GPUInfoRevision final : public IGPUInfo::IProvider { public: GPUInfoRevision( std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::unique_ptr> const dataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/gpuinfouevent.cpp000066400000000000000000000105501467225065400231010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfouevent.h" #include "../ihwidtranslator.h" #include "../infoproviderregistry.h" #include "gpuinfoueventdatasource.h" #include #include #include #include #include GPUInfoUevent::GPUInfoUevent( std::unique_ptr, std::filesystem::path const>> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> GPUInfoUevent::provideInfo(Vendor, int, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const { std::vector> info; static constexpr std::string_view driverStr{"DRIVER"}; static constexpr std::string_view pciIdStr{"PCI_ID"}; static constexpr std::string_view pciSubsysIdStr{"PCI_SUBSYS_ID"}; static constexpr std::string_view pciSlotStr{"PCI_SLOT_NAME"}; std::vector data; if (dataSource_->read(data, path.sys)) { std::string vendorId; std::string deviceId; std::string subvendorId; std::string subdeviceId; std::string pciSlot; std::string driver; for (auto const &line : data) { if (line.find(driverStr) == 0) { driver = line.substr(driverStr.length() + 1, std::string::npos); } else if (line.find(pciIdStr) == 0) { auto colonPos = line.find(':', pciIdStr.length() + 1); vendorId = line.substr(pciIdStr.length() + 1, colonPos - pciIdStr.length() - 1); deviceId = line.substr(colonPos + 1, std::string::npos); } else if (line.find(pciSubsysIdStr) == 0) { auto colonPos = line.find(':', pciSubsysIdStr.length() + 1); subvendorId = line.substr(pciSubsysIdStr.length() + 1, colonPos - pciSubsysIdStr.length() - 1); subdeviceId = line.substr(colonPos + 1, std::string::npos); } else if (line.find(pciSlotStr) == 0) { pciSlot = line.substr(pciSlotStr.length() + 1, std::string::npos); } } if (vendorId.empty()) SPDLOG_DEBUG("Cannot retrieve vendor ID"); if (deviceId.empty()) SPDLOG_DEBUG("Cannot retrieve device ID"); if (subvendorId.empty()) SPDLOG_DEBUG("Cannot retrieve subvendor ID"); if (subdeviceId.empty()) SPDLOG_DEBUG("Cannot retrieve subdevice ID"); if (pciSlot.empty()) SPDLOG_DEBUG("Cannot retrieve pci slot"); if (driver.empty()) SPDLOG_DEBUG("Cannot retrieve driver"); // ensure that all ids are in uppercase std::transform(vendorId.cbegin(), vendorId.cend(), vendorId.begin(), ::toupper); std::transform(deviceId.cbegin(), deviceId.cend(), deviceId.begin(), ::toupper); std::transform(subvendorId.cbegin(), subvendorId.cend(), subvendorId.begin(), ::toupper); std::transform(subdeviceId.cbegin(), subdeviceId.cend(), subdeviceId.begin(), ::toupper); // populate info auto vendorName = hwIDTranslator.vendor(vendorId); if (!vendorName.empty()) info.emplace_back(IGPUInfo::Keys::vendorName, std::move(vendorName)); auto deviceName = hwIDTranslator.device(vendorId, deviceId); if (!deviceName.empty()) info.emplace_back(IGPUInfo::Keys::deviceName, std::move(deviceName)); auto subdeviceName = hwIDTranslator.subdevice(vendorId, deviceId, subvendorId, subdeviceId); if (!subdeviceName.empty()) info.emplace_back(IGPUInfo::Keys::subdeviceName, std::move(subdeviceName)); info.emplace_back(IGPUInfo::Keys::driver, std::move(driver)); info.emplace_back(IGPUInfo::Keys::pciSlot, std::move(pciSlot)); info.emplace_back(IGPUInfo::Keys::vendorID, std::move(vendorId)); info.emplace_back(IGPUInfo::Keys::deviceID, std::move(deviceId)); info.emplace_back(IGPUInfo::Keys::subvendorID, std::move(subvendorId)); info.emplace_back(IGPUInfo::Keys::subdeviceID, std::move(subdeviceId)); } return info; } std::vector GPUInfoUevent::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } bool GPUInfoUevent::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique())); corectrl-v1.4.2/src/core/info/common/gpuinfouevent.h000066400000000000000000000017241467225065400225510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include class GPUInfoUevent final : public IGPUInfo::IProvider { public: GPUInfoUevent(std::unique_ptr< IDataSource, std::filesystem::path const>> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::unique_ptr, std::filesystem::path const>> const dataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/gpuinfoueventdatasource.h000066400000000000000000000015311467225065400246200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "common/fileutils.h" #include "core/idatasource.h" #include #include #include #include #include class GPUInfoUeventDataSource : public IDataSource, std::filesystem::path const> { public: std::string source() const override { return "uevent"; } bool read(std::vector &data, std::filesystem::path const &path) override { auto const filePath = path / source(); auto lines = Utils::File::readFileLines(filePath); if (!lines.empty()) { std::swap(data, lines); return true; } SPDLOG_WARN("Cannot retrieve device information from {}", filePath.c_str()); return false; } }; corectrl-v1.4.2/src/core/info/common/gpuinfovulkan.cpp000066400000000000000000000062041467225065400230740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfovulkan.h" #include "../infoproviderregistry.h" #include #include #include #include #include class GPUInfoVulkanDataSource : public IDataSource { public: std::string source() const override { return "vulkaninfo"; } bool read(std::string &data) override { auto env = QProcessEnvironment::systemEnvironment(); env.insert("LC_ALL", "C"); QProcess cmd; cmd.setProcessChannelMode(QProcess::MergedChannels); cmd.setProcessEnvironment(env); cmd.start(source().c_str(), QStringList()); if (cmd.waitForFinished()) { data = cmd.readAllStandardOutput().toStdString(); return true; } SPDLOG_WARN("vulkaninfo command failed"); return false; } }; GPUInfoVulkan::GPUInfoVulkan( std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> GPUInfoVulkan::provideInfo(Vendor, int gpuIndex, IGPUInfo::Path const &, IHWIDTranslator const &) const { std::vector> info; static constexpr std::string_view devicePropStr("VkPhysicalDeviceProperties"); std::string data; if (dataSource_->read(data)) { int currentGPUIndex = 0; auto devicePropStrPos = data.find(devicePropStr); while (devicePropStrPos != std::string::npos) { if (currentGPUIndex == gpuIndex) { auto apiVersion = parseApiVersion(data, devicePropStrPos); if (!apiVersion.empty()) info.emplace_back(GPUInfoVulkan::Keys::apiVersion, std::move(apiVersion)); break; } devicePropStrPos = data.find(devicePropStr, devicePropStrPos + devicePropStr.length()); currentGPUIndex++; } } return info; } std::vector GPUInfoVulkan::provideCapabilities(Vendor, int, IGPUInfo::Path const &) const { return {}; } std::string GPUInfoVulkan::parseApiVersion(std::string const &src, size_t pos) const { static constexpr std::string_view apiVerStr("apiVersion"); auto apiVerPos = src.find(apiVerStr, pos); if (apiVerPos != std::string::npos) { auto startPos = src.find_first_not_of("= ", apiVerPos + apiVerStr.length()); // version inside parentheses is preferred auto openParenPos = src.find("(", startPos); if (openParenPos != std::string::npos) { auto endPos = src.find(")", openParenPos); auto version = src.substr(openParenPos + 1, endPos - openParenPos - 1); return version; } // fallback version auto endPos = src.find("\n", startPos); auto version = src.substr(startPos, endPos - startPos); return version; } else SPDLOG_DEBUG("Cannot find '{}' in vulkaninfo output", apiVerStr.data()); return std::string{}; } bool GPUInfoVulkan::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique())); corectrl-v1.4.2/src/core/info/common/gpuinfovulkan.h000066400000000000000000000017351467225065400225450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../igpuinfo.h" #include "core/idatasource.h" #include #include #include #include class GPUInfoVulkan final : public IGPUInfo::IProvider { public: struct Keys { static constexpr std::string_view apiVersion{"vkapiv"}; }; GPUInfoVulkan(std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const override; std::vector provideCapabilities(Vendor vendor, int, IGPUInfo::Path const &path) const override; private: std::string parseApiVersion(std::string const &src, size_t pos) const; std::unique_ptr> const dataSource_; static bool registered_; }; corectrl-v1.4.2/src/core/info/common/swinfokernel.cpp000066400000000000000000000016071467225065400227140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "swinfokernel.h" #include "../infoproviderregistry.h" #include "common/stringutils.h" #include "swinfokerneldatasource.h" #include #include SWInfoKernel::SWInfoKernel( std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> SWInfoKernel::provideInfo() const { std::vector> info; std::string data; dataSource_->read(data); data = Utils::String::parseKernelProcVersion(data).value_or("0.0.0"); info.emplace_back(ISWInfo::Keys::kernelVersion, data); return info; } bool const SWInfoKernel::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique())); corectrl-v1.4.2/src/core/info/common/swinfokernel.h000066400000000000000000000010411467225065400223510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../iswinfo.h" #include "core/idatasource.h" #include #include class SWInfoKernel final : public ISWInfo::IProvider { public: SWInfoKernel(std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo() const override; private: std::unique_ptr> const dataSource_; static bool const registered_; }; corectrl-v1.4.2/src/core/info/common/swinfokerneldatasource.h000066400000000000000000000011711467225065400244300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #pragma once #include "common/fileutils.h" #include "core/idatasource.h" #include #include class SWInfoKernelDataSource : public IDataSource { public: std::string source() const override { return "/proc/version"; } bool read(std::string &data) override { auto const lines = Utils::File::readFileLines(source()); if (!lines.empty()) { data = lines.front(); return true; } SPDLOG_WARN("Cannot retrieve kernel version"); return false; } }; corectrl-v1.4.2/src/core/info/common/swinfomesa.cpp000066400000000000000000000042641467225065400223630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "swinfomesa.h" #include "../infoproviderregistry.h" #include #include #include #include #include class SWInfoMesaDataSource : public IDataSource { public: std::string source() const override { return "glxinfo"; } bool read(std::string &data) override { auto env = QProcessEnvironment::systemEnvironment(); env.insert("LC_ALL", "C"); QProcess cmd; cmd.setProcessChannelMode(QProcess::MergedChannels); cmd.setProcessEnvironment(env); cmd.start(source().c_str(), QStringList("-B")); if (cmd.waitForFinished()) { data = cmd.readAllStandardOutput().toStdString(); return true; } SPDLOG_WARN("glxinfo command failed"); return false; } }; SWInfoMesa::SWInfoMesa(std::unique_ptr> &&dataSource) noexcept : dataSource_(std::move(dataSource)) { } std::vector> SWInfoMesa::provideInfo() const { std::vector> info; static constexpr std::string_view queryRendererStr("GLX_MESA_query_renderer"); static constexpr std::string_view versionStr("Version: "); std::string data; if (dataSource_->read(data)) { auto queryRendererPos = data.find(queryRendererStr); if (queryRendererPos != std::string::npos) { auto versionPos = data.find(versionStr, queryRendererPos); if (versionPos != std::string::npos) { auto endLinePos = data.find("\n", versionPos); auto version = data.substr(versionPos + versionStr.length(), endLinePos - versionPos - versionStr.length()); info.emplace_back(ISWInfo::Keys::mesaVersion, std::move(version)); } else SPDLOG_DEBUG("Cannot find '{}' in glxinfo output", versionStr.data()); } else SPDLOG_DEBUG("Cannot find '{}' in glxinfo output", queryRendererStr.data()); } return info; } bool const SWInfoMesa::registered_ = InfoProviderRegistry::add( std::make_unique(std::make_unique())); corectrl-v1.4.2/src/core/info/common/swinfomesa.h000066400000000000000000000010351467225065400220210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "../iswinfo.h" #include "core/idatasource.h" #include #include class SWInfoMesa final : public ISWInfo::IProvider { public: SWInfoMesa(std::unique_ptr> &&dataSource) noexcept; std::vector> provideInfo() const override; private: std::unique_ptr> const dataSource_; static bool const registered_; }; corectrl-v1.4.2/src/core/info/cpuinfo.cpp000066400000000000000000000033621467225065400203610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "cpuinfo.h" #include #include #include CPUInfo::CPUInfo(int physicalId, std::vector &&executionUnits) noexcept : physicalId_(physicalId) , executionUnits_(std::move(executionUnits)) { } int CPUInfo::physicalId() const { return physicalId_; } std::vector const &CPUInfo::executionUnits() const { return executionUnits_; } void CPUInfo::addExecutionUnit(ICPUInfo::ExecutionUnit &&unit) { executionUnits_.emplace_back(std::move(unit)); } std::vector CPUInfo::keys() const { std::vector keys; keys.reserve(info_.size()); auto const keySelector = [](auto const &pair) { return pair.first; }; std::transform(info_.cbegin(), info_.cend(), std::back_inserter(keys), keySelector); return keys; } std::string CPUInfo::info(std::string_view key) const { auto const dataIt = info_.find(std::string(key)); if (dataIt != info_.cend()) return dataIt->second; return {}; } bool CPUInfo::hasCapability(std::string_view name) const { return capabilities_.count(std::string(name)) > 0; } void CPUInfo::initialize( std::vector> const &providers) { for (auto &provider : providers) { auto infos = provider->provideInfo(physicalId_, executionUnits_); for (auto &info : infos) info_.emplace(std::move(info)); auto capabilities = provider->provideCapabilities(physicalId_, executionUnits_); for (auto &capability : capabilities) capabilities_.emplace(std::move(capability)); } } corectrl-v1.4.2/src/core/info/cpuinfo.h000066400000000000000000000017711467225065400200300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icpuinfo.h" #include #include #include #include class CPUInfo final : public ICPUInfo { public: CPUInfo(int physicalId, std::vector &&executionUnits) noexcept; int physicalId() const override; std::vector const &executionUnits() const override; std::vector keys() const override; std::string info(std::string_view key) const override; bool hasCapability(std::string_view name) const override; void initialize( std::vector> const &providers) override; void addExecutionUnit(ICPUInfo::ExecutionUnit &&unit); private: int const physicalId_; std::vector executionUnits_; std::unordered_map info_; std::unordered_set capabilities_; }; corectrl-v1.4.2/src/core/info/gpuinfo.cpp000066400000000000000000000031261467225065400203630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "gpuinfo.h" #include #include #include GPUInfo::GPUInfo(Vendor vendor, int index, IGPUInfo::Path &&path) noexcept : vendor_(vendor) , index_(index) , path_(std::move(path)) { } Vendor GPUInfo::vendor() const { return vendor_; } int GPUInfo::index() const { return index_; } IGPUInfo::Path const &GPUInfo::path() const { return path_; } std::vector GPUInfo::keys() const { std::vector keys; keys.reserve(info_.size()); auto const keySelector = [](auto const &pair) { return pair.first; }; std::transform(info_.cbegin(), info_.cend(), std::back_inserter(keys), keySelector); return keys; } std::string GPUInfo::info(std::string_view key) const { auto const dataIt = info_.find(std::string(key)); if (dataIt != info_.cend()) return dataIt->second; return std::string{}; } bool GPUInfo::hasCapability(std::string_view name) const { return capabilities_.count(std::string(name)) > 0; } void GPUInfo::initialize( std::vector> const &providers, IHWIDTranslator const &hwidTranslator) { for (auto const &provider : providers) { auto infos = provider->provideInfo(vendor_, index_, path_, hwidTranslator); for (auto &info : infos) info_.emplace(std::move(info)); auto capabilities = provider->provideCapabilities(vendor_, index_, path_); for (auto &capability : capabilities) capabilities_.emplace(std::move(capability)); } } corectrl-v1.4.2/src/core/info/gpuinfo.h000066400000000000000000000017101467225065400200250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "igpuinfo.h" #include "vendor.h" #include #include #include class GPUInfo final : public IGPUInfo { public: GPUInfo(Vendor vendor, int index, IGPUInfo::Path &&path) noexcept; Vendor vendor() const override; int index() const override; IGPUInfo::Path const &path() const override; std::vector keys() const override; std::string info(std::string_view key) const override; bool hasCapability(std::string_view name) const override; void initialize( std::vector> const &infoProviders, IHWIDTranslator const &hwidTranslator) override; private: Vendor const vendor_; int const index_; IGPUInfo::Path const path_; std::unordered_map info_; std::unordered_set capabilities_; }; corectrl-v1.4.2/src/core/info/hwiddatasource.cpp000066400000000000000000000010201467225065400217110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "hwiddatasource.h" #include "common/fileutils.h" #include HWIDDataSource::HWIDDataSource(std::string const &path) noexcept : path_(path) { } std::string HWIDDataSource::source() const { return path_; } bool HWIDDataSource::read(std::vector &data) { auto fileData = Utils::File::readFile(path_); if (!fileData.empty()) { std::swap(data, fileData); return true; } return false; } corectrl-v1.4.2/src/core/info/hwiddatasource.h000066400000000000000000000006641467225065400213730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include #include class HWIDDataSource : public IDataSource> { public: HWIDDataSource(std::string const &path) noexcept; std::string source() const override; bool read(std::vector &data) override; private: std::string const path_; }; corectrl-v1.4.2/src/core/info/hwidtranslator.cpp000066400000000000000000000132661467225065400217670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "hwidtranslator.h" #include #include #include #include #include #include HWIDTranslator::HWIDTranslator( std::vector vendors, std::unique_ptr>> &&dataSource) noexcept { std::vector data; try { if (dataSource->read(data)) parseHWIDSFileData(data, std::move(vendors)); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } std::string HWIDTranslator::vendor(std::string const &vendorID) const { if (!vendors_.empty()) { std::string key(vendorID); std::transform(key.cbegin(), key.cend(), key.begin(), ::tolower); auto const vendorIt = vendors_.find(key); if (vendorIt != vendors_.cend()) return vendorIt->second; } return std::string{}; } std::string HWIDTranslator::device(std::string const &vendorID, std::string const &deviceID) const { if (!devices_.empty()) { std::string key; key.reserve(vendorID.length() + deviceID.length()); key.append(vendorID).append(deviceID); std::transform(key.cbegin(), key.cend(), key.begin(), ::tolower); auto const deviceIt = devices_.find(key); if (deviceIt != devices_.cend()) return deviceIt->second; } return std::string{}; } std::string HWIDTranslator::subdevice(std::string const &vendorID, std::string const &deviceID, std::string const &subvendorID, std::string const &subdeviceID) const { if (!subdevices_.empty()) { std::string key; key.reserve(vendorID.length() + deviceID.length() + subvendorID.length() + subdeviceID.length()); key.append(vendorID).append(deviceID).append(subvendorID).append(subdeviceID); std::transform(key.cbegin(), key.cend(), key.begin(), ::tolower); auto const subdeviceIt = subdevices_.find(key); if (subdeviceIt != subdevices_.cend()) return subdeviceIt->second; } return std::string{}; } std::string HWIDTranslator::extractName(std::string const &line, size_t start) const { auto nameStartPos = line.find_first_not_of(' ', start); if (nameStartPos != std::string::npos) { auto bracketPos = line.find(" [", nameStartPos); auto parenPos = line.find(" (", nameStartPos); auto nameEndPos = std::min({bracketPos, parenPos, std::string::npos}); return line.substr(nameStartPos, nameEndPos - nameStartPos); } return std::string{}; } void HWIDTranslator::parseHWIDSFileData(std::vector &data, std::vector &&vendors) { std::istringstream dataStream; dataStream.rdbuf()->pubsetbuf(data.data(), static_cast(data.size())); std::string line; line.reserve(200); std::string vendorID; vendorID.reserve(4); std::string deviceID; deviceID.reserve(4); std::string subvendorID; subvendorID.reserve(4); std::string subdeviceID; subdeviceID.reserve(4); std::string devicesKey; devicesKey.reserve(8); std::string subdevicesKey; subdevicesKey.reserve(16); std::vector skipLineChars{'#', '\0', 'C'}; bool skipVendor = true; size_t parsedVendorCount = 0; while (parsedVendorCount < vendors.size() && std::getline(dataStream, line)) { auto const firstChar = line[0]; // if the line starts with one of skipLineChars, ignore the line if (std::find(skipLineChars.cbegin(), skipLineChars.cend(), firstChar) != skipLineChars.cend()) { if (firstChar == 'C') skipVendor = true; } // vendor else if (firstChar != '\t') { if (!skipVendor) // vendor parsed! ++parsedVendorCount; auto spacePos = line.find(' '); vendorID = line.substr(0, spacePos); int vendorIDNum = -1; try { vendorIDNum = std::stoi(vendorID, nullptr, 16); // only parse vendors from vendorIDs if (std::find(vendors.cbegin(), vendors.cend(), static_cast(vendorIDNum)) == vendors.cend()) { skipVendor = true; } else { vendors_.insert({vendorID, extractName(line, spacePos)}); skipVendor = false; } } catch (std::exception const &e) { SPDLOG_DEBUG("Cannot convert vendor id {} from hwdata file.\nError: {}", vendorID, e.what()); skipVendor = true; } } // device or subvendor subdevice else { if (!skipVendor) { auto secondChar = line[1]; // device if (secondChar != '\t') { auto spacePos = line.find(' ', 1); deviceID = line.substr(1, spacePos - 1); devicesKey.clear(); devicesKey.append(vendorID).append(deviceID); devices_.insert({devicesKey, extractName(line, spacePos)}); } // subvendor subdevice else if (line.length() > 2) { auto subvendorSpacePos = line.find(' ', 2); subvendorID = line.substr(2, subvendorSpacePos - 2); auto subdeviceStartPos = line.find_first_not_of(' ', subvendorSpacePos); auto subdeviceEndPos = line.find(' ', subdeviceStartPos); subdeviceID = line.substr(subdeviceStartPos, subdeviceEndPos - subdeviceStartPos); subdevicesKey.clear(); subdevicesKey.append(vendorID) .append(deviceID) .append(subvendorID) .append(subdeviceID); subdevices_.insert({subdevicesKey, extractName(line, subdeviceEndPos)}); } } } } } corectrl-v1.4.2/src/core/info/hwidtranslator.h000066400000000000000000000026411467225065400214270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include "ihwidtranslator.h" #include "vendor.h" #include #include #include #include class HWIDTranslator final : public IHWIDTranslator { public: HWIDTranslator( std::vector vendors, std::unique_ptr>> &&dataSource) noexcept; // clang-format off std::string vendor(std::string const& vendorID) const override; std::string device(std::string const& vendorID, std::string const& deviceID) const override; std::string subdevice(std::string const& vendorID, std::string const& deviceID, std::string const& subvendorID, std::string const& subdeviceID) const override; // clang-format on private: /// Extracts a name from a line, skipping all information between /// the first ocurrence of " (" or " [" and the end of the line. /// @returns name std::string extractName(std::string const &line, size_t start) const; void parseHWIDSFileData(std::vector &data, std::vector &&vendors); private: std::unordered_map vendors_; std::unordered_map devices_; std::unordered_map subdevices_; }; corectrl-v1.4.2/src/core/info/icpuinfo.h000066400000000000000000000055311467225065400201770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include /// Interface to retrieve info of a physical cpu package. class ICPUInfo { public: struct Keys { static constexpr std::string_view vendorId{"vendorid"}; static constexpr std::string_view cpuFamily{"cpufamily"}; static constexpr std::string_view model{"model"}; static constexpr std::string_view modelName{"modname"}; static constexpr std::string_view stepping{"stepping"}; static constexpr std::string_view ucode{"ucodev"}; static constexpr std::string_view l3Cache{"l3cache"}; static constexpr std::string_view executionUnits{"exeunits"}; static constexpr std::string_view cores{"cores"}; static constexpr std::string_view flags{"flags"}; static constexpr std::string_view bugs{"bugs"}; static constexpr std::string_view bogomips{"bogomips"}; }; /// An execution unit is exposed by the system as a single cpu. struct ExecutionUnit { ExecutionUnit(int cpuId, int coreId, std::filesystem::path sysPath) : cpuId(cpuId) , coreId(coreId) , sysPath(std::move(sysPath)) { } /// cpu id exposed by the system int const cpuId; /// core id on the physical cpu package in which the cpu resides int const coreId; /// sysfs path std::filesystem::path const sysPath; }; class IProvider { public: virtual std::vector> provideInfo(int physicalId, std::vector const &executionUnits) = 0; virtual std::vector provideCapabilities( int physicalId, std::vector const &executionUnits) = 0; virtual ~IProvider() = default; }; class IProviderRegistry { public: virtual std::vector> const & cpuInfoProviders() const = 0; virtual ~IProviderRegistry() = default; }; /// @return physical id virtual int physicalId() const = 0; /// @return available execution units virtual std::vector const &executionUnits() const = 0; /// @returns collection of keys for the stored gpu information virtual std::vector keys() const = 0; /// @returns string with gpu info or empty string when no info /// is mapped to the key virtual std::string info(std::string_view key) const = 0; /// @returns true when a capability is present virtual bool hasCapability(std::string_view name) const = 0; /// Initialize cpu info /// @param infoProviders information providers virtual void initialize( std::vector> const &infoProviders) = 0; virtual ~ICPUInfo() = default; }; corectrl-v1.4.2/src/core/info/igpuinfo.h000066400000000000000000000054001467225065400201760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "vendor.h" #include #include #include #include #include #include class IHWIDTranslator; class IGPUInfo { public: struct Keys { static constexpr std::string_view vendorID{"vendorid"}; static constexpr std::string_view deviceID{"deviceid"}; static constexpr std::string_view subvendorID{"svendorid"}; static constexpr std::string_view subdeviceID{"sdeviceid"}; static constexpr std::string_view vendorName{"vendor"}; static constexpr std::string_view deviceName{"device"}; static constexpr std::string_view subdeviceName{"sdevice"}; static constexpr std::string_view pciSlot{"pcislot"}; static constexpr std::string_view driver{"driver"}; static constexpr std::string_view revision{"revision"}; static constexpr std::string_view memory{"memory"}; static constexpr std::string_view uniqueID{"uniqueid"}; }; struct Path { Path(std::filesystem::path sys, std::filesystem::path dev) noexcept : sys(std::move(sys)) , dev(std::move(dev)) { } std::filesystem::path const sys; std::filesystem::path const dev; }; class IProvider { public: virtual std::vector> provideInfo(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path, IHWIDTranslator const &hwIDTranslator) const = 0; virtual std::vector provideCapabilities(Vendor vendor, int gpuIndex, IGPUInfo::Path const &path) const = 0; virtual ~IProvider() = default; }; class IProviderRegistry { public: virtual std::vector> const & gpuInfoProviders() const = 0; virtual ~IProviderRegistry() = default; }; /// @returns gpu vendor id virtual Vendor vendor() const = 0; /// @returns gpu index virtual int index() const = 0; /// @returns gpu Path virtual IGPUInfo::Path const &path() const = 0; /// @returns collection of keys for the stored gpu information virtual std::vector keys() const = 0; /// @returns string with gpu info or empty string when no info /// is mapped to the key virtual std::string info(std::string_view key) const = 0; /// @returns true when the capability is present virtual bool hasCapability(std::string_view name) const = 0; /// Initialize gpu info /// @param infoProviders information providers /// @param hwidTranslator hwid code translator virtual void initialize( std::vector> const &infoProviders, IHWIDTranslator const &hwidTranslator) = 0; virtual ~IGPUInfo() = default; }; corectrl-v1.4.2/src/core/info/ihwidtranslator.h000066400000000000000000000015101467225065400215720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class IHWIDTranslator { public: /// returns vendor name or empty string if not found virtual std::string vendor(std::string const &vendorID) const = 0; /// returns device name or empty string if not found virtual std::string device(std::string const &vendorID, std::string const &deviceID) const = 0; /// returns subdevice name or empty string if not found virtual std::string subdevice(std::string const &vendorID, std::string const &deviceID, std::string const &subvendorID, std::string const &subdeviceID) const = 0; virtual ~IHWIDTranslator() = default; }; corectrl-v1.4.2/src/core/info/infoproviderregistry.cpp000066400000000000000000000031071467225065400232120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "infoproviderregistry.h" #include std::vector> const & InfoProviderRegistry::cpuInfoProviders() const { return cpuInfoProviders_(); } std::vector> const & InfoProviderRegistry::gpuInfoProviders() const { return gpuInfoProviders_(); } bool InfoProviderRegistry::add(std::unique_ptr &&provider) { cpuInfoProviders_().emplace_back(std::move(provider)); return true; } bool InfoProviderRegistry::add(std::unique_ptr &&provider) { gpuInfoProviders_().emplace_back(std::move(provider)); return true; } std::vector> const & InfoProviderRegistry::swInfoProviders() const { return swInfoProviders_(); } bool InfoProviderRegistry::add(std::unique_ptr &&provider) { swInfoProviders_().emplace_back(std::move(provider)); return true; } std::vector> & InfoProviderRegistry::cpuInfoProviders_() { static std::vector> providers; return providers; } std::vector> & InfoProviderRegistry::gpuInfoProviders_() { static std::vector> providers; return providers; } std::vector> & InfoProviderRegistry::swInfoProviders_() { static std::vector> providers; return providers; } corectrl-v1.4.2/src/core/info/infoproviderregistry.h000066400000000000000000000021411467225065400226540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "icpuinfo.h" #include "igpuinfo.h" #include "iswinfo.h" #include #include class InfoProviderRegistry final : public ICPUInfo::IProviderRegistry , public IGPUInfo::IProviderRegistry , public ISWInfo::IProviderRegistry { public: std::vector> const & cpuInfoProviders() const override; std::vector> const & gpuInfoProviders() const override; std::vector> const & swInfoProviders() const override; static bool add(std::unique_ptr &&provider); static bool add(std::unique_ptr &&provider); static bool add(std::unique_ptr &&provider); private: static std::vector> &cpuInfoProviders_(); static std::vector> &gpuInfoProviders_(); static std::vector> &swInfoProviders_(); }; corectrl-v1.4.2/src/core/info/iswinfo.h000066400000000000000000000025241467225065400200400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include class ISWInfo { public: struct Keys { static constexpr std::string_view kernelVersion{"kernelv"}; static constexpr std::string_view mesaVersion{"mesav"}; }; /// ISWInfo provider classes must implement this interface class IProvider { public: virtual std::vector> provideInfo() const = 0; virtual ~IProvider() = default; }; /// ISWInfo::IProvider registry classes must implement this interface class IProviderRegistry { public: virtual std::vector> const & swInfoProviders() const = 0; virtual ~IProviderRegistry() = default; }; /// @returns SWInfo data or empty data if there is no info mapped to key virtual std::string info(std::string_view key) const = 0; /// @returns collection of keys for the stored software information virtual std::vector keys() const = 0; /// Initialize software info /// @param infoProviders information providers virtual void initialize( std::vector> const &infoProviders) = 0; virtual ~ISWInfo() = default; }; corectrl-v1.4.2/src/core/info/swinfo.cpp000066400000000000000000000016631467225065400202250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "swinfo.h" #include #include #include std::string SWInfo::info(std::string_view key) const { auto const dataIt = info_.find(std::string(key)); if (dataIt != info_.cend()) return dataIt->second; return std::string{}; } std::vector SWInfo::keys() const { std::vector keys; keys.reserve(info_.size()); auto const keySelector = [](auto const &pair) { return pair.first; }; std::transform(info_.cbegin(), info_.cend(), std::back_inserter(keys), keySelector); return keys; } void SWInfo::initialize( std::vector> const &infoProviders) { for (auto const &provider : infoProviders) { auto infos = provider->provideInfo(); for (auto &info : infos) info_.insert(std::move(info)); } } corectrl-v1.4.2/src/core/info/swinfo.h000066400000000000000000000010271467225065400176640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/info/iswinfo.h" #include #include class SWInfo final : public ISWInfo { public: std::string info(std::string_view key) const override; std::vector keys() const override; void initialize(std::vector> const &infoProviders) override; private: std::unordered_map info_; }; corectrl-v1.4.2/src/core/info/vendor.h000066400000000000000000000002371467225065400176560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once enum class Vendor : int { AMD = 0x1002 }; corectrl-v1.4.2/src/core/iprofile.h000066400000000000000000000035201467225065400172350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/exportable.h" #include "core/importable.h" #include "core/item.h" #include #include #include class IProfile : public Item , public Importable , public Exportable { public: static constexpr std::string_view ItemID{"PROFILE"}; struct Info { static constexpr std::string_view GlobalID{"_global_"}; static constexpr std::string_view ManualID{"_manual_"}; static constexpr std::string_view GlobalIconURL{":/images/GlobalIcon"}; static constexpr std::string_view DefaultIconURL{":/images/DefaultIcon"}; Info(std::string name = "", std::string exe = "", std::string iconURL = std::string(DefaultIconURL)) : name(name) , exe(exe) , iconURL(iconURL) { } bool hasCustomIcon() const { return iconURL != IProfile::Info::DefaultIconURL && iconURL != IProfile::Info::GlobalIconURL; } std::string name{""}; std::string exe{""}; std::string iconURL{DefaultIconURL}; }; class Importer : public Importable::Importer { public: virtual bool provideActive() const = 0; virtual IProfile::Info const &provideInfo() const = 0; virtual ~Importer() = default; }; class Exporter : public Exportable::Exporter { public: virtual void takeActive(bool active) = 0; virtual void takeInfo(Info const &info) = 0; virtual ~Exporter() = default; }; virtual std::unique_ptr initializer() = 0; virtual bool active() const = 0; virtual void activate(bool active) = 0; virtual IProfile::Info const &info() const = 0; virtual void info(IProfile::Info const &info) = 0; virtual std::unique_ptr clone() const = 0; virtual ~IProfile() = default; }; corectrl-v1.4.2/src/core/iprofileapplicator.h000066400000000000000000000004221467225065400213120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once class IProfileView; class IProfileApplicator { public: virtual void apply(IProfileView &profileView) = 0; virtual ~IProfileApplicator() = default; }; corectrl-v1.4.2/src/core/iprofilefileparser.h000066400000000000000000000014271467225065400213160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include class IProfile; class IProfileFileParser { public: static constexpr std::string_view ProfileDataFileName{"profile"}; static constexpr std::string_view IconDataFileName{"icon"}; virtual std::string fileExtension() const = 0; virtual std::optional> load(std::filesystem::path const &path, std::string const &internalDataName) = 0; virtual bool save(std::filesystem::path const &path, std::vector>> const &data) = 0; virtual ~IProfileFileParser() = default; }; corectrl-v1.4.2/src/core/iprofileiconcache.h000066400000000000000000000032431467225065400210740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" #include #include #include #include #include class IProfileIconCache { public: /// Initialization method. virtual void init() = 0; /// Tries to use an icon from the cache, caching the fallback icon when no icon /// was cached. If this also fails, it will try to use the fallback default icon. /// @param info info of the profile to cache the icon for. His iconURL will be /// updated on success /// @param fallbackIcon data of the fallback icon to be cached /// @returns true on success virtual bool tryOrCache(IProfile::Info &info, std::vector const &fallbackIcon) = 0; /// Adds an icon to the cache, overwriting any previous icon for the profile. /// If this fails or there is no icon data, it will try to use the fallback /// default icon. /// @param info info of the profile to cache the icon for. His iconURL will be /// updated on success /// @param iconData data of the icon to be cached /// @returns true on success virtual bool cache(IProfile::Info &info, std::vector const &iconData) = 0; /// Syncs the cache icon when necessary. /// @param info info of the profile whose icon will be synced in the cache /// @return [success, updated] pair. Updated will be true when a new icon is /// cached. virtual std::pair syncCache(IProfile::Info &info) = 0; /// Cleans the profile cached icon on the cache. virtual void clean(IProfile::Info &info) = 0; virtual ~IProfileIconCache() = default; }; corectrl-v1.4.2/src/core/iprofilemanager.h000066400000000000000000000124651467225065400206000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "importable.h" #include "iprofile.h" #include #include #include #include #include #include class ISysModel; class IProfileManager { public: /// Profile manager observers must implement this interface. class Observer { public: /// A new profile was added. /// @param profileName name of the added profile virtual void profileAdded(std::string const &profileName) = 0; /// A profile was removed. /// @param profileName name of the removed profile virtual void profileRemoved(std::string const &profileName) = 0; /// The settings of a profile changed. /// @param profileName name of the profile that changed virtual void profileChanged(std::string const &profileName) = 0; /// The active state of a profile changed. /// @param profileName name of the profile that changed /// @param active new active state virtual void profileActiveChanged(std::string const &profileName, bool active) = 0; /// A profile was saved. /// @param profileName name of the saved profile virtual void profileSaved(std::string const &profileName) = 0; /// The info of a profile changed. /// @param oldInfo old profile info /// @param newInfo new profile info virtual void profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) = 0; virtual ~Observer() = default; }; /// Adds a new profile manager observer. /// @param observer new observer to be added virtual void addObserver(std::shared_ptr observer) = 0; /// Removes a observer from the profile manager observers /// @param observer observer to be removed virtual void removeObserver(std::shared_ptr const &observer) = 0; /// Initialization method. /// @param model system model to initialize from virtual void init(ISysModel const &model) = 0; /// Available profiles. /// @return names of the available profiles virtual std::vector profiles() const = 0; /// Request a profile from the avaiable profiles. /// @param profileName name of the requested profile /// @return the named profile when is available virtual std::optional> profile(std::string const &profileName) const = 0; /// Request the list of not saved profiles. /// @return names of the unsaved profiles virtual std::vector unsavedProfiles() const = 0; /// Checks whether a profile is not saved. /// @param profileName profile name to be checked /// @return true when the profile is unsaved virtual bool unsaved(std::string const &profileName) const = 0; /// Adds a new profile with the supplied info. /// @param info info of the profile to be created virtual void add(IProfile::Info const &info) = 0; /// Adds a clone of a profile with the supplied info. /// @param cloneInfo info of the resulting profile /// @param baseProfileName name of the profile to be cloned virtual void clone(IProfile::Info const &cloneInfo, std::string const &baseProfileName) = 0; /// Removes a profile. /// @param profileName name of the profile to be removed virtual void remove(std::string const &profileName) = 0; /// Changes the active state of a profile. /// @param profileName name of the profile to be changed /// @param active new active state virtual void activate(std::string const &profileName, bool active) = 0; /// Reset a profile settings to its defaults values. /// @param profileName name of the profile to be reseted virtual void reset(std::string const &profileName) = 0; /// Restore a profile from the last saved state. /// @param profileName name of the profile to be restored virtual void restore(std::string const &profileName) = 0; /// Updates the info of a profile. /// @param profileName name of the profile to be updated /// @param newInfo profile's new info virtual void update(std::string const &profileName, IProfile::Info const &newInfo) = 0; /// Updates a profile settings from a profile importer. /// @param profileName name of the profile to be updated /// @param importer profile importer virtual void update(std::string const &profileName, Importable::Importer &importer) = 0; /// Loads a profile settings from a profile file. /// @param profileName name of the profile to be loaded /// @param path path to the profile file /// @return true when the loading was successful virtual bool loadFrom(std::string const &profileName, std::filesystem::path const &path) = 0; /// Saves a profile. /// @param profileName name of the profile to be saved virtual void save(std::string const &profileName) = 0; /// Exports a profile to a profile file. /// @param profileName name of the profile to be exported /// @param path destination path of the exported profile file /// @return true when the exporting was successful virtual bool exportTo(std::string const &profileName, std::filesystem::path const &path) = 0; virtual ~IProfileManager() = default; }; corectrl-v1.4.2/src/core/iprofileparser.h000066400000000000000000000010461467225065400204530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include #include #include class IProfile; class IProfileParser { public: virtual std::string const &format() = 0; virtual std::unique_ptr initializer() = 0; virtual bool load(std::vector const &data, IProfile &profile) = 0; virtual bool save(std::vector &data, IProfile const &profile) = 0; virtual ~IProfileParser() = default; }; corectrl-v1.4.2/src/core/iprofilepart.h000066400000000000000000000016041467225065400201250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "importable.h" #include "item.h" #include class IProfilePartProvider; class IProfilePart : public Item , public Importable , public Exportable { public: class Importer : public Importable::Importer { public: virtual bool provideActive() const = 0; }; class Exporter : public Exportable::Exporter { public: virtual void takeActive(bool active) = 0; }; virtual std::unique_ptr factory(IProfilePartProvider const &profilePartProvider) = 0; virtual std::unique_ptr initializer() = 0; virtual bool active() const = 0; virtual void activate(bool active) = 0; virtual std::unique_ptr clone() const = 0; virtual ~IProfilePart() = default; }; corectrl-v1.4.2/src/core/iprofilepartprovider.h000066400000000000000000000007301467225065400216770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include class IProfilePart; class IProfilePartProvider { public: virtual std::unordered_map()>> const & profilePartProviders() const = 0; virtual ~IProfilePartProvider() = default; }; corectrl-v1.4.2/src/core/iprofilepartview.h000066400000000000000000000005611467225065400210210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class IProfilePart; class IProfilePartView { public: virtual std::string const &profile() const = 0; virtual std::shared_ptr const &part() const = 0; virtual ~IProfilePartView() = default; }; corectrl-v1.4.2/src/core/iprofilepartxmlparser.h000066400000000000000000000014571467225065400220710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "importable.h" #include "item.h" #include #include class IProfilePartXMLParserProvider; class IProfilePartXMLParser : public Item { public: virtual std::unique_ptr factory(IProfilePartXMLParserProvider const &profilePartXMLParserProvider) = 0; virtual std::unique_ptr initializer() = 0; virtual void loadFrom(pugi::xml_node const &parentNode) = 0; virtual void appendTo(pugi::xml_node &parentNode) = 0; virtual Importable::Importer &profilePartImporter() const = 0; virtual Exportable::Exporter &profilePartExporter() const = 0; virtual ~IProfilePartXMLParser() = default; }; corectrl-v1.4.2/src/core/iprofilepartxmlparserprovider.h000066400000000000000000000007541467225065400236430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include class IProfilePartXMLParser; class IProfilePartXMLParserProvider { public: virtual std::unordered_map< std::string, std::function()>> const & profilePartParserProviders() const = 0; virtual ~IProfilePartXMLParserProvider() = default; }; corectrl-v1.4.2/src/core/iprofilestorage.h000066400000000000000000000036761467225065400206360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" #include #include #include /// Stores profiles into a location. class IProfileStorage { public: /// Initializes the profile storage. /// @param defaultProfile default profile of the application virtual void init(IProfile const &defaultProfile) = 0; /// Reads the profiles on the storage. /// @param baseProfile profile used as creation base /// @return loaded profiles virtual std::vector> profiles(IProfile const &baseProfile) = 0; /// Loads a profile from the storage. /// @param profile profile to be loaded /// @return true on success virtual bool load(IProfile &profile) = 0; /// Saves a profile into the storage. /// @param profile profile to be saved /// @return true on success virtual bool save(IProfile &profile) = 0; /// Loads a profile configuration from a file. /// @param profile profile to be loaded /// @param path path to the profile file /// @return true on success virtual bool loadFrom(IProfile &profile, std::filesystem::path const &path) const = 0; /// Exports a profile to a profile file. /// @param profile profile to be exported /// @param path path to the target profile file /// @return true on success virtual bool exportTo(IProfile const &profile, std::filesystem::path const &path) const = 0; /// Updates the info of a stored profile with new info. /// @param profile profile of the stored profile to be updated /// @param newInfo info to be updated /// @return true on success virtual bool update(IProfile const &profile, IProfile::Info &newInfo) = 0; /// Removes a stored profile. /// @param info info of the stored profile to be removed virtual void remove(IProfile::Info &info) = 0; virtual ~IProfileStorage() = default; }; corectrl-v1.4.2/src/core/iprofileview.h000066400000000000000000000012321467225065400201260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "isysmodel.h" #include #include #include class IProfilePart; class IProfilePartView; class IProfileView : public ISysModel::Importer { public: class View { public: virtual std::string const &name() const = 0; virtual std::vector> const &parts() const = 0; virtual ~View() = default; }; virtual std::string const &name() const = 0; virtual std::vector> const &parts() const = 0; virtual ~IProfileView() = default; }; corectrl-v1.4.2/src/core/iprofileviewfactory.h000066400000000000000000000007411467225065400215220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include class Exportable; class IProfileView; class IProfileViewFactory { public: virtual std::unique_ptr build(Exportable const &profile, std::optional> base = std::nullopt) const = 0; virtual ~IProfileViewFactory() = default; }; corectrl-v1.4.2/src/core/iqmlcomponentfactory.h000066400000000000000000000012051467225065400216770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class QMLItem; class QQmlApplicationEngine; class QQuickItem; class IQMLComponentFactory { public: virtual void registerQMLTypes() const = 0; virtual QMLItem *createQMLItem(std::string const &itemID, QQuickItem *parent, QQmlApplicationEngine &qmlEngine) const = 0; virtual QQuickItem * createQuickItem(std::string const &itemID, QQuickItem *parent, std::string const &parentObjectName) const = 0; virtual ~IQMLComponentFactory() = default; }; corectrl-v1.4.2/src/core/iqmlcomponentregistry.h000066400000000000000000000013011467225065400220750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include class QQuickItem; class QQmlApplicationEngine; class QMLItem; class IQMLComponentRegistry { public: virtual std::vector> const & qmlTypeRegisterers() const = 0; virtual std::unordered_map< std::string, std::function> const & qmlItemProviders() const = 0; virtual std::unordered_map> const & quickItemProviders() const = 0; virtual ~IQMLComponentRegistry() = default; }; corectrl-v1.4.2/src/core/isession.h000066400000000000000000000015261467225065400172640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class IProfileView; class IProfileManager; class ISysModel; class ISession { public: class ManualProfileObserver { public: virtual void toggled(std::string const &profileName, bool active) = 0; virtual ~ManualProfileObserver() = default; }; virtual void addManualProfileObserver( std::shared_ptr observer) = 0; virtual void removeManualProfileObserver( std::shared_ptr observer) = 0; virtual void init(ISysModel const &model) = 0; virtual bool toggleManualProfile(std::string const &profileName) = 0; virtual IProfileManager &profileManager() const = 0; virtual ~ISession() = default; }; corectrl-v1.4.2/src/core/isyscomponent.h000066400000000000000000000025641467225065400203450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "importable.h" #include "item.h" #include #include #include #include #include class ICommandQueue; class ISysComponent : public Item , public Importable , public Exportable { public: class Importer : public Importable::Importer { public: virtual bool provideActive() const = 0; }; class Exporter : public Exportable::Exporter { public: virtual void takeActive(bool active) = 0; }; virtual bool active() const = 0; virtual void activate(bool active) = 0; /// @return unique key generated for this system component virtual std::string const &key() const = 0; /// @return component information as a pair of the component name and /// a vector of pairs of key and info values. virtual std::pair>> componentInfo() const = 0; virtual void init() = 0; virtual void preInit(ICommandQueue &ctlCmds) = 0; virtual void postInit(ICommandQueue &ctlCmds) = 0; virtual void sync(ICommandQueue &ctlCmds) = 0; virtual void updateSensors( std::unordered_map> const &ignored) = 0; virtual ~ISysComponent() = default; }; corectrl-v1.4.2/src/core/isyscomponentprofilepart.h000066400000000000000000000005261467225065400226110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "item.h" #include "profilepart.h" #include class ISysComponentProfilePart : public ProfilePart { public: virtual bool belongsTo(Item const &i) const = 0; virtual std::string const &key() const = 0; }; corectrl-v1.4.2/src/core/isysexplorer.h000066400000000000000000000005441467225065400201770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class ISysExplorer { public: /// @returns list of supported render device names (format: renderD) virtual std::vector renderers() = 0; virtual ~ISysExplorer() = default; }; corectrl-v1.4.2/src/core/isysmodel.h000066400000000000000000000021131467225065400174310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/exportable.h" #include "core/importable.h" #include "core/item.h" #include #include #include #include #include #include class ICommandQueue; class ISysModel : public Item , public Importable , public Exportable { public: static constexpr std::string_view ItemID{"SYS_MODEL"}; class Importer : public Importable::Importer { public: }; class Exporter : public Exportable::Exporter { public: }; virtual void init() = 0; virtual void preInit(ICommandQueue &ctlCmds) = 0; virtual void postInit(ICommandQueue &ctlCmds) = 0; virtual void sync(ICommandQueue &ctlCmds) = 0; virtual void updateSensors( std::unordered_map> const &ignored) = 0; virtual std::vector< std::pair>>> info() const = 0; virtual ~ISysModel() = default; }; corectrl-v1.4.2/src/core/isysmodelsyncer.h000066400000000000000000000006431467225065400206630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once class ISysModel; class QString; class QVariant; class ISysModelSyncer { public: virtual ISysModel &sysModel() const = 0; virtual void settingChanged(QString const &key, QVariant const &value) = 0; virtual void init() = 0; virtual void stop() = 0; virtual ~ISysModelSyncer() = default; }; corectrl-v1.4.2/src/core/isysmodelui.h000066400000000000000000000004101467225065400177650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" class ISysModelUI : public IProfile::Importer , public IProfile::Exporter { public: virtual ~ISysModelUI() = default; }; corectrl-v1.4.2/src/core/item.h000066400000000000000000000010351467225065400163610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class Item { public: virtual std::string const &ID() const = 0; /// Returns the instance ID. /// /// When there are multiple instances of the same item, an unique /// instance ID will be returned for each item. Otherwise, the /// returned instance ID will be the value of the item ID. virtual std::string const &instanceID() const { return ID(); } virtual ~Item() = default; }; corectrl-v1.4.2/src/core/iuifactory.h000066400000000000000000000005741467225065400176100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once class ISession; class ISysModel; class QQmlApplicationEngine; class IUIFactory { public: virtual void build(QQmlApplicationEngine &qmlEngine, ISysModel const &sysModel, ISession &session) const = 0; virtual ~IUIFactory() = default; }; corectrl-v1.4.2/src/core/profile.cpp000066400000000000000000000073431467225065400174260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profile.h" #include "iprofile.h" #include "iprofilepart.h" #include "iprofilepartprovider.h" #include "isyscomponent.h" #include "isyscomponentprofilepart.h" #include "isysmodel.h" #include "item.h" #include #include #include #include Profile::Factory::Factory(IProfilePartProvider const &profilePartProvider, Profile &outer) noexcept : ProfilePart::Factory(profilePartProvider) , outer_(outer) { } void Profile::Factory::takeProfilePart(std::unique_ptr &&part) { outer_.parts_.emplace_back(std::move(part)); } std::optional> Profile::Factory::provideExporter(Item const &i) { auto &id = i.ID(); if (id == ISysModel::ItemID) return *this; else return factory(id); } class Profile::Initializer final : public ISysModel::Exporter { public: Initializer(Profile const &outer) : outer_(outer) { } std::optional> provideExporter(Item const &i) override; private: Profile const &outer_; std::unordered_map> initializers_; }; std::optional> Profile::Initializer::provideExporter(Item const &i) { auto &id = i.ID(); if (id == ISysModel::ItemID) return *this; else { auto &key = dynamic_cast(i).key(); for (auto &part : outer_.parts_) { if (key == dynamic_cast(*part).key()) { if (initializers_.count(key) > 0) return *initializers_.at(key); else { auto initializer = part->initializer(); if (initializer != nullptr) { initializers_.emplace(key, std::move(initializer)); return *initializers_.at(key); } } break; } } } return {}; } Profile::Profile() noexcept : id_(IProfile::ItemID) { } std::unique_ptr Profile::initializer() { return std::make_unique(*this); } bool Profile::active() const { return active_; } void Profile::activate(bool active) { active_ = active; } IProfile::Info const &Profile::info() const { return info_; } void Profile::info(Info const &info) { info_ = info; } std::unique_ptr Profile::clone() const { auto clone = std::make_unique(); clone->active_ = active_; clone->info_ = info_; clone->parts_.reserve(parts_.size()); std::transform( parts_.cbegin(), parts_.cend(), std::back_inserter(clone->parts_), [](std::shared_ptr const &part) { return part->clone(); }); return std::move(clone); } std::string const &Profile::ID() const { return id_; } void Profile::importWith(Importable::Importer &i) { auto importer = i.provideImporter(*this); if (importer.has_value()) { auto &profileImporter = dynamic_cast(importer->get()); activate(profileImporter.provideActive()); info(profileImporter.provideInfo()); for (auto &part : parts_) part->importWith(*importer); } } void Profile::exportWith(Exportable::Exporter &e) const { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { auto &profileExporter = dynamic_cast(exporter->get()); profileExporter.takeActive(active()); profileExporter.takeInfo(info()); for (auto const &part : parts_) part->exportWith(*exporter); } } std::string const &Profile::name() const { return info_.name; } std::vector> const &Profile::parts() const { return parts_; } corectrl-v1.4.2/src/core/profile.h000066400000000000000000000031361467225065400170670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" #include "iprofileview.h" #include "isysmodel.h" #include "profilepart.h" #include #include #include class IProfilePartProvider; class Profile final : public IProfile , public IProfileView::View { public: Profile() noexcept; Profile(Profile const &) = delete; Profile &operator=(Profile const &) = delete; std::unique_ptr initializer() override; bool active() const override; void activate(bool active) override; IProfile::Info const &info() const override; void info(IProfile::Info const &info) override; std::unique_ptr clone() const override; std::string const &ID() const override; void importWith(Importable::Importer &i) override; void exportWith(Exportable::Exporter &e) const override; std::string const &name() const override; std::vector> const &parts() const override; class Factory final : public ProfilePart::Factory , public ISysModel::Exporter { public: Factory(IProfilePartProvider const &profilePartProvider, Profile &outer) noexcept; void takeProfilePart(std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; private: Profile &outer_; }; private: class Initializer; std::string const id_; std::vector> parts_; IProfile::Info info_; bool active_{true}; }; corectrl-v1.4.2/src/core/profilefactory.cpp000066400000000000000000000011651467225065400210120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilefactory.h" #include "isysmodel.h" #include "profile.h" #include ProfileFactory::ProfileFactory( std::unique_ptr &&profilePartProvider) noexcept : profilePartProvider_(std::move(profilePartProvider)) { } std::unique_ptr ProfileFactory::build(ISysModel const &sysModel) const { auto profile = std::make_unique(); Profile::Factory profileFactory(*profilePartProvider_, *profile); sysModel.exportWith(profileFactory); return std::move(profile); } corectrl-v1.4.2/src/core/profilefactory.h000066400000000000000000000007421467225065400204570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofilepartprovider.h" #include class ISysModel; class IProfile; class ProfileFactory final { public: ProfileFactory( std::unique_ptr &&profilePartProvider) noexcept; std::unique_ptr build(ISysModel const &sysModel) const; private: std::unique_ptr profilePartProvider_; }; corectrl-v1.4.2/src/core/profileiconcache.cpp000066400000000000000000000045721467225065400212640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profileiconcache.h" #include "ifilecache.h" #include #include ProfileIconCache::ProfileIconCache(std::unique_ptr &&cache) noexcept : cache_(std::move(cache)) { } void ProfileIconCache::init() { cache_->init(); } bool ProfileIconCache::tryOrCache(IProfile::Info &info, std::vector const &fallbackIcon) { auto fileName = info.exe != IProfile::Info::ManualID ? info.exe : info.exe + info.name; // try the cache auto cacheURL = cache_->get(fileName); if (cacheURL.has_value()) { if (info.iconURL != *cacheURL) info.iconURL = *cacheURL; return true; } // cache fallback icon return cache(info, fallbackIcon); } bool ProfileIconCache::cache(IProfile::Info &info, std::vector const &iconData) { auto cacheURL = cacheIconFromData(iconData, info); if (cacheURL.has_value()) { info.iconURL = *cacheURL; return true; } return false; } std::pair ProfileIconCache::syncCache(IProfile::Info &info) { auto fileName = info.exe != IProfile::Info::ManualID ? info.exe : info.exe + info.name; auto cacheURL = cache_->add(info.iconURL, fileName); if (cacheURL.has_value()) { auto updateURL = info.iconURL != *cacheURL; if (updateURL) info.iconURL = *cacheURL; return {true, updateURL}; } SPDLOG_DEBUG("Failed to cache icon for {}", fileName.data()); return {false, false}; } void ProfileIconCache::clean(IProfile::Info &info) { auto fileName = info.exe != IProfile::Info::ManualID ? info.exe : info.exe + info.name; cache_->remove(fileName); } std::optional ProfileIconCache::cacheIconFromData(std::vector const &iconData, IProfile::Info const &info) const { auto fileName = info.exe != IProfile::Info::ManualID ? info.exe : info.exe + info.name; auto cacheURL = cache_->add(iconData, fileName); if (cacheURL.has_value()) return cacheURL; SPDLOG_DEBUG("Failed to cache icon for {}", fileName.data()); return {}; } corectrl-v1.4.2/src/core/profileiconcache.h000066400000000000000000000016221467225065400207220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofileiconcache.h" #include #include #include #include class IFileCache; class ProfileIconCache final : public IProfileIconCache { public: ProfileIconCache(std::unique_ptr &&cache) noexcept; void init() override; bool tryOrCache(IProfile::Info &info, std::vector const &fallbackIcon) override; bool cache(IProfile::Info &info, std::vector const &iconData) override; std::pair syncCache(IProfile::Info &info) override; void clean(IProfile::Info &info) override; private: std::optional cacheIconFromData(std::vector const &iconData, IProfile::Info const &info) const; std::unique_ptr const cache_; }; corectrl-v1.4.2/src/core/profilemanager.cpp000066400000000000000000000271061467225065400207600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilemanager.h" #include "core/isysmodel.h" #include "iprofile.h" #include #include #include #include #include ProfileManager::ProfileManager( std::unique_ptr &&defautlProfile, std::unique_ptr &&profileStorage) noexcept : defaultProfile_(std::move(defautlProfile)) , profileStorage_(std::move(profileStorage)) { } void ProfileManager::addObserver(std::shared_ptr observer) { std::lock_guard lock(obMutex_); auto const it = std::find(observers_.begin(), observers_.end(), observer); if (it == observers_.end()) observers_.emplace_back(std::move(observer)); } void ProfileManager::removeObserver( std::shared_ptr const &observer) { std::lock_guard lock(obMutex_); std::erase(observers_, observer); } void ProfileManager::init(ISysModel const &model) { // initialize default profile model.exportWith(*defaultProfile_->initializer()); profileStorage_->init(*defaultProfile_); std::regex const invalidName(R"(^\s+$)"); std::regex const invalidExe(R"(\\\|\/|\||\x00|\*|`|;|:|'|")"); std::unordered_set exes; bool globalFound = false; auto profiles = profileStorage_->profiles(*defaultProfile_); for (auto &profile : profiles) { auto &info = profile->info(); if (info.exe == IProfile::Info::GlobalID) { auto overrideInfo = info; overrideInfo.name = IProfile::Info::GlobalID; overrideInfo.iconURL = IProfile::Info::GlobalIconURL; profile->info(overrideInfo); globalFound = true; } if (!globalFound && info.name == IProfile::Info::GlobalID) { SPDLOG_WARN("Ignoring profile with name: '{}', exe: '{}'", info.name, info.exe); SPDLOG_WARN("Used profile name ({}) is reserved for the Global Profile", info.name); continue; } if (!globalFound && info.exe == IProfile::Info::GlobalID) { SPDLOG_WARN("Ignoring profile with name: '{}', exe: '{}'", info.name, info.exe); SPDLOG_WARN("Used profile executable name ({}) is " "reserved for the Global Profile", info.exe); continue; } if (std::regex_search(info.name, invalidName)) { SPDLOG_WARN("Ignoring profile with name: '{}', exe: '{}'", info.name, info.exe); SPDLOG_WARN("Profile name ({}) has invalid characters", info.name); continue; } auto profileIt = profiles_.find(info.name); if (profileIt != profiles_.cend()) { SPDLOG_WARN("Ignoring profile with name: '{}', exe: '{}'", info.name, info.exe); SPDLOG_WARN("There is another profile with the same name ({})", info.name); continue; } if (info.exe != IProfile::Info::ManualID) { if (std::regex_search(info.exe, invalidExe)) { SPDLOG_WARN("Ignoring profile with name: '{}', exe: '{}'", info.name, info.exe); SPDLOG_WARN("Profile executable name ({}) has invalid characters", info.exe); continue; } auto exeIt = exes.find(info.exe); if (exeIt != exes.cend()) { SPDLOG_WARN("Ignoring profile with name: '{}', exe: '{}'", info.name, info.exe); SPDLOG_WARN("There is another profile for the same executable ({})", info.exe); continue; } exes.insert(info.exe); } profiles_.emplace(info.name, std::move(profile)); } if (!globalFound) { auto globalProfile = defaultProfile_->clone(); globalProfile->info({std::string(IProfile::Info::GlobalID), std::string(IProfile::Info::GlobalID), std::string(IProfile::Info::GlobalIconURL)}); profileStorage_->save(*globalProfile); profiles_.emplace(globalProfile->info().name, std::move(globalProfile)); } } std::vector ProfileManager::profiles() const { std::vector profiles; profiles.reserve(profiles_.size()); std::transform(profiles_.cbegin(), profiles_.cend(), std::back_inserter(profiles), [](auto const &kv) { return kv.first; }); return profiles; } std::optional> ProfileManager::profile(std::string const &profileName) const { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) return *profileIt->second; return {}; } std::vector ProfileManager::unsavedProfiles() const { std::vector profiles; profiles.reserve(unsavedProfiles_.size()); std::transform(unsavedProfiles_.cbegin(), unsavedProfiles_.cend(), std::back_inserter(profiles), [](auto const &profile) { return profile; }); return profiles; } bool ProfileManager::unsaved(std::string const &profileName) const { return unsavedProfiles_.find(profileName) != unsavedProfiles_.cend(); } void ProfileManager::add(IProfile::Info const &info) { auto const profileIt = profiles_.find(info.name); if (profileIt == profiles_.cend()) { auto newProfile = defaultProfile_->clone(); newProfile->info(info); profileStorage_->save(*newProfile); profiles_.emplace(info.name, std::move(newProfile)); notifyProfileAdded(info.name); } } void ProfileManager::clone(IProfile::Info const &cloneInfo, std::string const &baseProfileName) { auto const profileIt = profiles_.find(baseProfileName); if (profileIt != profiles_.cend()) { auto const clonedProfileIt = profiles_.find(cloneInfo.name); if (clonedProfileIt == profiles_.cend()) { auto clone = profileIt->second->clone(); clone->info(cloneInfo); // manual profiles are always active if (cloneInfo.exe == IProfile::Info::ManualID) clone->activate(true); profileStorage_->save(*clone); profiles_.emplace(cloneInfo.name, std::move(clone)); notifyProfileAdded(cloneInfo.name); } } } void ProfileManager::remove(std::string const &profileName) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { auto info = profileIt->second->info(); profileStorage_->remove(info); profiles_.erase(profileIt); notifyProfileRemoved(profileName); } } void ProfileManager::activate(std::string const &profileName, bool active) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { auto &profile = profileIt->second; // update stored profile active state auto storedProfile = profile->clone(); profileStorage_->load(*storedProfile); storedProfile->activate(active); profileStorage_->save(*storedProfile); // update profile active state profile->activate(active); notifyProfileActiveChanged(profileName, active); } } void ProfileManager::reset(std::string const &profileName) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { auto resetedProfile = defaultProfile_->clone(); resetedProfile->info(profileIt->second->info()); resetedProfile->activate(profileIt->second->active()); profiles_.insert_or_assign(profileName, std::move(resetedProfile)); unsavedProfiles_.insert(profileName); notifyProfileChanged(profileName); } } void ProfileManager::restore(std::string const &profileName) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { profileStorage_->load(*profileIt->second); unsavedProfiles_.erase(profileName); notifyProfileChanged(profileName); } } void ProfileManager::update(std::string const &profileName, IProfile::Info const &newInfo) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { auto &profile = *profileIt->second; auto oldInfo = profile.info(); auto info = newInfo; profileStorage_->update(profile, info); // update profile info profile.info(info); if (info.name != profileName) { // re-inserting element with the new name as key auto profileNodeHandler = profiles_.extract(profileIt); profileNodeHandler.key() = info.name; profiles_.insert(std::move(profileNodeHandler)); // updating unsaved profile name auto unsavedIt = unsavedProfiles_.find(profileName); if (unsavedIt != unsavedProfiles_.cend()) { unsavedProfiles_.erase(unsavedIt); unsavedProfiles_.insert(info.name); } } notifyProfileInfoChanged(oldInfo, info); // manual profiles are always active if (info.exe == IProfile::Info::ManualID && !profile.active()) { profile.activate(true); notifyProfileActiveChanged(info.name, true); } } } void ProfileManager::update(std::string const &profileName, Importable::Importer &importer) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { profileIt->second->importWith(importer); unsavedProfiles_.insert(profileName); notifyProfileChanged(profileName); } } bool ProfileManager::loadFrom(std::string const &profileName, std::filesystem::path const &path) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { auto &profile = *profileIt->second; auto info = profile.info(); auto active = profile.active(); if (!profileStorage_->loadFrom(profile, path)) return false; profile.activate(active); profile.info(info); unsavedProfiles_.insert(profileName); notifyProfileChanged(profileName); return true; } return false; } void ProfileManager::save(std::string const &profileName) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) { profileStorage_->save(*profileIt->second); unsavedProfiles_.erase(profileName); notifyProfileSaved(profileName); } } bool ProfileManager::exportTo(std::string const &profileName, std::filesystem::path const &path) { auto const profileIt = profiles_.find(profileName); if (profileIt != profiles_.cend()) return profileStorage_->exportTo(*profileIt->second, path); return false; } void ProfileManager::notifyProfileAdded(std::string const &profileName) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->profileAdded(profileName); } void ProfileManager::notifyProfileRemoved(std::string const &profileName) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->profileRemoved(profileName); } void ProfileManager::notifyProfileChanged(std::string const &profileName) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->profileChanged(profileName); } void ProfileManager::notifyProfileActiveChanged(std::string const &profileName, bool active) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->profileActiveChanged(profileName, active); } void ProfileManager::notifyProfileSaved(std::string const &profileName) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->profileSaved(profileName); } void ProfileManager::notifyProfileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->profileInfoChanged(oldInfo, newInfo); } corectrl-v1.4.2/src/core/profilemanager.h000066400000000000000000000052511467225065400204220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" #include "iprofilemanager.h" #include "iprofilestorage.h" #include #include #include #include #include class ProfileManager final : public IProfileManager { public: ProfileManager(std::unique_ptr &&defaultProfile, std::unique_ptr &&profileStorage) noexcept; void addObserver(std::shared_ptr observer) override; void removeObserver( std::shared_ptr const &observer) override; void init(ISysModel const &model) override; std::vector profiles() const override; std::optional> profile(std::string const &profileName) const override; std::vector unsavedProfiles() const override; bool unsaved(std::string const &profileName) const override; void add(IProfile::Info const &info) override; void clone(IProfile::Info const &cloneInfo, std::string const &baseProfileName = std::string(IProfile::Info::GlobalID)) override; void remove(std::string const &profileName) override; void activate(std::string const &profileName, bool active) override; void reset(std::string const &profileName) override; void restore(std::string const &profileName) override; void update(std::string const &profileName, IProfile::Info const &newInfo) override; void update(std::string const &profileName, Importable::Importer &importer) override; bool loadFrom(std::string const &profileName, std::filesystem::path const &path) override; void save(std::string const &profileName) override; bool exportTo(std::string const &profileName, std::filesystem::path const &path) override; private: void notifyProfileAdded(std::string const &profileName); void notifyProfileRemoved(std::string const &profileName); void notifyProfileChanged(std::string const &profileName); void notifyProfileActiveChanged(std::string const &profileName, bool active); void notifyProfileSaved(std::string const &profileName); void notifyProfileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo); std::unique_ptr defaultProfile_; std::unique_ptr profileStorage_; std::unordered_map> profiles_; std::unordered_set unsavedProfiles_; std::vector> observers_; std::mutex obMutex_; }; corectrl-v1.4.2/src/core/profilemanagerui.cpp000066400000000000000000000241101467225065400213060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilemanagerui.h" #include "iprofile.h" #include "iprofilemanager.h" #include "isession.h" #include "isysmodelui.h" #include "qmlcomponentregistry.h" #include #include #include #include #include char const *const ProfileManagerUI::trStrings[] = { QT_TRANSLATE_NOOP("ProfileManagerUI", "_global_"), }; class ProfileManagerUI::ProfileManagerObserver : public IProfileManager::Observer { public: ProfileManagerObserver(ProfileManagerUI &outer) noexcept : outer_(outer) { } void profileAdded(std::string const &profileName) override; void profileRemoved(std::string const &profileName) override; void profileChanged(std::string const &profileName) override; void profileActiveChanged(std::string const &profileName, bool active) override; void profileSaved(std::string const &profileName) override; void profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) override; private: ProfileManagerUI &outer_; }; void ProfileManagerUI::ProfileManagerObserver::profileAdded( std::string const &profileName) { outer_.addProfileComponet(profileName); } void ProfileManagerUI::ProfileManagerObserver::profileRemoved( std::string const &profileName) { emit outer_.profileRemoved(QString::fromStdString(profileName)); } void ProfileManagerUI::ProfileManagerObserver::profileChanged( std::string const &profileName) { emit outer_.profileChanged(QString::fromStdString(profileName)); } void ProfileManagerUI::ProfileManagerObserver::profileActiveChanged( std::string const &profileName, bool active) { emit outer_.profileActiveChanged(QString::fromStdString(profileName), active); } void ProfileManagerUI::ProfileManagerObserver::profileSaved( std::string const &profileName) { emit outer_.profileSaved(QString::fromStdString(profileName)); } void ProfileManagerUI::ProfileManagerObserver::profileInfoChanged( IProfile::Info const &oldInfo, IProfile::Info const &newInfo) { outer_.addProfileUsedNames(newInfo.name); auto profile = outer_.profileManager_->profile(newInfo.name); emit outer_.profileInfoChanged( QString::fromStdString(oldInfo.name), QString::fromStdString(newInfo.name), newInfo.exe != IProfile::Info::ManualID ? QString::fromStdString(newInfo.exe) : QLatin1String(""), outer_.toQMLIconPath(newInfo.iconURL), newInfo.hasCustomIcon(), profile->get().active()); } class ProfileManagerUI::ManualProfileObserver : public ISession::ManualProfileObserver { public: ManualProfileObserver(ProfileManagerUI &outer) noexcept : outer_(outer) { } void toggled(std::string const &profileName, bool active) override; private: ProfileManagerUI &outer_; }; void ProfileManagerUI::ManualProfileObserver::toggled( const std::string &profileName, bool active) { emit outer_.manualProfileToggled(QString::fromStdString(profileName), active); } ProfileManagerUI::ProfileManagerUI(QObject *parent) noexcept : QObject(parent) , profileManagerObserver_( std::make_shared(*this)) , manualProfileObserver_( std::make_shared(*this)) { usedExecutableNames_.insert( QString::fromLatin1(IProfile::Info::ManualID.data())); } void ProfileManagerUI::init(ISession *session, ISysModelUI *sysModelUI) { sysModelUI_ = sysModelUI; session_ = session; session_->addManualProfileObserver(manualProfileObserver_); profileManager_ = &session_->profileManager(); profileManager_->addObserver(profileManagerObserver_); // create profile components auto profileNames = profileManager_->profiles(); // short profile names std::sort(profileNames.begin(), profileNames.end()); // the global profile must be the first element auto globalIt = std::find_if( profileNames.begin(), profileNames.end(), [](auto const &profile) { return profile == IProfile::Info::GlobalID; }); if (globalIt != profileNames.cend()) std::rotate(profileNames.begin(), globalIt, globalIt + 1); QVariantList list; for (auto const &profileName : profileNames) { addProfileUsedNames(profileName); auto profile = profileManager_->profile(profileName); auto &info = profile->get().info(); list.append(QString::fromStdString(info.name)); list.append(info.exe != IProfile::Info::ManualID ? QString::fromStdString(info.exe) : QLatin1String("")); list.append(toQMLIconPath(info.iconURL)); list.append(profile->get().active()); list.append(info.hasCustomIcon()); } emit initProfiles(list); } QString ProfileManagerUI::defaultIcon() const { return toQMLIconPath(IProfile::Info::DefaultIconURL.data()); } bool ProfileManagerUI::isProfileNameInUse(QString const &profileName) { return usedProfileNames_.contains(profileName); } bool ProfileManagerUI::isExecutableNameInUse(QString const &executableName) { return usedExecutableNames_.contains(executableName); } bool ProfileManagerUI::isProfileUnsaved(QString const &profileName) { return profileManager_->unsaved(profileName.toStdString()); } bool ProfileManagerUI::isProfileActive(QString const &profileName) { auto profile = profileManager_->profile(profileName.toStdString()); if (profile.has_value()) return profile->get().active(); return false; } void ProfileManagerUI::add(QString const &name, QString const &exe, QString const &icon, QString const &base) { IProfile::Info info(name.toStdString(), exe.length() > 0 ? exe.toStdString() : std::string(IProfile::Info::ManualID)); info.iconURL = cleanIconFilePath(icon); if (base == "defaultProfile") profileManager_->add(std::move(info)); else profileManager_->clone(std::move(info), base.toStdString()); } void ProfileManagerUI::remove(QString const &name) { auto profileName = name.toStdString(); removeProfileUsedNames(profileName); profileManager_->remove(profileName); } void ProfileManagerUI::updateInfo(QString const &oldName, QString const &newName, QString const &exe, QString const &icon) { auto profileName = oldName.toStdString(); removeProfileUsedNames(profileName); IProfile::Info info(newName.toStdString(), exe.length() > 0 ? exe.toStdString() : std::string(IProfile::Info::ManualID), cleanIconFilePath(icon)); profileManager_->update(profileName, info); } void ProfileManagerUI::activate(QString const &name, bool active) { profileManager_->activate(name.toStdString(), active); } void ProfileManagerUI::toggleManualProfile(QString const &name) { session_->toggleManualProfile(name.toStdString()); } void ProfileManagerUI::loadSettings(QString const &name) { auto profile = profileManager_->profile(name.toStdString()); if (profile.has_value()) profile->get().exportWith(*sysModelUI_); } bool ProfileManagerUI::loadSettings(QString const &name, QUrl const &path) { if (profileManager_->loadFrom( name.toStdString(), path.toString(QUrl::RemoveScheme).toStdString())) { loadSettings(name); return true; } return false; } void ProfileManagerUI::applySettings(QString const &name) { profileManager_->update(name.toStdString(), *sysModelUI_); } void ProfileManagerUI::resetSettings(QString const &name) { profileManager_->reset(name.toStdString()); loadSettings(name); } void ProfileManagerUI::restoreSettings(QString const &name) { profileManager_->restore(name.toStdString()); loadSettings(name); } void ProfileManagerUI::saveSettings(QString const &name) { profileManager_->save(name.toStdString()); } bool ProfileManagerUI::exportProfile(QString const &name, QUrl const &path) { return profileManager_->exportTo( name.toStdString(), path.toString(QUrl::RemoveScheme).toStdString()); } std::string ProfileManagerUI::cleanIconFilePath(QString iconPath) const { if (iconPath.startsWith("file://")) iconPath.remove("file://"); else if (iconPath.startsWith("qrc:")) iconPath.remove(0, 3); return iconPath.toStdString(); } QString ProfileManagerUI::toQMLIconPath(std::string const &iconPath) const { auto qtIconPath = QString::fromStdString(iconPath); if (qtIconPath.startsWith(":/")) qtIconPath.prepend("qrc"); else qtIconPath.prepend("file://"); return qtIconPath; } void ProfileManagerUI::addProfileComponet(std::string const &profileName) { addProfileUsedNames(profileName); auto profile = profileManager_->profile(profileName); auto &info = profile->get().info(); emit profileAdded(QString::fromStdString(info.name), info.exe != IProfile::Info::ManualID ? QString::fromStdString(info.exe) : QLatin1String(""), toQMLIconPath(info.iconURL), info.hasCustomIcon(), profile->get().active()); } void ProfileManagerUI::addProfileUsedNames(std::string const &profileName) { auto profile = profileManager_->profile(profileName); auto &profileInfo = profile->get().info(); auto name = QString::fromStdString(profileName); usedProfileNames_.insert(name); if (profileInfo.exe != IProfile::Info::ManualID) { auto exe = QString::fromStdString(profileInfo.exe); usedExecutableNames_.insert(exe); } } void ProfileManagerUI::removeProfileUsedNames(std::string const &profileName) { auto profile = profileManager_->profile(profileName); auto &profileInfo = profile->get().info(); auto name = QString::fromStdString(profileName); usedProfileNames_.remove(name); if (profileInfo.exe != IProfile::Info::ManualID) { auto exe = QString::fromStdString(profileInfo.exe); usedExecutableNames_.remove(exe); } } bool const ProfileManagerUI::registered_ = QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, ProfileManagerUI::QMLComponentID.data()); }); corectrl-v1.4.2/src/core/profilemanagerui.h000066400000000000000000000062311467225065400207570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include #include #include class IProfileManager; class ISession; class ISysModelUI; class IFileCache; class ProfileManagerUI : public QObject { Q_OBJECT public: static constexpr std::string_view QMLComponentID{"PROFILE_MANAGER"}; explicit ProfileManagerUI(QObject *parent = nullptr) noexcept; void init(ISession *session, ISysModelUI *sysModelUI); Q_INVOKABLE QString defaultIcon() const; Q_INVOKABLE bool isProfileNameInUse(QString const &profileName); Q_INVOKABLE bool isExecutableNameInUse(QString const &executableName); Q_INVOKABLE bool isProfileUnsaved(QString const &profileName); Q_INVOKABLE bool isProfileActive(QString const &profileName); Q_INVOKABLE void add(QString const &name, QString const &exe, QString const &icon, QString const &base); Q_INVOKABLE void remove(QString const &name); Q_INVOKABLE void updateInfo(QString const &oldName, QString const &newName, QString const &exe, QString const &icon); Q_INVOKABLE void activate(QString const &name, bool active); Q_INVOKABLE void toggleManualProfile(QString const &name); Q_INVOKABLE void loadSettings(QString const &name); Q_INVOKABLE bool loadSettings(QString const &name, QUrl const &path); Q_INVOKABLE void applySettings(QString const &name); Q_INVOKABLE void resetSettings(QString const &name); Q_INVOKABLE void restoreSettings(QString const &name); Q_INVOKABLE void saveSettings(QString const &name); Q_INVOKABLE bool exportProfile(QString const &name, QUrl const &path); signals: void initProfiles(QVariantList const &profiles); void profileAdded(QString const &name, QString const &exe, QString const &icon, bool hasCustomIcon, bool isActive); void profileRemoved(QString const &name); void profileChanged(QString const &name); void profileActiveChanged(QString const &name, bool active); void manualProfileToggled(QString const &name, bool active); void profileSaved(QString const &name); void profileInfoChanged(QString const &oldName, QString const &newName, QString const &exe, QString const &icon, bool hasCustomIcon, bool isActive); private: std::string cleanIconFilePath(QString iconPath) const; QString toQMLIconPath(std::string const &iconPath) const; void addProfileComponet(std::string const &profileName); void addProfileUsedNames(std::string const &profileName); void removeProfileUsedNames(std::string const &profileName); ISession *session_{nullptr}; IProfileManager *profileManager_{nullptr}; ISysModelUI *sysModelUI_{nullptr}; class ProfileManagerObserver; std::shared_ptr profileManagerObserver_; class ManualProfileObserver; std::shared_ptr manualProfileObserver_; QSet usedProfileNames_; QSet usedExecutableNames_; static bool const registered_; static char const *const trStrings[]; }; corectrl-v1.4.2/src/core/profilepart.cpp000066400000000000000000000037461467225065400203200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilepart.h" #include "iprofilepartprovider.h" #include bool ProfilePart::active() const { return active_; } void ProfilePart::activate(bool active) { active_ = active; } std::unique_ptr ProfilePart::clone() const { auto clone = cloneProfilePart(); clone->activate(active()); return clone; } void ProfilePart::importWith(Importable::Importer &i) { auto importer = i.provideImporter(*this); if (importer.has_value()) { auto &profilePartImporter = dynamic_cast(importer->get()); activate(profilePartImporter.provideActive()); importProfilePart(profilePartImporter); } } void ProfilePart::exportWith(Exportable::Exporter &e) const { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { auto &profilePartExporter = dynamic_cast(exporter->get()); profilePartExporter.takeActive(active()); exportProfilePart(profilePartExporter); } } ProfilePart::Factory::Factory(IProfilePartProvider const &profilePartProvider) noexcept : profilePartProvider_(profilePartProvider) { } std::optional> ProfilePart::Factory::factory(std::string const &componentID) { auto profilePart = createPart(componentID); if (profilePart != nullptr) { auto factory = profilePart->factory(profilePartProvider_); takeProfilePart(std::move(profilePart)); if (factory != nullptr) { factories_.emplace_back(std::move(factory)); return *factories_.back(); } } return {}; } std::unique_ptr ProfilePart::Factory::createPart(std::string const &componentID) const { auto &partProviders = profilePartProvider_.profilePartProviders(); auto const providerIt = partProviders.find(componentID); if (providerIt != partProviders.cend()) return providerIt->second(); return nullptr; } corectrl-v1.4.2/src/core/profilepart.h000066400000000000000000000030361467225065400177550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "iprofilepart.h" #include "iprofilepartprovider.h" #include #include #include #include #include class ProfilePart : public IProfilePart { public: ProfilePart() = default; ProfilePart(ProfilePart const &) = delete; ProfilePart &operator=(ProfilePart const &) = delete; bool active() const final override; void activate(bool active) final override; std::unique_ptr clone() const final override; void importWith(Importable::Importer &i) final override; void exportWith(Exportable::Exporter &e) const final override; class Factory { public: Factory(IProfilePartProvider const &profilePartProvider) noexcept; std::optional> factory(std::string const &componentID); virtual void takeProfilePart(std::unique_ptr &&part) = 0; virtual ~Factory() = default; protected: std::unique_ptr createPart(std::string const &componentID) const; private: IProfilePartProvider const &profilePartProvider_; std::vector> factories_; }; protected: virtual void importProfilePart(IProfilePart::Importer &i) = 0; virtual void exportProfilePart(IProfilePart::Exporter &e) const = 0; virtual std::unique_ptr cloneProfilePart() const = 0; private: bool active_{true}; }; corectrl-v1.4.2/src/core/profilepartprovider.cpp000066400000000000000000000015361467225065400220660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilepartprovider.h" #include std::unordered_map()>> const & ProfilePartProvider::profilePartProviders() const { return profilePartProviders_(); } std::unordered_map()>> & ProfilePartProvider::profilePartProviders_() { static std::unordered_map()>> providers; return providers; } bool ProfilePartProvider::registerProvider( std::string_view componentID, std::function()> &&provider) { profilePartProviders_().emplace(std::string(componentID), std::move(provider)); return true; } corectrl-v1.4.2/src/core/profilepartprovider.h000066400000000000000000000014221467225065400215250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofilepartprovider.h" #include #include #include #include #include class IProfilePart; class ProfilePartProvider final : public IProfilePartProvider { public: std::unordered_map()>> const & profilePartProviders() const override; static bool registerProvider(std::string_view componentID, std::function()> &&provider); private: static std::unordered_map()>> & profilePartProviders_(); }; corectrl-v1.4.2/src/core/profilepartview.cpp000066400000000000000000000007711467225065400212060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilepartview.h" #include ProfilePartView::ProfilePartView(std::string const &profile, std::shared_ptr part) noexcept : profile_(profile) , part_(std::move(part)) { } std::string const &ProfilePartView::profile() const { return profile_; } std::shared_ptr const &ProfilePartView::part() const { return part_; } corectrl-v1.4.2/src/core/profilepartview.h000066400000000000000000000010671467225065400206520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofilepartview.h" #include #include class IProfilePart; class ProfilePartView final : public IProfilePartView { public: ProfilePartView(std::string const &profile, std::shared_ptr part) noexcept; std::string const &profile() const override; std::shared_ptr const &part() const override; private: std::string profile_; std::shared_ptr part_; }; corectrl-v1.4.2/src/core/profilepartxmlparser.cpp000066400000000000000000000035601467225065400222500ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilepartxmlparser.h" #include "iprofilepartxmlparserprovider.h" #include "item.h" #include ProfilePartXMLParser::ProfilePartXMLParser(std::string_view id, Importable::Importer &importer, Exportable::Exporter &exporter) noexcept : id_(id) , importer_(importer) , exporter_(exporter) { } std::string const &ProfilePartXMLParser::ID() const { return id_; } void ProfilePartXMLParser::loadFrom(pugi::xml_node const &parentNode) { resetAttributes(); loadPartFrom(parentNode); } Importable::Importer &ProfilePartXMLParser::profilePartImporter() const { return importer_; } Exportable::Exporter &ProfilePartXMLParser::profilePartExporter() const { return exporter_; } ProfilePartXMLParser::Factory::Factory( IProfilePartXMLParserProvider const &profilePartParserProvider) noexcept : profilePartParserProvider_(profilePartParserProvider) { } std::optional> ProfilePartXMLParser::Factory::factory(Item const &i) { auto partParser = createPartParser(i.ID()); if (partParser != nullptr) { auto factory = partParser->factory(profilePartParserProvider_); takePartParser(i, std::move(partParser)); if (factory != nullptr) { factories_.emplace_back(std::move(factory)); return *factories_.back(); } } return {}; } std::unique_ptr ProfilePartXMLParser::Factory::createPartParser(std::string const &componentID) const { auto &partParserProviders = profilePartParserProvider_.profilePartParserProviders(); auto const providerIt = partParserProviders.find(componentID); if (providerIt != partParserProviders.cend()) return providerIt->second(); return nullptr; } corectrl-v1.4.2/src/core/profilepartxmlparser.h000066400000000000000000000033421467225065400217130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "importable.h" #include "iprofilepartxmlparser.h" #include #include #include #include #include #include #include class Item; class IProfilePartXMLParserProvider; class ProfilePartXMLParser : public IProfilePartXMLParser { public: ProfilePartXMLParser(std::string_view id, Importable::Importer &profilePartImporter, Exportable::Exporter &profilePartExporter) noexcept; std::string const &ID() const final override; void loadFrom(pugi::xml_node const &parentNode) final override; Importable::Importer &profilePartImporter() const final override; Exportable::Exporter &profilePartExporter() const final override; class Factory { public: Factory(IProfilePartXMLParserProvider const &profilePartParserProvider) noexcept; std::optional> factory(Item const &i); virtual void takePartParser(Item const &i, std::unique_ptr &&part) = 0; virtual ~Factory() = default; private: std::unique_ptr createPartParser(std::string const &componentID) const; IProfilePartXMLParserProvider const &profilePartParserProvider_; std::vector> factories_; }; protected: virtual void resetAttributes() = 0; virtual void loadPartFrom(pugi::xml_node const &parentNode) = 0; private: std::string const id_; Importable::Importer &importer_; Exportable::Exporter &exporter_; }; corectrl-v1.4.2/src/core/profilepartxmlparserprovider.cpp000066400000000000000000000017671467225065400240320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilepartxmlparserprovider.h" #include std::unordered_map()>> const & ProfilePartXMLParserProvider::profilePartParserProviders() const { return profilePartParserProviders_(); } std::unordered_map()>> & ProfilePartXMLParserProvider::profilePartParserProviders_() { static std::unordered_map< std::string, std::function()>> providers; return providers; } bool ProfilePartXMLParserProvider::registerProvider( std::string_view componentID, std::function()> &&provider) { profilePartParserProviders_().emplace(std::string(componentID), std::move(provider)); return true; } corectrl-v1.4.2/src/core/profilepartxmlparserprovider.h000066400000000000000000000015251467225065400234670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofilepartxmlparserprovider.h" #include #include #include #include #include class IProfilePartXMLParser; class ProfilePartXMLParserProvider final : public IProfilePartXMLParserProvider { public: std::unordered_map()>> const & profilePartParserProviders() const override; static bool registerProvider( std::string_view componentID, std::function()> &&provider); private: static std::unordered_map< std::string, std::function()>> & profilePartParserProviders_(); }; corectrl-v1.4.2/src/core/profilestorage.cpp000066400000000000000000000160571467225065400210150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilestorage.h" #include "common/fileutils.h" #include "iprofilefileparser.h" #include "iprofileiconcache.h" #include "iprofileparser.h" #include #include #include #include #include namespace fs = std::filesystem; ProfileStorage::ProfileStorage( std::filesystem::path &&path, std::unique_ptr &&profileParser, std::unique_ptr &&profileFileParser, std::unique_ptr &&iconCache) noexcept : path_(std::move(path)) , profileParser_(std::move(profileParser)) , profileFileParser_(std::move(profileFileParser)) , iconCache_(std::move(iconCache)) , profileDataFileName_(IProfileFileParser::ProfileDataFileName) { fileExtension_ += "." + profileFileParser_->fileExtension(); profileDataFileName_ += "." + profileParser_->format(); } void ProfileStorage::init(IProfile const &defaultProfile) { initProfilesDirectory(); // initialize components defaultProfile.exportWith(*profileParser_->initializer()); iconCache_->init(); } std::vector> ProfileStorage::profiles(IProfile const &baseProfile) { std::vector> profiles; if (profilesDirectoryExist()) { for (auto const &pathIt : fs::directory_iterator(path_)) { auto const &filePath = pathIt.path(); if (Utils::File::isFilePathValid(filePath) && filePath.extension() == fileExtension_) { auto profile = baseProfile.clone(); if (loadProfileFromStorage(filePath, *profile)) profiles.emplace_back(std::move(profile)); } } } return profiles; } bool ProfileStorage::load(IProfile &profile) { if (profilesDirectoryExist()) { auto info = profile.info(); auto fileName = info.exe != IProfile::Info::ManualID ? info.exe + fileExtension_ : info.exe + info.name + fileExtension_; return loadProfileFromStorage(path_ / fileName, profile); } return false; } bool ProfileStorage::save(IProfile &profile) { if (profilesDirectoryExist()) { auto info = profile.info(); auto fileName = info.exe != IProfile::Info::ManualID ? info.exe + fileExtension_ : info.exe + info.name + fileExtension_; auto exported = exportTo(profile, path_ / fileName); if (exported) { if (info.hasCustomIcon()) { // sync icon cache when custom icons are used auto [success, updated] = iconCache_->syncCache(info); if (success && updated) profile.info(info); } return true; } } return false; } bool ProfileStorage::loadFrom(IProfile &profile, std::filesystem::path const &path) const { if (Utils::File::isFilePathValid(path) && path.extension() == fileExtension_) return loadProfileFrom(path, profile); else SPDLOG_DEBUG("Cannot load {}. Invalid file.", path.c_str()); return false; } bool ProfileStorage::exportTo(IProfile const &profile, std::filesystem::path const &path) const { std::vector profileData; if (profileParser_->save(profileData, profile)) { std::vector>> data; data.emplace_back(std::string(profileDataFileName_), std::move(profileData)); auto info = profile.info(); if (info.hasCustomIcon()) { // save the custom icon in the profile auto iconData = Utils::File::readFile(info.iconURL); if (!iconData.empty()) data.emplace_back(std::string(IProfileFileParser::IconDataFileName), std::move(iconData)); } auto targetFilePath = path; if (targetFilePath.extension() != fileExtension_) targetFilePath += fileExtension_; return profileFileParser_->save(targetFilePath, data); } return false; } bool ProfileStorage::update(IProfile const &profile, IProfile::Info &newInfo) { auto updatedProfile = profile.clone(); if (!load(*updatedProfile)) return false; // manual profiles are always active if (newInfo.exe == IProfile::Info::ManualID && !updatedProfile->active()) updatedProfile->activate(true); auto oldInfo = profile.info(); updatedProfile->info(newInfo); if (!save(*updatedProfile)) return false; auto cacheURL = updatedProfile->info().iconURL; if (cacheURL != newInfo.iconURL) newInfo.iconURL = cacheURL; if (oldInfo.exe != newInfo.exe || (oldInfo.exe == IProfile::Info::ManualID && newInfo.exe == IProfile::Info::ManualID && oldInfo.name != newInfo.name)) remove(oldInfo); return true; } void ProfileStorage::remove(IProfile::Info &info) { if (profilesDirectoryExist()) { iconCache_->clean(info); auto fileName = info.exe != IProfile::Info::ManualID ? info.exe + fileExtension_ : info.exe + info.name + fileExtension_; try { fs::remove(path_ / fileName); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } } } void ProfileStorage::initProfilesDirectory() const { if (!fs::exists(path_)) { fs::create_directories(path_); fs::permissions(path_, fs::perms::owner_all | fs::perms::group_read | fs::perms::group_exec | fs::perms::others_read | fs::perms::others_exec); } if (!fs::is_directory(path_)) throw std::runtime_error( std::format("{} is not a directory.", path_.c_str())); } bool ProfileStorage::profilesDirectoryExist() const { if (Utils::File::isDirectoryPathValid(path_)) return true; SPDLOG_DEBUG("Something went wrong with the profile storage directory: ", path_.c_str()); return false; } bool ProfileStorage::loadProfileFromStorage(std::filesystem::path const &path, IProfile &profile) const { auto profileData = profileFileParser_->load(path, profileDataFileName_); if (profileData.has_value()) { if (profileParser_->load(*profileData, profile)) { auto info = profile.info(); if (info.exe == IProfile::Info::GlobalID) info.iconURL = IProfile::Info::GlobalIconURL; else { // try to read the icon stored in the profile auto profileIcon = profileFileParser_->load( path, std::string(IProfileFileParser::IconDataFileName)); // profiles without icons use the default icon if (!profileIcon.has_value()) info.iconURL = IProfile::Info::DefaultIconURL; // profiles with icons use a cached icon else if (iconCache_->tryOrCache(info, *profileIcon)) profile.info(info); } return true; } } return false; } bool ProfileStorage::loadProfileFrom(std::filesystem::path const &path, IProfile &profile) const { auto profileData = profileFileParser_->load(path, profileDataFileName_); if (profileData.has_value()) return profileParser_->load(*profileData, profile); return false; } corectrl-v1.4.2/src/core/profilestorage.h000066400000000000000000000033601467225065400204530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofilestorage.h" #include #include #include #include #include class IProfileParser; class IProfileFileParser; class IProfileIconCache; class ProfileStorage : public IProfileStorage { public: ProfileStorage(std::filesystem::path &&path, std::unique_ptr &&profileParser, std::unique_ptr &&profileFileParser, std::unique_ptr &&iconCache) noexcept; void init(IProfile const &defaultProfile) override; std::vector> profiles(IProfile const &baseProfile) override; bool load(IProfile &profile) override; bool save(IProfile &profile) override; bool loadFrom(IProfile &profile, std::filesystem::path const &path) const override; bool exportTo(IProfile const &profile, std::filesystem::path const &path) const override; bool update(IProfile const &profile, IProfile::Info &newInfo) override; void remove(IProfile::Info &info) override; private: void initProfilesDirectory() const; bool profilesDirectoryExist() const; bool loadProfileFromStorage(std::filesystem::path const &path, IProfile &profile) const; bool loadProfileFrom(std::filesystem::path const &path, IProfile &profile) const; std::filesystem::path const path_; std::unique_ptr profileParser_; std::unique_ptr profileFileParser_; std::unique_ptr iconCache_; std::string fileExtension_; std::string profileDataFileName_; }; corectrl-v1.4.2/src/core/profileview.cpp000066400000000000000000000050621467225065400203150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profileview.h" #include "iprofilepart.h" #include "isyscomponentprofilepart.h" #include "isysmodel.h" #include "profilepartview.h" #include #include std::string const &ProfileView::name() const { return name_; } std::vector> const &ProfileView::parts() const { return parts_; } std::optional> ProfileView::provideImporter(Item const &i) { if (i.ID() == ISysModel::ItemID) return *this; else { auto partIter = std::find_if( parts_.cbegin(), parts_.cend(), [&](std::unique_ptr const &part) { auto *sysPart = dynamic_cast( part->part().get()); if (sysPart == nullptr) return false; return sysPart->belongsTo(i); }); if (partIter != parts_.cend()) return dynamic_cast(*partIter->get()->part()); } return {}; } ProfileView::Initializer::Initializer( ProfileView &profileView, std::optional> base) noexcept : profileView_(profileView) , base_(base) { } std::optional> ProfileView::Initializer::provideExporter(Item const &i) { if (i.ID() == IProfile::ItemID) { auto &pView = dynamic_cast(i); profileView_.name_ = pView.name(); auto const &parts = pView.parts(); for (auto const &part : parts) { std::shared_ptr profilePart; std::string partProfileName; if (!part->active() && base_.has_value()) { // compose from base_ partProfileName = base_->get().name(); auto const &baseParts = base_->get().parts(); auto const basePartIter = std::find_if( baseParts.cbegin(), baseParts.cend(), [&](auto const &partView) { return partView->part()->ID() == part->ID(); }); if (basePartIter != baseParts.cend()) profilePart = basePartIter->get()->part(); } else { partProfileName = dynamic_cast(i).info().name; profilePart = part; } profileView_.parts_.emplace_back(std::make_unique( std::move(partProfileName), std::move(profilePart))); } } return {}; } void ProfileView::Initializer::takeActive(bool) { } void ProfileView::Initializer::takeInfo(IProfile::Info const &) { } corectrl-v1.4.2/src/core/profileview.h000066400000000000000000000023321467225065400177570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "iprofile.h" #include "iprofilepartview.h" #include "iprofileview.h" #include #include #include #include #include class ProfileView final : public IProfileView { public: std::string const &name() const override; std::vector> const &parts() const override; std::optional> provideImporter(Item const &i) override; class Initializer : public IProfile::Exporter { public: Initializer(ProfileView &profileView, std::optional> base = std::nullopt) noexcept; std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(IProfile::Info const &info) override; private: ProfileView &profileView_; std::optional> base_; }; private: std::string name_; std::vector> parts_; }; corectrl-v1.4.2/src/core/profileviewfactory.cpp000066400000000000000000000010471467225065400217040ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profileviewfactory.h" #include "exportable.h" #include "profileview.h" #include std::unique_ptr ProfileViewFactory::build( Exportable const &profile, std::optional> base) const { auto profileView = std::make_unique(); ProfileView::Initializer pvInitializer(*profileView, base); profile.exportWith(pvInitializer); return std::move(profileView); } corectrl-v1.4.2/src/core/profileviewfactory.h000066400000000000000000000007201467225065400213460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofileviewfactory.h" #include #include #include class Exportable; class IProfileView; class ProfileViewFactory final : public IProfileViewFactory { public: std::unique_ptr build(Exportable const &profile, std::optional> base) const; }; corectrl-v1.4.2/src/core/profilexmlparser.cpp000066400000000000000000000127321467225065400213620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilexmlparser.h" #include "iprofile.h" #include "isyscomponentprofilepart.h" #include #include #include #include #include ProfileXMLParser::Factory::Factory( IProfilePartXMLParserProvider const &profilePartParserProvider, ProfileXMLParser &outer) noexcept : ProfilePartXMLParser::Factory(profilePartParserProvider) , outer_(outer) { } void ProfileXMLParser::Factory::takePartParser( Item const &i, std::unique_ptr &&part) { auto &key = dynamic_cast(i).key(); outer_.parsers_.emplace(key, std::move(part)); } std::optional> ProfileXMLParser::Factory::provideExporter(Item const &i) { if (i.ID() == IProfile::ItemID) return *this; else return factory(i); } class ProfileXMLParser::Initializer final : public IProfile::Exporter { public: Initializer(ProfileXMLParser &outer) noexcept : outer_(outer) { } std::optional> provideExporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(IProfile::Info const &info) override; private: ProfileXMLParser &outer_; std::unordered_map> initializers_; }; std::optional> ProfileXMLParser::Initializer::provideExporter(Item const &i) { auto &id = i.ID(); if (id == IProfile::ItemID) return *this; else { auto &key = dynamic_cast(i).key(); if (initializers_.count(key) > 0) return *initializers_.at(key); else if (outer_.parsers_.count(key) > 0) { auto initializer = outer_.parsers_.at(key)->initializer(); if (initializer != nullptr) { initializers_.emplace(key, std::move(initializer)); return *initializers_.at(key); } } } return {}; } void ProfileXMLParser::Initializer::takeActive(bool active) { outer_.active_ = outer_.activeDefault_ = active; } void ProfileXMLParser::Initializer::takeInfo(IProfile::Info const &info) { outer_.info_ = outer_.infoDefault_ = info; } ProfileXMLParser::ProfileXMLParser() noexcept : format_("xml") { profileNodeName_ = IProfile::ItemID; std::transform(profileNodeName_.cbegin(), profileNodeName_.cend(), profileNodeName_.begin(), ::toupper); } std::string const &ProfileXMLParser::format() { return format_; } std::unique_ptr ProfileXMLParser::initializer() { return std::make_unique(*this); } bool ProfileXMLParser::load(std::vector const &data, IProfile &profile) { pugi::xml_document doc; auto status = doc.load_buffer(data.data(), data.size()); if (status) { auto profileNode = doc.child(profileNodeName_.c_str()); if (!profileNode.empty()) { auto active = profileNode.attribute("active"); auto name = profileNode.attribute("name"); auto exe = profileNode.attribute("exe"); active_ = active.as_bool(activeDefault_); info_.name = name.as_string(infoDefault_.name.c_str()); info_.exe = exe.as_string(infoDefault_.exe.c_str()); for (auto &[key, component] : parsers_) component->loadFrom(profileNode); profile.importWith(*this); return true; } } SPDLOG_DEBUG("Cannot parse xml data for profile {}.\nError: {}", profile.info().name, status.description()); return false; } class PugiXMLWriter final : public pugi::xml_writer { public: PugiXMLWriter(std::vector &data) : data_(data) { data.clear(); } void write(const void *data, size_t size) override { auto start = data_.size(); data_.resize(start + size); memcpy(&data_[start], data, size * sizeof(char)); } private: std::vector &data_; }; bool ProfileXMLParser::save(std::vector &data, IProfile const &profile) { profile.exportWith(*this); pugi::xml_document doc; auto profileNode = doc.append_child(profileNodeName_.c_str()); profileNode.append_attribute("active") = active_; profileNode.append_attribute("name") = info_.name.c_str(); profileNode.append_attribute("exe") = info_.exe.c_str(); for (auto &[key, component] : parsers_) component->appendTo(profileNode); PugiXMLWriter writer(data); doc.save(writer); return true; } std::optional> ProfileXMLParser::provideExporter(Item const &i) { if (i.ID() == IProfile::ItemID) return *this; auto &key = dynamic_cast(i).key(); auto const iter = parsers_.find(key); if (iter != parsers_.cend()) return iter->second->profilePartExporter(); return {}; } std::optional> ProfileXMLParser::provideImporter(Item const &i) { if (i.ID() == IProfile::ItemID) return *this; auto &key = dynamic_cast(i).key(); auto const iter = parsers_.find(key); if (iter != parsers_.cend()) return iter->second->profilePartImporter(); return {}; } void ProfileXMLParser::takeActive(bool active) { active_ = active; } void ProfileXMLParser::takeInfo(IProfile::Info const &info) { info_ = info; } bool ProfileXMLParser::provideActive() const { return active_; } IProfile::Info const &ProfileXMLParser::provideInfo() const { return info_; } corectrl-v1.4.2/src/core/profilexmlparser.h000066400000000000000000000037571467225065400210360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" #include "iprofileparser.h" #include "profilepartxmlparser.h" #include #include #include class IProfilePartXMLParser; class IProfilePartXMLParserProvider; class ProfileXMLParser final : public IProfileParser , public IProfile::Importer , public IProfile::Exporter { public: ProfileXMLParser() noexcept; std::string const &format() override; std::unique_ptr initializer() override; bool load(std::vector const &data, IProfile &profile) override; bool save(std::vector &data, IProfile const &profile) override; std::optional> provideExporter(Item const &i) override; std::optional> provideImporter(Item const &i) override; void takeActive(bool active) override; void takeInfo(IProfile::Info const &info) override; bool provideActive() const override; IProfile::Info const &provideInfo() const override; class Factory final : public ProfilePartXMLParser::Factory , public IProfile::Exporter { public: Factory(IProfilePartXMLParserProvider const &profilePartParserProvider, ProfileXMLParser &outer) noexcept; void takePartParser(Item const &i, std::unique_ptr &&part) override; std::optional> provideExporter(Item const &i) override; void takeActive(bool) override { } void takeInfo(IProfile::Info const &) override { } private: ProfileXMLParser &outer_; }; private: class Initializer; std::string const format_; std::string profileNodeName_; std::unordered_map> parsers_; IProfile::Info info_; IProfile::Info infoDefault_; bool active_; bool activeDefault_; }; corectrl-v1.4.2/src/core/profilexmlparserfactory.cpp000066400000000000000000000014411467225065400227450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "profilexmlparserfactory.h" #include "iprofile.h" #include "iprofileparser.h" #include "iprofilepartxmlparserprovider.h" #include "profilexmlparser.h" #include ProfileXMLParserFactory::ProfileXMLParserFactory( std::unique_ptr &&profilePartParserProvider) noexcept : profilePartParserProvider_(std::move(profilePartParserProvider)) { } std::unique_ptr ProfileXMLParserFactory::build(IProfile const &baseProfile) const { auto parser = std::make_unique(); ProfileXMLParser::Factory parserFactory(*profilePartParserProvider_, *parser); baseProfile.exportWith(parserFactory); return std::move(parser); } corectrl-v1.4.2/src/core/profilexmlparserfactory.h000066400000000000000000000010631467225065400224120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class IProfile; class IProfileParser; class IProfilePartXMLParserProvider; class ProfileXMLParserFactory { public: ProfileXMLParserFactory(std::unique_ptr &&profilePartParserProvider) noexcept; std::unique_ptr build(IProfile const &baseProfile) const; private: std::unique_ptr profilePartParserProvider_; }; corectrl-v1.4.2/src/core/qmlcomponentfactory.cpp000066400000000000000000000047441467225065400220740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "qmlcomponentfactory.h" #include "qmlcomponentregistry.h" #include "qmlitem.h" #include #include #include #include #include QMLComponentFactory::QMLComponentFactory( std::unique_ptr &&qmlComponentRegistry) noexcept : qmlComponentRegistry_(std::move(qmlComponentRegistry)) { } void QMLComponentFactory::registerQMLTypes() const { auto const &qmlTypeRegisterers = qmlComponentRegistry_->qmlTypeRegisterers(); for (auto const &qmlTypeRegisterer : qmlTypeRegisterers) qmlTypeRegisterer(); } QMLItem *QMLComponentFactory::createQMLItem(std::string const &itemID, QQuickItem *parent, QQmlApplicationEngine &qmlEngine) const { auto &qmlItemProviders = qmlComponentRegistry_->qmlItemProviders(); auto const providerIt = qmlItemProviders.find(itemID); if (providerIt != qmlItemProviders.cend()) { auto item = providerIt->second(qmlEngine); QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership); auto parentName = parent->objectName(); if (!parentName.contains(QMLItem::ParentObjectSuffix.data())) parentName.append(QMLItem::ParentObjectSuffix.data()); parentItem(item, parent, parentName.toStdString()); return item; } return nullptr; } QQuickItem * QMLComponentFactory::createQuickItem(std::string const &itemID, QQuickItem *parent, std::string const &parentObjectName) const { auto quickItemProviders = qmlComponentRegistry_->quickItemProviders(); auto providerIt = quickItemProviders.find(itemID); if (providerIt != quickItemProviders.cend()) { auto item = providerIt->second(); QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership); parentItem(item, parent, parentObjectName); return item; } return nullptr; } void QMLComponentFactory::parentItem(QQuickItem *item, QQuickItem *parent, std::string_view parentObjectName) const { QQuickItem *parentItem = parent; if (parent->objectName() != parentObjectName.data()) { parentItem = parent->findChild(parentObjectName.data()); if (parentItem == nullptr) parentItem = parent; } item->setParentItem(parentItem); item->setParent(parentItem); } corectrl-v1.4.2/src/core/qmlcomponentfactory.h000066400000000000000000000022531467225065400215320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iqmlcomponentfactory.h" #include #include class IQMLComponentRegistry; class QQuickItem; class QMLComponentFactory final : public IQMLComponentFactory { public: QMLComponentFactory( std::unique_ptr &&qmlComponentRegistry) noexcept; void registerQMLTypes() const override; QMLItem *createQMLItem(std::string const &itemID, QQuickItem *parent, QQmlApplicationEngine &qmlEngine) const override; QQuickItem *createQuickItem(std::string const &itemID, QQuickItem *parent, std::string const &parentObjectName) const override; private: /// Parent item to the first object that has parentObjectName as /// object name (the parent itself or one of its children) /// If there is no object with parentObjectName as object name, /// the item is parented to parent. void parentItem(QQuickItem *item, QQuickItem *parent, std::string_view parentObjectName) const; std::unique_ptr qmlComponentRegistry_; }; corectrl-v1.4.2/src/core/qmlcomponentregistry.cpp000066400000000000000000000036421467225065400222710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "qmlcomponentregistry.h" #include std::vector> const & QMLComponentRegistry::qmlTypeRegisterers() const { return qmlTypeRegisterers_(); } std::unordered_map> const & QMLComponentRegistry::qmlItemProviders() const { return qmlItemProviders_(); } std::unordered_map> const & QMLComponentRegistry::quickItemProviders() const { return quickItemProviders_(); } bool QMLComponentRegistry::addQMLTypeRegisterer(std::function &®isterer) { qmlTypeRegisterers_().emplace_back(std::move(registerer)); return true; } bool QMLComponentRegistry::addQMLItemProvider( std::string_view componentID, std::function &&provider) { qmlItemProviders_().emplace(std::string(componentID), std::move(provider)); return true; } bool QMLComponentRegistry::addQuickItemProvider( std::string_view itemID, std::function &&provider) { quickItemProviders_().emplace(std::string(itemID), std::move(provider)); return true; } std::vector> &QMLComponentRegistry::qmlTypeRegisterers_() { static std::vector> registerers; return registerers; } std::unordered_map> & QMLComponentRegistry::qmlItemProviders_() { static std::unordered_map> providers; return providers; } std::unordered_map> & QMLComponentRegistry::quickItemProviders_() { static std::unordered_map> providers; return providers; } corectrl-v1.4.2/src/core/qmlcomponentregistry.h000066400000000000000000000026501467225065400217340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iqmlcomponentregistry.h" #include #include #include #include #include class QMLItem; class QQmlApplicationEngine; class QQuickItem; class QMLComponentRegistry final : public IQMLComponentRegistry { public: std::vector> const & qmlTypeRegisterers() const override; std::unordered_map> const & qmlItemProviders() const override; std::unordered_map> const & quickItemProviders() const override; static bool addQMLTypeRegisterer(std::function &®isterer); static bool addQMLItemProvider( std::string_view componentID, std::function &&provider); static bool addQuickItemProvider(std::string_view itemID, std::function &&provider); private: static std::vector> &qmlTypeRegisterers_(); static std::unordered_map> & qmlItemProviders_(); static std::unordered_map> & quickItemProviders_(); }; corectrl-v1.4.2/src/core/qmlitem.cpp000066400000000000000000000024601467225065400174310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "qmlitem.h" #include "iqmlcomponentfactory.h" #include QString const &QMLItem::name() const { return name_; } void QMLItem::setName(QString const &name) { if (name_ != name) { name_ = name; emit nameChanged(); } } void QMLItem::setupChild(QQuickItem *child) { auto qmlItemChild = dynamic_cast(child); if (qmlItemChild != nullptr) connect(qmlItemChild, &QMLItem::settingsChanged, this, &QMLItem::settingsChanged, Qt::UniqueConnection); } QMLItem::Initializer::Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) noexcept : qmlComponentFactory_(qmlComponentFactory) , qmlEngine_(qmlEngine) { } std::pair>, QMLItem *> QMLItem::Initializer::initializer(std::string const &itemID, QMLItem *parent) { auto item = qmlComponentFactory_.createQMLItem(itemID, parent, qmlEngine_); if (item != nullptr) { auto factory = item->initializer(qmlComponentFactory_, qmlEngine_); if (factory != nullptr) { initializers_.emplace_back(std::move(factory)); return {*initializers_.back(), item}; } } return {}; } corectrl-v1.4.2/src/core/qmlitem.h000066400000000000000000000037321467225065400171010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include #include #include #include #include #include #include #include #include #include class IQMLComponentFactory; class QQmlApplicationEngine; class QMLItem : public QQuickItem { Q_OBJECT Q_PROPERTY(QString name READ name NOTIFY nameChanged) public: /// Suffix used for QMLItem parent objects in QML files static constexpr std::string_view ParentObjectSuffix{"_Plug"}; /// @returns item's name QString const &name() const; /// @returns Initializer of the derived class virtual std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) = 0; virtual ~QMLItem() = default; Q_INVOKABLE void setupChild(QQuickItem *child); Q_INVOKABLE virtual void activate(bool active) = 0; signals: void nameChanged(); void settingsChanged(); protected: /// Sets the item's name void setName(QString const &name); public: /// QMLItem specializations should extend this class in their /// Initializer specializations class Initializer { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) noexcept; /// @returns A pair with an instance of the initializer for the QMLItem /// registered with the itemID and a pointer to the created QMLItem std::pair>, QMLItem *> initializer(std::string const &itemID, QMLItem *parent); virtual ~Initializer() = default; protected: IQMLComponentFactory const &qmlComponentFactory_; private: QQmlApplicationEngine &qmlEngine_; std::vector> initializers_; }; private: QString name_; }; corectrl-v1.4.2/src/core/session.cpp000066400000000000000000000351731467225065400174530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "session.h" #include "helper/ihelpermonitor.h" #include "iprofileapplicator.h" #include "iprofilemanager.h" #include "iprofileview.h" #include "iprofileviewfactory.h" #include #include #include class Session::ProfileManagerObserver : public IProfileManager::Observer { public: ProfileManagerObserver(Session &outer) noexcept : outer_(outer) { } void profileAdded(std::string const &profileName) override; void profileRemoved(std::string const &profileName) override; void profileChanged(std::string const &profileName) override; void profileActiveChanged(std::string const &profileName, bool active) override; void profileSaved(std::string const &profileName) override; void profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) override; private: Session &outer_; }; void Session::ProfileManagerObserver::profileAdded(std::string const &profileName) { outer_.profileAdded(profileName); } void Session::ProfileManagerObserver::profileRemoved(std::string const &profileName) { outer_.profileRemoved(profileName); } void Session::ProfileManagerObserver::profileChanged(std::string const &profileName) { outer_.profileChanged(profileName); } void Session::ProfileManagerObserver::profileActiveChanged( std::string const &profileName, bool active) { outer_.profileActiveChanged(profileName, active); } void Session::ProfileManagerObserver::profileSaved(std::string const &profileName) { outer_.profileSaved(profileName); } void Session::ProfileManagerObserver::profileInfoChanged( IProfile::Info const &oldInfo, IProfile::Info const &newInfo) { outer_.profileInfoChanged(oldInfo, newInfo); } class Session::HelperMonitorObserver : public IHelperMonitor::Observer { public: HelperMonitorObserver(Session &outer) noexcept : outer_(outer) { } void appExec(std::string appExe) override; void appExit(std::string appExe) override; private: Session &outer_; }; void Session::HelperMonitorObserver::appExec(std::string appExe) { outer_.queueProfileViewForExecutable(appExe); } void Session::HelperMonitorObserver::appExit(std::string appExe) { outer_.dequeueProfileViewForExecutable(appExe); } Session::Session(std::shared_ptr profileApplicator, std::unique_ptr &&profileManager, std::unique_ptr &&profileViewFactory, std::unique_ptr &&helperMonitor) noexcept : profileApplicator_(std::move(profileApplicator)) , profileManager_(std::move(profileManager)) , profileViewFactory_(std::move(profileViewFactory)) , helperMonitor_(std::move(helperMonitor)) , profileManagerObserver_( std::make_shared(*this)) , helperMonitorObserver_(std::make_shared(*this)) { profileManager_->addObserver(profileManagerObserver_); helperMonitor_->addObserver(helperMonitorObserver_); } void Session::addManualProfileObserver( std::shared_ptr observer) { std::lock_guard lock(manualProfileObserversMutex_); auto const it = std::find(manualProfileObservers_.begin(), manualProfileObservers_.end(), observer); if (it == manualProfileObservers_.cend()) manualProfileObservers_.emplace_back(std::move(observer)); } void Session::removeManualProfileObserver( std::shared_ptr observer) { std::lock_guard lock(manualProfileObserversMutex_); std::erase(manualProfileObservers_, observer); } void Session::init(ISysModel const &model) { profileManager_->init(model); populateProfileExeIndex(); createProfileViews({}, {std::string(IProfile::Info::GlobalID)}); profileApplicator_->apply(*pViews_.back()); helperMonitor_->init(); watchProfiles(); } bool Session::toggleManualProfile(std::string const &profileName) { auto profile = profileManager_->profile(profileName); if (!profile || profile->get().info().exe != IProfile::Info::ManualID) return false; std::lock_guard lock(pViewsMutex_); std::lock_guard mLock(manualProfileMutex_); auto baseView = getBaseView(pViews_, manualProfile_); // remove profile view of the active manual profile if (manualProfile_.has_value()) { pViews_.pop_back(); notifyManualProfileToggled(*manualProfile_, false); } // update manual profile state if (manualProfile_.has_value() && manualProfile_ == profileName) manualProfile_ = std::nullopt; else manualProfile_ = profileName; // create the profile view of the manual profile if (manualProfile_.has_value()) { createProfileViews(baseView, {*manualProfile_}); notifyManualProfileToggled(*manualProfile_, true); } // apply active profile view profileApplicator_->apply(*pViews_.back()); return true; } IProfileManager &Session::profileManager() const { return *profileManager_; } void Session::profileAdded(std::string const &profileName) { auto profile = profileManager_->profile(profileName); if (profile.has_value() && profile->get().active() && profile->get().info().exe != IProfile::Info::ManualID) { auto const &exe = profile->get().info().exe; std::lock_guard lock(profileExeIndexMutex_); if (profileExeIndex_.find(exe) == profileExeIndex_.cend()) { profileExeIndex_.emplace(exe, profileName); helperMonitor_->watchApp(exe); } } } void Session::profileRemoved(std::string const &profileName) { bool isManual = false; { std::lock_guard lock(manualProfileMutex_); if (manualProfile_ == profileName) { manualProfile_ = std::nullopt; isManual = true; notifyManualProfileToggled(profileName, false); } } if (!isManual) { // remove from profile executable index std::lock_guard lock(profileExeIndexMutex_); auto const profileIndexIter = std::find_if( profileExeIndex_.cbegin(), profileExeIndex_.cend(), [&](auto const &indexItem) { return indexItem.second == profileName; }); if (profileIndexIter != profileExeIndex_.cend()) { helperMonitor_->forgetApp(profileIndexIter->first); profileExeIndex_.erase(profileIndexIter); } } dequeueProfileView(profileName); } void Session::profileChanged(std::string const &profileName) { std::lock_guard lock(pViewsMutex_); auto const profileViewIter = std::find_if( pViews_.cbegin(), pViews_.cend(), [&](auto const &pv) { return pv->name() == profileName; }); if (profileViewIter != pViews_.cend()) { // compute a list with the names of profile views to recreate std::vector pViewsToRecreate; pViewsToRecreate.reserve(pViews_.size()); std::transform(profileViewIter, pViews_.cend(), std::back_inserter(pViewsToRecreate), [](auto const &pv) { return pv->name(); }); // remove outdated profile views pViews_.erase(profileViewIter, pViews_.cend()); // recreate the list of profile views { std::lock_guard lock(manualProfileMutex_); createProfileViews(getBaseView(pViews_, manualProfile_), pViewsToRecreate); } // apply active profile view profileApplicator_->apply(*pViews_.back()); } } void Session::profileActiveChanged(std::string const &profileName, bool active) { auto profile = profileManager_->profile(profileName); if (profile.has_value() && profile->get().info().exe != IProfile::Info::ManualID) { if (active) profileAdded(profileName); else profileRemoved(profileName); } } void Session::profileSaved(std::string const &) { } void Session::profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo) { if (oldInfo.exe != newInfo.exe || oldInfo.name != newInfo.name) { // sync profile executable index { std::lock_guard lock(profileExeIndexMutex_); profileExeIndex_.erase(oldInfo.exe); if (newInfo.exe != IProfile::Info::ManualID) profileExeIndex_.emplace(newInfo.exe, newInfo.name); } // update monitor if (oldInfo.exe != newInfo.exe) { if (oldInfo.exe != IProfile::Info::ManualID) helperMonitor_->forgetApp(oldInfo.exe); if (newInfo.exe != IProfile::Info::ManualID) helperMonitor_->watchApp(newInfo.exe); } // handle active manual profile if (oldInfo.exe == IProfile::Info::ManualID) { std::lock_guard lock(manualProfileMutex_); if (oldInfo.name == manualProfile_) { // the manual profile has been turned into an automatic profile if (newInfo.exe != IProfile::Info::ManualID) manualProfile_ = std::nullopt; else // only the profile name has changed manualProfile_ = newInfo.name; } } // handle profile view { std::lock_guard lock(pViewsMutex_); // find the profile view auto profileViewIter = std::find_if( pViews_.cbegin(), pViews_.cend(), [&](auto const &pv) { return pv->name() == oldInfo.name; }); if (profileViewIter != pViews_.end()) { std::vector pViewsToRecreate; pViewsToRecreate.reserve(pViews_.size()); // recreate the profile view when only its name has been changed if (oldInfo.exe == newInfo.exe && oldInfo.name != newInfo.name) pViewsToRecreate.push_back(newInfo.name); // compute a list with the names of profile views to recreate auto nextProfileViewIter = std::next(profileViewIter); if (nextProfileViewIter != pViews_.end()) { std::transform(nextProfileViewIter, pViews_.cend(), std::back_inserter(pViewsToRecreate), [](auto const &pv) { return pv->name(); }); } // remove affected the profile views pViews_.erase(profileViewIter, pViews_.cend()); // recreate the list of profile views { std::lock_guard lock(manualProfileMutex_); createProfileViews(getBaseView(pViews_, manualProfile_), pViewsToRecreate); } // apply active profile view profileApplicator_->apply(*pViews_.back()); } } } } void Session::queueProfileViewForExecutable(std::string const &executableName) { std::string profileName; { std::lock_guard lock(profileExeIndexMutex_); auto const profileIndexNameIter = profileExeIndex_.find(executableName); if (profileIndexNameIter != profileExeIndex_.cend()) profileName = profileIndexNameIter->second; } queueProfileView(profileName); } void Session::dequeueProfileViewForExecutable(std::string const &executableName) { std::string profileName; { std::lock_guard lock(profileExeIndexMutex_); auto const profileIndexNameIter = profileExeIndex_.find(executableName); if (profileIndexNameIter != profileExeIndex_.cend()) profileName = profileIndexNameIter->second; } dequeueProfileView(profileName); } void Session::populateProfileExeIndex() { auto profiles = profileManager_->profiles(); for (auto &profileName : profiles) { auto profile = profileManager_->profile(profileName); auto info = profile->get().info(); if (profile->get().active() && info.exe != IProfile::Info::ManualID) profileExeIndex_.emplace(info.exe, std::move(profileName)); } } void Session::watchProfiles() { for (auto const &[exe, name] : profileExeIndex_) { if (exe != IProfile::Info::GlobalID && exe != IProfile::Info::ManualID) helperMonitor_->watchApp(exe); } } void Session::createProfileViews( std::optional> baseProfileView, std::vector const &profileNames) { for (auto const &profileName : profileNames) { auto profile = profileManager_->profile(profileName); if (profile.has_value()) { auto profileView = profileViewFactory_->build(*profile, baseProfileView); pViews_.emplace_back(std::move(profileView)); } } } std::optional> Session::getBaseView(std::deque> const &pViews, std::optional const &manualProfile) const { std::optional> base; if (!pViews.empty()) { if (!manualProfile.has_value()) base = *pViews.back(); else { auto baseIt = std::next(pViews.rbegin()); if (baseIt != pViews.rend()) base = **baseIt; } } return base; } void Session::queueProfileView(std::string const &profileName) { // compute a list of profile views to create including the profile std::vector pViewsToRecreate{profileName}; std::lock_guard lock(pViewsMutex_); std::lock_guard mLock(manualProfileMutex_); auto baseView = getBaseView(pViews_, manualProfile_); // recreate active manual profile view if (manualProfile_.has_value()) { pViewsToRecreate.push_back(*manualProfile_); pViews_.pop_back(); } createProfileViews(baseView, pViewsToRecreate); // apply active profile view profileApplicator_->apply(*pViews_.back()); } void Session::dequeueProfileView(std::string const &profileName) { std::lock_guard lock(pViewsMutex_); auto profileViewIter = std::find_if( pViews_.cbegin(), pViews_.cend(), [&](auto const &pv) { return pv->name() == profileName; }); if (profileViewIter != pViews_.end()) { auto nextProfileView = std::next(profileViewIter); // compute a list with the names of profile views to recreate std::vector pViewsToRecreate; if (nextProfileView != pViews_.end()) { pViewsToRecreate.reserve(pViews_.size()); std::transform(nextProfileView, pViews_.cend(), std::back_inserter(pViewsToRecreate), [](auto const &pv) { return pv->name(); }); } // remove profile view and the outdated profile views pViews_.erase(profileViewIter, pViews_.cend()); // recreate the list of profile views { std::lock_guard lock(manualProfileMutex_); createProfileViews(getBaseView(pViews_, manualProfile_), pViewsToRecreate); } // apply active profile view profileApplicator_->apply(*pViews_.back()); } } void Session::notifyManualProfileToggled(std::string const &profileName, bool active) { std::lock_guard lock(manualProfileObserversMutex_); for (auto &o : manualProfileObservers_) o->toggled(profileName, active); } corectrl-v1.4.2/src/core/session.h000066400000000000000000000061711467225065400171140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprofile.h" #include "isession.h" #include #include #include #include #include #include #include #include class IProfileApplicator; class IProfileView; class IProfileViewFactory; class IHelperMonitor; class Session final : public ISession { public: Session(std::shared_ptr profileApplicator, std::unique_ptr &&profileManager, std::unique_ptr &&profileViewFactory, std::unique_ptr &&helperMonitor) noexcept; void addManualProfileObserver( std::shared_ptr observer) override; void removeManualProfileObserver( std::shared_ptr observer) override; void init(ISysModel const &model) override; bool toggleManualProfile(std::string const &profileName) override; IProfileManager &profileManager() const override; private: void profileAdded(std::string const &profileName); void profileRemoved(std::string const &profileName); void profileChanged(std::string const &profileName); void profileActiveChanged(std::string const &profileName, bool active); void profileSaved(std::string const &profileName); void profileInfoChanged(IProfile::Info const &oldInfo, IProfile::Info const &newInfo); void queueProfileViewForExecutable(std::string const &executableName); void dequeueProfileViewForExecutable(std::string const &executableName); void populateProfileExeIndex(); void watchProfiles(); void createProfileViews( std::optional> baseProfileView, std::vector const &profileNames); std::optional> getBaseView(std::deque> const &pViews, std::optional const &manualProfile) const; void queueProfileView(std::string const &profileName); void dequeueProfileView(std::string const &profileName); void notifyManualProfileToggled(std::string const &profileName, bool active); std::shared_ptr profileApplicator_; std::unique_ptr profileManager_; std::unique_ptr profileViewFactory_; std::unique_ptr helperMonitor_; class ProfileManagerObserver; std::shared_ptr const profileManagerObserver_; class HelperMonitorObserver; std::shared_ptr const helperMonitorObserver_; std::optional manualProfile_; std::mutex manualProfileMutex_; std::deque> pViews_; std::mutex pViewsMutex_; using executableName = std::string; using profileName = std::string; std::unordered_map profileExeIndex_; std::mutex profileExeIndexMutex_; std::vector> manualProfileObservers_; std::mutex manualProfileObserversMutex_; }; corectrl-v1.4.2/src/core/sysexplorer.cpp000066400000000000000000000031431467225065400203570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "sysexplorer.h" #include "common/fileutils.h" #include "common/stringutils.h" #include #include #include SysExplorer::SysExplorer(std::vector gpuVendors) noexcept : gpuVendors_(std::move(gpuVendors)) { } std::vector SysExplorer::renderers() { namespace fs = std::filesystem; std::vector devices; fs::path renderBasePath{"/sys/class/drm"}; for (auto const &drmEntry : fs::directory_iterator(renderBasePath)) { auto const &renderDPath = drmEntry.path(); // use the entries starting with "renderD" auto const renderDName = renderDPath.filename().string(); if (renderDName.find("renderD") == 0) { auto const sysPath = renderDPath / "device"; if (Utils::File::isDirectoryPathValid(sysPath)) { // skip unsupported devices if (!checkGPUVendor(sysPath)) continue; devices.emplace_back(std::move(renderDName)); } } } return devices; } bool SysExplorer::checkGPUVendor(std::filesystem::path sysPath) const { auto const vendorPath = sysPath / "vendor"; auto lines = Utils::File::readFileLines(vendorPath); if (!lines.empty()) { int vendor; if (Utils::String::toNumber(vendor, lines.front(), 16)) { if (std::find(gpuVendors_.cbegin(), gpuVendors_.cend(), Vendor{vendor}) != gpuVendors_.cend()) return true; } else SPDLOG_DEBUG("Cannot parse vendor id from file {}.", vendorPath.c_str()); } return false; } corectrl-v1.4.2/src/core/sysexplorer.h000066400000000000000000000007421467225065400200260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "info/vendor.h" #include "isysexplorer.h" #include #include class SysExplorer final : public ISysExplorer { public: SysExplorer(std::vector gpuVendors) noexcept; std::vector renderers() override; private: bool checkGPUVendor(std::filesystem::path sysPath) const; std::vector gpuVendors_; }; corectrl-v1.4.2/src/core/sysfsdatasource.h000066400000000000000000000062031467225065400206470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "idatasource.h" #include #include #include #include #include #include #include #include template concept SysFSDataType = std::is_same_v || std::is_same_v>; /// SysFS data source that allows the transformation of the source data to other /// types. /// /// To perform a transformation of the whole contents of the file, use the type /// std::vector as the Input template type parameter. Otherwise, only /// the first line of the file will be passed to the transformation function. template class SysFSDataSource : public IDataSource { public: /// Creates a new SysFSDataSource instance using a file as data source and, /// optionally, transforming the sysfs data source data to the Output type data /// using the custom transform function. /// /// @param path path to the sysfs file. /// /// @param transform function to map the sysfs data source data to the /// specified Output type. This function is only needed when the Output type is not /// a SysFSDataType, requiring a transformation between the types. SysFSDataSource( std::filesystem::path const &path, std::function &&transform = [](Input const &, Output &) {}) noexcept : path_(path.string()) , transform_(std::move(transform)) { file_.open(path); if (!file_.is_open()) SPDLOG_DEBUG("Cannot open {}", path_.c_str()); } std::string source() const override { return path_; } bool read(Output &data) override { if (file_.is_open()) { if constexpr (std::is_same_v) { readFirstLine(data); } else if constexpr (std::is_same_v>) { readAll(data); } else if constexpr (std::is_same_v>) { readAll(fileData_); transform_(fileData_, data); } else if constexpr (std::is_same_v) { readFirstLine(lineData_); transform_(lineData_, data); } return true; } return false; } private: /// Reads the first line of the file into data. void readFirstLine(std::string &data) { file_.clear(); file_.seekg(0); std::getline(file_, data); } /// Reads the file lines into data, reusing existing data elements as /// the new data holders when possible. void readAll(std::vector &data) { file_.clear(); file_.seekg(0); size_t index = 0; while (std::getline(file_, lineData_)) { if (data.size() == index) data.emplace_back(std::string()); std::swap(lineData_, data[index++]); } } std::string const path_; std::function const transform_; std::ifstream file_; std::string lineData_; std::vector fileData_; }; corectrl-v1.4.2/src/core/sysmodel.cpp000066400000000000000000000044751467225065400176300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "sysmodel.h" #include "core/exportable.h" #include "core/importable.h" #include "core/isyscomponent.h" #include "info/iswinfo.h" SysModel::SysModel(std::shared_ptr swInfo, std::vector> &&components) noexcept : id_{ISysModel::ItemID} , swInfo_(std::move(swInfo)) , components_(std::move(components)) { } void SysModel::init() { for (auto &component : components_) component->init(); } void SysModel::preInit(ICommandQueue &ctlCmds) { for (auto &component : components_) component->preInit(ctlCmds); } void SysModel::postInit(ICommandQueue &ctlCmds) { for (auto &component : components_) component->postInit(ctlCmds); } void SysModel::sync(ICommandQueue &ctlCmds) { for (auto &component : components_) component->sync(ctlCmds); } void SysModel::updateSensors( std::unordered_map> const &ignored) { for (auto &component : components_) component->updateSensors(ignored); } std::vector>>> SysModel::info() const { std::vector>>> info; info.emplace_back(softwareInfo()); for (auto const &component : components_) info.emplace_back(component->componentInfo()); return info; } std::string const &SysModel::ID() const { return id_; } void SysModel::importWith(Importable::Importer &i) { auto importer = i.provideImporter(*this); if (importer.has_value()) { for (auto &component : components_) component->importWith(*importer); } } void SysModel::exportWith(Exportable::Exporter &e) const { auto exporter = e.provideExporter(*this); if (exporter.has_value()) { for (auto const &component : components_) component->exportWith(*exporter); } } std::pair>> SysModel::softwareInfo() const { std::pair>> info; info.first = "Software"; auto swInfoKeys = swInfo_->keys(); for (auto &swInfoKey : swInfoKeys) info.second.emplace_back(swInfoKey, swInfo_->info(swInfoKey)); return info; } corectrl-v1.4.2/src/core/sysmodel.h000066400000000000000000000023271467225065400172670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "isysmodel.h" #include #include #include #include class ISWInfo; class ISysComponent; class SysModel final : public ISysModel { public: SysModel(std::shared_ptr swInfo, std::vector> &&components) noexcept; void init() override; void preInit(ICommandQueue &ctlCmds) override; void postInit(ICommandQueue &ctlCmds) override; void sync(ICommandQueue &ctlCmds) override; void updateSensors( std::unordered_map> const &ignored) override; std::vector>>> info() const override; std::string const &ID() const override; void importWith(Importable::Importer &i) override; void exportWith(Exportable::Exporter &e) const override; private: std::pair>> softwareInfo() const; std::string const id_; std::shared_ptr const swInfo_; std::vector> const components_; }; corectrl-v1.4.2/src/core/sysmodelfactory.cpp000066400000000000000000000214611467225065400212120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "sysmodelfactory.h" #include "common/fileutils.h" #include "common/stringutils.h" #include "components/controls/icontrol.h" #include "components/controls/icpucontrolprovider.h" #include "components/controls/igpucontrolprovider.h" #include "components/cpu.h" #include "components/cpuutils.h" #include "components/gpu.h" #include "components/sensors/icpusensorprovider.h" #include "components/sensors/igpusensorprovider.h" #include "components/sensors/isensor.h" #include "info/cpuinfo.h" #include "info/gpuinfo.h" #include "info/ihwidtranslator.h" #include "info/iswinfo.h" #include "isyscomponent.h" #include "isysexplorer.h" #include "sysmodel.h" #include #include #include #include #include #include #include SysModelFactory::SysModelFactory( std::unique_ptr &&swInfo, std::unique_ptr &&sysExplorer, std::unique_ptr &&hwIDTranslator, std::unique_ptr &&cpuControlProvider, std::unique_ptr &&cpuSensorProvider, std::unique_ptr &&gpuControlProvider, std::unique_ptr &&gpuSensorProvider, ICPUInfo::IProviderRegistry const &cpuInfoProviderRegistry, IGPUInfo::IProviderRegistry const &gpuInfoProviderRegistry) noexcept : swInfo_(std::move(swInfo)) , sysExplorer_(std::move(sysExplorer)) , hwidTranslator_(std::move(hwIDTranslator)) , cpuControlProvider_(std::move(cpuControlProvider)) , cpuSensorProvider_(std::move(cpuSensorProvider)) , gpuControlProvider_(std::move(gpuControlProvider)) , gpuSensorProvider_(std::move(gpuSensorProvider)) , cpuInfoProviderRegistry_(cpuInfoProviderRegistry) , gpuInfoProviderRegistry_(gpuInfoProviderRegistry) { } std::unique_ptr SysModelFactory::build() const { std::vector> components; auto gpuInfo = createGPUInfo(); for (auto &info : gpuInfo) components.emplace_back(createGPU(std::move(info), *swInfo_)); auto cpuInfo = createCPUInfo(); for (auto &info : cpuInfo) components.emplace_back(createCPU(std::move(info), *swInfo_)); return std::make_unique(swInfo_, std::move(components)); } std::vector> SysModelFactory::createCPUInfo() const { auto cpuInfo = parseCPUInfo(); for (auto &info : cpuInfo) info->initialize(cpuInfoProviderRegistry_.cpuInfoProviders()); return cpuInfo; } std::unique_ptr SysModelFactory::createCPU(std::unique_ptr &&cpuInfo, ISWInfo const &swInfo) const { // create CPU controls std::vector> controls; auto &cpuControlProviders = cpuControlProvider_->cpuControlProviders(); for (auto const &provider : cpuControlProviders) { auto newControls = provider->provideCPUControls(*cpuInfo, swInfo); controls.insert(controls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } // create CPU sensors std::vector> sensors; auto &cpuSensorProviders = cpuSensorProvider_->cpuSensorProviders(); for (auto const &provider : cpuSensorProviders) { auto newSensors = provider->provideCPUSensors(*cpuInfo, swInfo); sensors.insert(sensors.end(), std::make_move_iterator(newSensors.begin()), std::make_move_iterator(newSensors.end())); } return std::make_unique(std::move(cpuInfo), std::move(controls), std::move(sensors)); } std::vector> SysModelFactory::createGPUInfo() const { namespace fs = std::filesystem; std::vector> gpuInfo; fs::path sysBasePath{"/sys/class/drm"}; auto deviceNames = sysExplorer_->renderers(); for (auto const &deviceName : deviceNames) { auto sysPath = sysBasePath / deviceName / "device"; auto devPath = fs::path("/dev/dri").append(deviceName); auto vendor = parseVendor(sysBasePath / deviceName / "device/vendor"); int const gpuIndex = computeGPUIndex(deviceName); auto info = std::make_unique(vendor, gpuIndex, GPUInfo::Path(sysPath, devPath)); info->initialize(gpuInfoProviderRegistry_.gpuInfoProviders(), *hwidTranslator_); gpuInfo.emplace_back(std::move(info)); } return gpuInfo; } std::unique_ptr SysModelFactory::createGPU(std::unique_ptr &&gpuInfo, ISWInfo const &swInfo) const { // create GPU controls std::vector> controls; auto &gpuControlProviders = gpuControlProvider_->gpuControlProviders(); for (auto const &provider : gpuControlProviders) { auto newControls = provider->provideGPUControls(*gpuInfo, swInfo); controls.insert(controls.end(), std::make_move_iterator(newControls.begin()), std::make_move_iterator(newControls.end())); } // create GPU sensors std::vector> sensors; auto &gpuSensorProviders = gpuSensorProvider_->gpuSensorProviders(); for (auto const &provider : gpuSensorProviders) { auto newSensors = provider->provideGPUSensors(*gpuInfo, swInfo); sensors.insert(sensors.end(), std::make_move_iterator(newSensors.begin()), std::make_move_iterator(newSensors.end())); } return std::make_unique(std::move(gpuInfo), std::move(controls), std::move(sensors)); } std::vector> SysModelFactory::parseCPUInfo() const { static constexpr std::string_view cpuIdStr{"processor"}; std::filesystem::path const basePath{"/sys/devices/system/cpu"}; std::vector> cpuInfo; int value; std::optional cpuId; auto cpuInfoLines = Utils::File::readFileLines("/proc/cpuinfo"); for (auto const &line : cpuInfoLines) { if (line.empty()) { // push collected info std::optional physicalId; std::optional coreId; auto physicalIdStr = Utils::CPU::parseProcCpuInfo(cpuInfoLines, *cpuId, "physical id"); if (physicalIdStr.has_value() && Utils::String::toNumber(value, *physicalIdStr)) physicalId = value; auto coreIdStr = Utils::CPU::parseProcCpuInfo(cpuInfoLines, *cpuId, "core id"); if (coreIdStr.has_value() && Utils::String::toNumber(value, *coreIdStr)) coreId = value; if (cpuId.has_value() && physicalId.has_value() && coreId.has_value()) { std::string cpuDir{"cpu"}; cpuDir.append(std::to_string(*cpuId)); auto executionUnitPath = basePath / cpuDir; auto infoIt = std::find_if(cpuInfo.cbegin(), cpuInfo.cend(), [=](auto const &info) { return info->physicalId() == *physicalId; }); if (infoIt != cpuInfo.cend()) static_cast(infoIt->get()) ->addExecutionUnit( ICPUInfo::ExecutionUnit(*cpuId, *coreId, executionUnitPath)); else { std::vector units{ ICPUInfo::ExecutionUnit(*cpuId, *coreId, executionUnitPath)}; cpuInfo.emplace_back( std::make_unique(*physicalId, std::move(units))); } physicalId = cpuId = coreId = std::nullopt; } else { SPDLOG_DEBUG("Cannot parse some data from /proc/cpuinfo"); return {}; } } auto cpuIdIt = line.find(cpuIdStr); if (cpuIdIt != std::string::npos) { auto indexPos = line.find_first_not_of("\t: ", cpuIdStr.size()); if (indexPos != std::string::npos && Utils::String::toNumber(value, line.substr(indexPos))) { cpuId = value; continue; } } } return cpuInfo; } int SysModelFactory::computeGPUIndex(std::string const &deviceRenderDName) const { auto const indexStr = Utils::String::cleanPrefix(deviceRenderDName, "renderD"); int index = -1; if (Utils::String::toNumber(index, indexStr)) index -= 128; else SPDLOG_DEBUG("Cannot compute GPU index for device {}.", deviceRenderDName); return index; } Vendor SysModelFactory::parseVendor(std::filesystem::path const &vendorPath) const { Vendor vendor{-1}; auto const lines = Utils::File::readFileLines(vendorPath); if (!lines.empty()) { int dataValue; if (Utils::String::toNumber(dataValue, lines.front(), 16)) vendor = Vendor{dataValue}; else SPDLOG_DEBUG("Cannot parse vendor id from file {}.", vendorPath.c_str()); } return vendor; } corectrl-v1.4.2/src/core/sysmodelfactory.h000066400000000000000000000044221467225065400206550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "components/controls/control.h" #include "info/icpuinfo.h" #include "info/igpuinfo.h" #include "info/vendor.h" #include #include #include #include class ICPU; class IGPU; class ISWInfo; class ISysModel; class ISysExplorer; class IHWIDTranslator; class ICPUControlProvider; class ICPUSensorProvider; class IGPUControlProvider; class IGPUSensorProvider; class SysModelFactory final { public: SysModelFactory( std::unique_ptr &&swInfo, std::unique_ptr &&sysExplorer, std::unique_ptr &&hwidTranslator, std::unique_ptr &&cpuControlProvider, std::unique_ptr &&cpuSensorProvider, std::unique_ptr &&gpuControlProvider, std::unique_ptr &&gpuSensorProvider, ICPUInfo::IProviderRegistry const &cpuInfoProviderRegistry, IGPUInfo::IProviderRegistry const &gpuInfoProviderRegistry) noexcept; std::unique_ptr build() const; private: std::vector> createCPUInfo() const; std::unique_ptr createCPU(std::unique_ptr &&cpuInfo, ISWInfo const &swInfo) const; std::vector> createGPUInfo() const; std::unique_ptr createGPU(std::unique_ptr &&gpuInfo, ISWInfo const &swInfo) const; std::vector> parseCPUInfo() const; int computeGPUIndex(std::string const &deviceRenderDName) const; Vendor parseVendor(std::filesystem::path const &vendorPath) const; std::shared_ptr const swInfo_; std::unique_ptr const sysExplorer_; std::unique_ptr const hwidTranslator_; std::unique_ptr const cpuControlProvider_; std::unique_ptr const cpuSensorProvider_; std::unique_ptr const gpuControlProvider_; std::unique_ptr const gpuSensorProvider_; ICPUInfo::IProviderRegistry const &cpuInfoProviderRegistry_; IGPUInfo::IProviderRegistry const &gpuInfoProviderRegistry_; }; corectrl-v1.4.2/src/core/sysmodelqmlitem.cpp000066400000000000000000000070261467225065400212140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "sysmodelqmlitem.h" #include "components/igpu.h" #include "components/igpuprofilepart.h" #include "info/igpuinfo.h" #include "iprofilepart.h" #include "isyscomponent.h" #include "isyscomponentprofilepart.h" #include "isysmodel.h" #include "item.h" #include "qmlcomponentregistry.h" #include #include #include #include #include class SysModelQMLItem::Initializer final : public QMLItem::Initializer , public ISysModel::Exporter { public: Initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine, SysModelQMLItem &qmlItem) noexcept : QMLItem::Initializer(qmlComponentFactory, qmlEngine) , outer_(qmlItem) { } std::optional> provideExporter(Item const &i) override; private: SysModelQMLItem &outer_; }; std::optional> SysModelQMLItem::Initializer::provideExporter(Item const &i) { auto &itemID = i.ID(); if (itemID == ISysModel::ItemID) return *this; else { auto [componentInitializer, qmlItemPtr] = initializer(itemID, &outer_); if (componentInitializer.has_value()) { auto &key = dynamic_cast(i).key(); outer_.components_.emplace(key, qmlItemPtr); return componentInitializer; } } return {}; } void SysModelQMLItem::activate(bool) { } std::optional> SysModelQMLItem::provideImporter(Item const &i) { if (i.ID() == IProfile::ItemID) return *this; auto &key = dynamic_cast(i).key(); auto const iter = components_.find(key); if (iter != components_.cend()) return dynamic_cast(*iter->second); return {}; } std::optional> SysModelQMLItem::provideExporter(Item const &i) { if (i.ID() == IProfile::ItemID) return *this; auto &key = dynamic_cast(i).key(); auto const iter = components_.find(key); if (iter != components_.cend()) return dynamic_cast(*iter->second); return {}; } bool SysModelQMLItem::provideActive() const { return profileActive_; } IProfile::Info const &SysModelQMLItem::provideInfo() const { return profileInfo_; } void SysModelQMLItem::takeActive(bool active) { profileActive_ = active; } void SysModelQMLItem::takeInfo(IProfile::Info const &info) { profileInfo_ = info; } std::unique_ptr SysModelQMLItem::initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) { return std::make_unique(qmlComponentFactory, qmlEngine, *this); } bool SysModelQMLItem::register_() { QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, ISysModel::ItemID.data()); }); QMLComponentRegistry::addQMLItemProvider( ISysModel::ItemID, [](QQmlApplicationEngine &engine) { QQmlComponent component(&engine, QStringLiteral("qrc:/qml/SysModelForm.qml")); return qobject_cast(component.create()); }); return true; } bool const SysModelQMLItem::registered_ = SysModelQMLItem::register_(); corectrl-v1.4.2/src/core/sysmodelqmlitem.h000066400000000000000000000024761467225065400206650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "exportable.h" #include "iprofile.h" #include "isysmodelui.h" #include "qmlitem.h" #include #include #include #include #include class IQMLComponentFactory; class QQmlApplicationEngine; class SysModelQMLItem : public QMLItem , public ISysModelUI { Q_OBJECT public: static constexpr std::string_view ParentObjectName{"PROFILE_SYS_MODEL"}; void activate(bool active) override; std::optional> provideImporter(Item const &i) override; std::optional> provideExporter(Item const &i) override; bool provideActive() const override; IProfile::Info const &provideInfo() const override; void takeActive(bool active) override; void takeInfo(IProfile::Info const &info) override; std::unique_ptr initializer(IQMLComponentFactory const &qmlComponentFactory, QQmlApplicationEngine &qmlEngine) override; private: class Initializer; std::unordered_map components_; IProfile::Info profileInfo_; bool profileActive_; static bool register_(); static bool const registered_; }; corectrl-v1.4.2/src/core/sysmodelsyncer.cpp000066400000000000000000000052131467225065400210430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "sysmodelsyncer.h" #include "iprofileview.h" #include #include #include #include SysModelSyncer::SysModelSyncer(std::unique_ptr &&sysModel, std::unique_ptr &&helperSysCtl) noexcept : sysModel_(std::move(sysModel)) , helperSysCtl_(std::move(helperSysCtl)) { } ISysModel &SysModelSyncer::sysModel() const { return *sysModel_; } void SysModelSyncer::settingChanged(QString const &key, QVariant const &value) { if (key == "Workarounds/ignoredSensors") { std::lock_guard lock(sensorsMutex_); ignoredSensors_.clear(); auto const sensorList = value.toStringList(); for (auto const &sensor : sensorList) { auto componentSensorIdList = sensor.split('/'); if (componentSensorIdList.size() == 2) { auto component = componentSensorIdList.at(0).toStdString(); auto sensorId = componentSensorIdList.at(1).toStdString(); if (ignoredSensors_.count(component) == 0) ignoredSensors_[component] = {}; ignoredSensors_[component].emplace(sensorId); } } } } void SysModelSyncer::init() { helperSysCtl_->init(); sysModel_->preInit(cmds_); helperSysCtl_->apply(cmds_); // NOTE give some time to the helper so it applies the pre-init commands // before the model initialization. std::this_thread::sleep_for(std::chrono::milliseconds(500)); sysModel_->init(); sysModel_->postInit(cmds_); helperSysCtl_->apply(cmds_); // start the sensor updating thread updateThread_ = std::make_unique([&]() { while (!stopSignal_.load(std::memory_order_relaxed)) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); updateSensors(); } }); // start the model syncing thread syncThread_ = std::make_unique([&]() { while (!stopSignal_.load(std::memory_order_relaxed)) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); syncModel(); } }); } void SysModelSyncer::stop() { stopSignal_.store(true, std::memory_order_relaxed); updateThread_->join(); syncThread_->join(); } void SysModelSyncer::apply(IProfileView &profileView) { std::lock_guard lock(syncMutex_); sysModel_->importWith(profileView); } void SysModelSyncer::updateSensors() { std::lock_guard lock(sensorsMutex_); sysModel_->updateSensors(ignoredSensors_); } void SysModelSyncer::syncModel() { std::lock_guard lock(syncMutex_); sysModel_->sync(cmds_); helperSysCtl_->apply(cmds_); } corectrl-v1.4.2/src/core/sysmodelsyncer.h000066400000000000000000000025161467225065400205130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "commandqueue.h" #include "helper/ihelpersysctl.h" #include "iprofileapplicator.h" #include "isysmodel.h" #include "isysmodelsyncer.h" #include #include #include #include #include #include #include #include class IProfileView; class SysModelSyncer final : public QObject , public ISysModelSyncer , public IProfileApplicator { Q_OBJECT public: SysModelSyncer(std::unique_ptr &&sysModel, std::unique_ptr &&helperSysCtl) noexcept; ISysModel &sysModel() const override; void settingChanged(QString const &key, QVariant const &value) override; void init() override; void stop() override; void apply(IProfileView &profileView) override; private: void updateSensors(); void syncModel(); std::unique_ptr const sysModel_; std::unique_ptr const helperSysCtl_; std::mutex syncMutex_; CommandQueue cmds_; std::mutex sensorsMutex_; std::unordered_map> ignoredSensors_; std::unique_ptr updateThread_; std::unique_ptr syncThread_; std::atomic stopSignal_{false}; }; corectrl-v1.4.2/src/core/systeminfoui.cpp000066400000000000000000000106031467225065400205150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "systeminfoui.h" #include "app/app.h" #include "isysmodel.h" #include "qmlcomponentregistry.h" #include #include #include #include #include #include #include char const *const SystemInfoUI::trStrings[] = { // XXX add info keys here QT_TRANSLATE_NOOP("SystemInfoUI", "kernelv"), QT_TRANSLATE_NOOP("SystemInfoUI", "mesav"), QT_TRANSLATE_NOOP("SystemInfoUI", "vkapiv"), QT_TRANSLATE_NOOP("SystemInfoUI", "glcorev"), QT_TRANSLATE_NOOP("SystemInfoUI", "glcompv"), QT_TRANSLATE_NOOP("SystemInfoUI", "vendorid"), QT_TRANSLATE_NOOP("SystemInfoUI", "deviceid"), QT_TRANSLATE_NOOP("SystemInfoUI", "svendorid"), QT_TRANSLATE_NOOP("SystemInfoUI", "sdeviceid"), QT_TRANSLATE_NOOP("SystemInfoUI", "vendor"), QT_TRANSLATE_NOOP("SystemInfoUI", "device"), QT_TRANSLATE_NOOP("SystemInfoUI", "sdevice"), QT_TRANSLATE_NOOP("SystemInfoUI", "pcislot"), QT_TRANSLATE_NOOP("SystemInfoUI", "driver"), QT_TRANSLATE_NOOP("SystemInfoUI", "revision"), QT_TRANSLATE_NOOP("SystemInfoUI", "memory"), QT_TRANSLATE_NOOP("SystemInfoUI", "gputype"), QT_TRANSLATE_NOOP("SystemInfoUI", "biosv"), QT_TRANSLATE_NOOP("SystemInfoUI", "cpufamily"), QT_TRANSLATE_NOOP("SystemInfoUI", "model"), QT_TRANSLATE_NOOP("SystemInfoUI", "modname"), QT_TRANSLATE_NOOP("SystemInfoUI", "stepping"), QT_TRANSLATE_NOOP("SystemInfoUI", "ucodev"), QT_TRANSLATE_NOOP("SystemInfoUI", "l3cache"), QT_TRANSLATE_NOOP("SystemInfoUI", "exeunits"), QT_TRANSLATE_NOOP("SystemInfoUI", "cores"), QT_TRANSLATE_NOOP("SystemInfoUI", "flags"), QT_TRANSLATE_NOOP("SystemInfoUI", "bugs"), QT_TRANSLATE_NOOP("SystemInfoUI", "bogomips"), QT_TRANSLATE_NOOP("SystemInfoUI", "arch"), QT_TRANSLATE_NOOP("SystemInfoUI", "opmode"), QT_TRANSLATE_NOOP("SystemInfoUI", "byteorder"), QT_TRANSLATE_NOOP("SystemInfoUI", "virt"), QT_TRANSLATE_NOOP("SystemInfoUI", "l1dcache"), QT_TRANSLATE_NOOP("SystemInfoUI", "l1icache"), QT_TRANSLATE_NOOP("SystemInfoUI", "l2cache"), QT_TRANSLATE_NOOP("SystemInfoUI", "uniqueid"), }; SystemInfoUI::SystemInfoUI(QObject *parent) noexcept : QObject(parent) { } void SystemInfoUI::init(ISysModel const *sysModel) { sysModel_ = sysModel; initInfo(); for (auto const &sysModelInfo : info_) { QVariantList list; for (auto const &sysComponentInfo : sysModelInfo.second) { list.append(sysComponentInfo.first); list.append(sysComponentInfo.second); } emit addSystemInfo(sysModelInfo.first, list); } } void SystemInfoUI::copyToClipboard() const { auto clipboard = QApplication::clipboard(); if (clipboard != nullptr) { QString text(App::Name.data()); text += " v"; text += App::VersionStr.data(); text += "\n"; for (auto const &sysModelInfo : info_) { auto sectionTitle = sysModelInfo.first; sectionTitle.replace("\n", " "); text += "\n==== " + sectionTitle + " ====\n"; for (auto const &sysComponentInfo : sysModelInfo.second) text += sysComponentInfo.first + ": " + sysComponentInfo.second + "\n"; } clipboard->setText(text); } } void SystemInfoUI::initInfo() { auto rawInfo = sysModel_->info(); for (auto const &sysModelInfo : rawInfo) { std::vector> processedModelInfo; // translate keys std::transform(sysModelInfo.second.cbegin(), sysModelInfo.second.cend(), std::back_inserter(processedModelInfo), [](auto const &pair) { return std::pair(tr(pair.first.c_str()), QString::fromStdString(pair.second)); }); // sort information elements using the translated keys std::sort(processedModelInfo.begin(), processedModelInfo.end(), [](auto const &left, auto const &right) { return left.first < right.first; }); info_.emplace_back(QString::fromStdString(sysModelInfo.first), std::move(processedModelInfo)); } } bool const SystemInfoUI::registered_ = QMLComponentRegistry::addQMLTypeRegisterer([]() { qmlRegisterType("CoreCtrl.UIComponents", 1, 0, SystemInfoUI::QMLComponentID.data()); }); corectrl-v1.4.2/src/core/systeminfoui.h000066400000000000000000000015121467225065400201610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include #include class ISysModel; class SystemInfoUI : public QObject { Q_OBJECT public: static constexpr std::string_view QMLComponentID{"SYSTEM_INFO"}; explicit SystemInfoUI(QObject *parent = nullptr) noexcept; void init(ISysModel const *sysModel); Q_INVOKABLE void copyToClipboard() const; signals: void addSystemInfo(QString const &componentName, QVariantList const &info); private: void initInfo(); ISysModel const *sysModel_; std::vector>>> info_; static bool const registered_; static char const *const trStrings[]; }; corectrl-v1.4.2/src/core/uifactory.cpp000066400000000000000000000044431467225065400177710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "uifactory.h" #include "iqmlcomponentfactory.h" #include "isession.h" #include "isysmodel.h" #include "isysmodelui.h" #include "profilemanagerui.h" #include "qmlitem.h" #include "sysmodelqmlitem.h" #include "systeminfoui.h" #include #include #include #include #include #include #include #include #include #include UIFactory::UIFactory( std::unique_ptr &&qmlComponentfactory) noexcept : qmlComponentFactory_(std::move(qmlComponentfactory)) { } void UIFactory::build(QQmlApplicationEngine &qmlEngine, ISysModel const &sysModel, ISession &session) const { qmlComponentFactory_->registerQMLTypes(); // Enable native font rendering. QQuickWindow::setTextRenderType(QQuickWindow::NativeTextRendering); qmlEngine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); if (qmlEngine.rootObjects().isEmpty()) throw std::runtime_error("QML engine failed to load main interface!"); auto item = createSysModelQMLItem(qmlEngine); if (item != nullptr) { auto initializer = item->initializer(*qmlComponentFactory_, qmlEngine); sysModel.exportWith(*initializer); auto profileManagerUI = static_cast( qmlEngine.rootObjects().front()->findChild( ProfileManagerUI::QMLComponentID.data())); profileManagerUI->init(&session, dynamic_cast(item)); auto systemInfoUI = static_cast( qmlEngine.rootObjects().front()->findChild( SystemInfoUI::QMLComponentID.data())); systemInfoUI->init(&sysModel); } } QMLItem *UIFactory::createSysModelQMLItem(QQmlApplicationEngine &qmlEngine) const { QString parentObjectName(SysModelQMLItem::ParentObjectName.data()); parentObjectName.append(QMLItem::ParentObjectSuffix.data()); auto itemParent = qmlEngine.rootObjects().front()->findChild( parentObjectName); if (itemParent != nullptr) return qmlComponentFactory_->createQMLItem(std::string(ISysModel::ItemID), itemParent, qmlEngine); return nullptr; } corectrl-v1.4.2/src/core/uifactory.h000066400000000000000000000012031467225065400174250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iuifactory.h" #include class QMLItem; class IQMLComponentFactory; class QQmlApplicationEngine; class UIFactory final : public IUIFactory { public: UIFactory(std::unique_ptr &&qmlComponentfactory) noexcept; void build(QQmlApplicationEngine &qmlEngine, ISysModel const &sysModel, ISession &session) const override; private: QMLItem *createSysModelQMLItem(QQmlApplicationEngine &qmlEngine) const; std::unique_ptr qmlComponentFactory_; }; corectrl-v1.4.2/src/helper/000077500000000000000000000000001467225065400156025ustar00rootroot00000000000000corectrl-v1.4.2/src/helper/CMakeLists.txt000066400000000000000000000071001467225065400203400ustar00rootroot00000000000000find_package(PkgConfig REQUIRED) find_package(Botan QUIET) if(NOT Botan_FOUND) message(FATAL_ERROR "Botan library not found") endif() set(DBUS_DATADIR_PREFIX_DIR ${CMAKE_INSTALL_FULL_DATADIR}) option(INSTALL_DBUS_FILES_IN_PREFIX "Use installation prefix for D-Bus files" OFF) # Find dbus if(NOT INSTALL_DBUS_FILES_IN_PREFIX) pkg_check_modules(DBUS REQUIRED dbus-1) execute_process( COMMAND pkg-config --variable=datadir dbus-1 RESULT_VARIABLE DBUS_DATADIR_PREFIX_DIR_RESULT OUTPUT_VARIABLE DBUS_DATADIR_PREFIX_DIR OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT DBUS_DATADIR_PREFIX_DIR_RESULT EQUAL "0") message(FATAL_ERROR "Failed to retrieve D-Bus `datadir` variable using pkg-config") endif() endif() message("D-Bus files will be installed into ${DBUS_DATADIR_PREFIX_DIR}/dbus-1") # Find polkit pkg_check_modules(POLKIT REQUIRED polkit-gobject-1) execute_process( COMMAND pkg-config --variable=policydir polkit-gobject-1 RESULT_VARIABLE POLKIT_POLICY_INSTALL_DIR_RESULT OUTPUT_VARIABLE POLKIT_POLICY_INSTALL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT POLKIT_POLICY_INSTALL_DIR_RESULT EQUAL "0") message(FATAL_ERROR "Failed to retrieve Polkit `policydir` variable using pkg-config") endif() list(APPEND HELPER_COMPILE_DEFINITIONS SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE ) list(APPEND PROCESS_MONITOR_SRC pmon/processmonitor.cpp pmon/procpidsolver.cpp pmon/nlprocexecsocket.cpp pmon/nlprocexecmonitor.cpp pmon/processregistry.cpp pmon/appregistry.cpp pmon/msgdispatcher.cpp pmon/processeventconnector.c ) list(APPEND SYSTEM_CONTROL_SRC sysctl/sysfswriter.cpp sysctl/msgreceiver.cpp ) set(CMAKE_AUTOMOC ON) add_executable(corectrl_helperkiller helperkiller.cpp polkit.cpp ) set(CMAKE_AUTOMOC OFF) target_include_directories(corectrl_helperkiller PRIVATE ${POLKIT_INCLUDE_DIRS} ) target_compile_definitions(corectrl_helperkiller PRIVATE ${HELPER_COMPILE_DEFINITIONS}) target_link_libraries(corectrl_helperkiller PRIVATE Qt5::Core Qt5::DBus spdlog::spdlog ${POLKIT_LIBRARIES} ${ATOMIC_LIB} ) configure_file(org.corectrl.helperkiller.service.in org.corectrl.helperkiller.service) install(TARGETS corectrl_helperkiller DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}/corectrl") install(FILES org.corectrl.helperkiller.conf DESTINATION "${DBUS_DATADIR_PREFIX_DIR}/dbus-1/system.d") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.corectrl.helperkiller.service" DESTINATION "${DBUS_DATADIR_PREFIX_DIR}/dbus-1/system-services") install(FILES org.corectrl.helperkiller.policy DESTINATION "${POLKIT_POLICY_INSTALL_DIR}") set(CMAKE_AUTOMOC ON) add_executable(corectrl_helper helper.cpp polkit.cpp ${COMMON_SRC} ${CRYPTO_SRC} ${PROCESS_MONITOR_SRC} ${SYSTEM_CONTROL_SRC} ) set(CMAKE_AUTOMOC OFF) target_include_directories(corectrl_helper PRIVATE ${Botan_INCLUDE_DIRS} ${POLKIT_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src ) target_compile_definitions(corectrl_helper PRIVATE ${HELPER_COMPILE_DEFINITIONS}) target_link_libraries(corectrl_helper PRIVATE Qt5::Core Qt5::DBus stdc++fs pthread spdlog::spdlog ${Botan_LIBRARIES} ${POLKIT_LIBRARIES} ${ATOMIC_LIB} ) configure_file(org.corectrl.helper.service.in org.corectrl.helper.service) install(TARGETS corectrl_helper DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}/corectrl") install(FILES org.corectrl.helper.conf DESTINATION "${DBUS_DATADIR_PREFIX_DIR}/dbus-1/system.d") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/org.corectrl.helper.service" DESTINATION "${DBUS_DATADIR_PREFIX_DIR}/dbus-1/system-services") install(FILES org.corectrl.helper.policy DESTINATION "${POLKIT_POLICY_INSTALL_DIR}") corectrl-v1.4.2/src/helper/helper.cpp000066400000000000000000000120311467225065400175620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "helper.h" #include "common/cryptolayer.h" #include "common/logger.h" #include "helperids.h" #include "pmon/appregistry.h" #include "pmon/msgdispatcher.h" #include "pmon/nlprocexecmonitor.h" #include "pmon/nlprocexecsocket.h" #include "pmon/procpidsolver.h" #include "polkit.h" #include "sysctl/msgreceiver.h" #include "sysctl/sysfswriter.h" #include #include #include #include #include #include #include Helper::Helper(QObject *parent) noexcept : QDBusAbstractAdaptor(parent) { } Helper::~Helper() = default; QDBusVariant Helper::start(QByteArray const &appPublicKey, int autoExitTimeout, QDBusMessage const &message) { if (!started()) { setupLogger(std::filesystem::temp_directory_path() / LOG_HELPER_FILE_NAME); SPDLOG_DEBUG("----- Helper started -----"); if (!(isAuthorized(message) && initCrypto(appPublicKey) && initProcessMonitor() && initMsgReceiver())) { exitHelper(); return QDBusVariant(false); } autoExitTimer_.setInterval(autoExitTimeout); autoExitTimer_.setSingleShot(true); connect(&autoExitTimer_, &QTimer::timeout, this, &Helper::autoExitTimeout); autoExitTimer_.start(); } return QDBusVariant(cryptoLayer_->publicKey()); } bool Helper::started() const { return autoExitTimer_.isActive(); } void Helper::exit(QByteArray const &signature) { if (cryptoLayer_->verify({"exit"}, signature)) { autoExitTimer_.stop(); exitHelper(); } else SPDLOG_DEBUG("Failed to verify 'exit' call from D-Bus"); } void Helper::exitHelper() { endProcessMonitor(); QTimer::singleShot(0, QCoreApplication::instance(), &QCoreApplication::quit); } void Helper::autoExitTimeout() { SPDLOG_WARN("Auto exit timeout. Killing helper instance..."); exitHelper(); } bool Helper::isAuthorized(QDBusMessage const &message) const { auto subject = Polkit::BusNameSubject{message.service().toStdString()}; return Polkit::checkAuthorizationSync(POLKIT_HELPER_ACTION, subject) == Polkit::AuthResult::Yes; } bool Helper::initCrypto(QByteArray const &appPublicKey) { try { cryptoLayer_ = std::make_shared(); cryptoLayer_->init(); cryptoLayer_->usePublicKey(appPublicKey); return true; } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } void Helper::delayAutoExit() { if (autoExitTimer_.isActive()) autoExitTimer_.start(); } bool Helper::initProcessMonitor() { bool success = false; try { appRegistry_ = std::make_shared(); processMonitor_ = std::make_unique( appRegistry_, std::make_unique(), std::make_unique(cryptoLayer_, appRegistry_)); auto pMonInit = [&]() { processMonitor_->start(); }; pMonThread_ = std::make_unique(pMonInit); success = true; } catch (NLProcExecSocket::BindError &e) { SPDLOG_WARN("Bind socket error: {}", e.what()); SPDLOG_WARN("Do you have root permissions?"); } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return success; } void Helper::endProcessMonitor() { if (pMonThread_ != nullptr) { processMonitor_->stop(); pMonThread_->join(); } } bool Helper::initMsgReceiver() { try { msgReceiver_ = std::make_unique( cryptoLayer_, std::make_unique()); return true; } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } bool initDBusForHelperService(QObject *obj) { QDBusConnection bus = QDBusConnection::systemBus(); if (!bus.isConnected()) { SPDLOG_DEBUG("Could not connect to D-Bus system bus"); return false; } if (!bus.registerObject(QStringLiteral(DBUS_HELPER_PATH), obj)) { SPDLOG_DEBUG("Could not register D-Bus object on path {} " "using the interface {}\n.Last D-Bus error: {}", DBUS_HELPER_PATH, DBUS_HELPER_INTERFACE, bus.lastError().message().toStdString()); return false; } if (!bus.registerService(QStringLiteral(DBUS_HELPER_SERVICE))) { SPDLOG_DEBUG("Could not register D-Bus service {}.\nLast D-Bus error: {}", DBUS_HELPER_SERVICE, bus.lastError().message().toStdString()); return false; } return true; } bool endDBusForHelperService() { QDBusConnection bus = QDBusConnection::systemBus(); bus.unregisterObject(QStringLiteral(DBUS_HELPER_PATH)); auto success = bus.unregisterService(QStringLiteral(DBUS_HELPER_SERVICE)); if (!success) { SPDLOG_DEBUG("D-Bus error unregistering service {}: {}", DBUS_HELPER_SERVICE, bus.lastError().message().toStdString()); } return success; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); new Helper(&app); if (!initDBusForHelperService(&app)) exit(1); app.exec(); if (!endDBusForHelperService()) exit(1); return 0; } corectrl-v1.4.2/src/helper/helper.h000066400000000000000000000025401467225065400172330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "helperids.h" #include #include #include #include #include #include #include class ICryptoLayer; class IAppRegistry; class IProcessMonitor; class MsgReceiver; class QByteArray; class Helper final : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", DBUS_HELPER_INTERFACE) public: Helper(QObject *parent) noexcept; ~Helper(); public slots: // D-Bus interface slots QDBusVariant start(QByteArray const &appPublicKey, int autoExitTimeout, QDBusMessage const &message); bool started() const; Q_NOREPLY void exit(QByteArray const &signature); Q_NOREPLY void delayAutoExit(); private slots: void exitHelper(); void autoExitTimeout(); private: bool isAuthorized(QDBusMessage const &message) const; bool initCrypto(QByteArray const &appPublicKey); bool initProcessMonitor(); void endProcessMonitor(); bool initMsgReceiver(); QTimer autoExitTimer_; std::shared_ptr cryptoLayer_; std::shared_ptr appRegistry_; std::unique_ptr processMonitor_; std::unique_ptr pMonThread_; std::unique_ptr msgReceiver_; }; corectrl-v1.4.2/src/helper/helpercontrol.cpp000066400000000000000000000114351467225065400211720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "helpercontrol.h" #include "common/icryptolayer.h" #include "helperids.h" #include #include #include #include #include #include #include #include #include #include #include #include #include HelperControl::HelperControl(std::shared_ptr cryptoLayer, QObject *parent) noexcept : QObject(parent) , cryptoLayer_(std::move(cryptoLayer)) , autoExitTimeout_(minExitTimeout()) , deferAutoExitSignalInterval_(minExitTimeout() * .667) { connect(&deferHelperHealthCheckTimer_, &QTimer::timeout, this, &HelperControl::helperHealthCheckTimeout); connect(&deferHelperAutoExitSignalTimer_, &QTimer::timeout, this, &HelperControl::helperExitDeferrerTimeout); } units::time::millisecond_t HelperControl::minExitTimeout() const { return units::time::millisecond_t(1000); } void HelperControl::init(units::time::millisecond_t autoExitTimeout) { autoExitTimeout_ = std::max(autoExitTimeout, minExitTimeout()); deferAutoExitSignalInterval_ = autoExitTimeout * .667; cryptoLayer_->init(); createHelperInterface(); killOtherHelperInstance(); auto helperPublicKey = startHelper(); if (!helperPublicKey.has_value()) throw std::runtime_error("Cannot start helper"); cryptoLayer_->usePublicKey(helperPublicKey.value()); // Check the helper health every 15 seconds. deferHelperHealthCheckTimer_.setInterval(15000); deferHelperHealthCheckTimer_.start(); } void HelperControl::stop() { deferHelperHealthCheckTimer_.stop(); deferHelperAutoExitSignalTimer_.stop(); stopHelper(); } void HelperControl::helperHealthCheckTimeout() { if (deferHelperAutoExitSignalTimer_.isActive() && !helperHasBeenStarted()) { SPDLOG_WARN("The Helper has not been started. Starting it now."); deferHelperAutoExitSignalTimer_.stop(); auto helperPublicKey = startHelper(); if (!helperPublicKey.has_value()) { // NOTE If the helper died and cannot be started again, it's better to not // crash the application throwing an exception. SPDLOG_WARN("Cannot restart helper!"); } cryptoLayer_->usePublicKey(helperPublicKey.value()); } } void HelperControl::helperExitDeferrerTimeout() { helperInterface_->asyncCall(QStringLiteral("delayAutoExit")); } bool HelperControl::helperHasBeenStarted() const { QDBusReply reply = helperInterface_->call(QStringLiteral("started")); return reply.isValid() && reply.value(); } void HelperControl::createHelperInterface() { helperInterface_ = std::make_unique( QStringLiteral(DBUS_HELPER_SERVICE), QStringLiteral(DBUS_HELPER_PATH), QStringLiteral(DBUS_HELPER_INTERFACE), QDBusConnection::systemBus()); if (!helperInterface_->isValid()) throw std::runtime_error(std::format( "Cannot connect to D-Bus interface {}: {}", DBUS_HELPER_INTERFACE, helperInterface_->lastError().message().toStdString())); } std::optional HelperControl::startHelper() { QDBusReply reply = helperInterface_->call( QStringLiteral("start"), cryptoLayer_->publicKey(), autoExitTimeout_.to()); if (!(reply.isValid() && reply.value().variant().type() == QVariant::ByteArray)) return std::nullopt; deferHelperAutoExitSignalTimer_.setInterval( deferAutoExitSignalInterval_.to()); deferHelperAutoExitSignalTimer_.start(); return reply.value().variant().value(); } void HelperControl::stopHelper() { auto signature = cryptoLayer_->signature({"exit"}); helperInterface_->asyncCall(QStringLiteral("exit"), signature); } void HelperControl::killOtherHelperInstance() { if (helperHasBeenStarted()) { SPDLOG_WARN("Helper instance detected. Killing it now."); if (!startHelperKiller() || helperHasBeenStarted()) throw std::runtime_error("Failed to kill other helper instance"); } } bool HelperControl::startHelperKiller() { QDBusInterface iface(QStringLiteral(DBUS_HELPER_KILLER_SERVICE), QStringLiteral(DBUS_HELPER_KILLER_PATH), QStringLiteral(DBUS_HELPER_KILLER_INTERFACE), QDBusConnection::systemBus()); if (!iface.isValid()) { SPDLOG_DEBUG("Cannot connect to D-Bus interface {}: {}", DBUS_HELPER_KILLER_INTERFACE, iface.lastError().message().toStdString()); return false; } QDBusReply reply = iface.call(QStringLiteral("start")); if (!reply.isValid()) { SPDLOG_DEBUG("Helper killer error: {}", iface.lastError().message().toStdString()); return false; } return reply.value(); } corectrl-v1.4.2/src/helper/helpercontrol.h000066400000000000000000000023341467225065400206350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "ihelpercontrol.h" #include #include #include #include #include #include class ICryptoLayer; class QDBusInterface; class HelperControl final : public QObject , public IHelperControl { Q_OBJECT public: HelperControl(std::shared_ptr cryptoLayer, QObject *parent = nullptr) noexcept; units::time::millisecond_t minExitTimeout() const override; void init(units::time::millisecond_t autoExitTimeout) override; void stop() override; private slots: void helperHealthCheckTimeout(); void helperExitDeferrerTimeout(); private: bool helperHasBeenStarted() const; void createHelperInterface(); std::optional startHelper(); void stopHelper(); void killOtherHelperInstance(); bool startHelperKiller(); std::shared_ptr cryptoLayer_; QTimer deferHelperHealthCheckTimer_; QTimer deferHelperAutoExitSignalTimer_; std::unique_ptr helperInterface_; units::time::millisecond_t autoExitTimeout_; units::time::millisecond_t deferAutoExitSignalInterval_; }; corectrl-v1.4.2/src/helper/helperids.h000066400000000000000000000017401467225065400177340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once // clang-format off #define POLKIT_HELPER_KILLER_ACTION "org.corectrl.helperkiller.init" #define DBUS_HELPER_KILLER_SERVICE "org.corectrl.helperkiller" #define DBUS_HELPER_KILLER_INTERFACE "org.corectrl.helperkiller" #define DBUS_HELPER_KILLER_PATH "/" #define POLKIT_HELPER_ACTION "org.corectrl.helper.init" #define DBUS_HELPER_SERVICE "org.corectrl.helper" #define DBUS_HELPER_INTERFACE "org.corectrl.helper" #define DBUS_HELPER_PATH "/Helper" #define DBUS_HELPER_PMON_INTERFACE "org.corectrl.helper.pmon" #define DBUS_HELPER_PMON_PATH "/Helper/PMon" #define DBUS_HELPER_SYSCTL_INTERFACE "org.corectrl.helper.sysctl" #define DBUS_HELPER_SYSCTL_PATH "/Helper/SysCtl" #define LOG_HELPER_FILE_NAME "CoreCtrl_helper.log" #define HELPER_EXE "corectrl_helper" // clang-format on corectrl-v1.4.2/src/helper/helperkiller.cpp000066400000000000000000000041111467225065400207650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "helperkiller.h" #include "helperids.h" #include "polkit.h" #include #include #include #include #include #include #include #include #include #include HelperKiller::HelperKiller(QObject *parent) noexcept : QDBusAbstractAdaptor(parent) { } HelperKiller::~HelperKiller() = default; bool HelperKiller::start(QDBusMessage const &message) const { if (!isAuthorized(message)) return false; QProcess cmd; cmd.start(QStringLiteral("pidof"), QStringList(HELPER_EXE)); bool result = cmd.waitForFinished(); if (result) { try { auto output = cmd.readAllStandardOutput().toStdString(); int pid = std::stoi(output); result = kill(pid, SIGKILL) == 0; } catch (std::exception const &) { result = false; } } QTimer::singleShot(0, QCoreApplication::instance(), &QCoreApplication::quit); return result; } bool HelperKiller::isAuthorized(QDBusMessage const &message) const { auto subject = Polkit::BusNameSubject{message.service().toStdString()}; return Polkit::checkAuthorizationSync(POLKIT_HELPER_KILLER_ACTION, subject) == Polkit::AuthResult::Yes; } bool initDBusForHelperKillerService(QObject *obj) { QDBusConnection bus = QDBusConnection::systemBus(); return bus.isConnected() && bus.registerObject(QStringLiteral(DBUS_HELPER_KILLER_PATH), obj) && bus.registerService(QStringLiteral(DBUS_HELPER_KILLER_SERVICE)); } bool endDBusForHelperKillerService() { QDBusConnection bus = QDBusConnection::systemBus(); bus.unregisterObject(QStringLiteral(DBUS_HELPER_KILLER_PATH)); return bus.unregisterService(QStringLiteral(DBUS_HELPER_KILLER_SERVICE)); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); new HelperKiller(&app); if (!initDBusForHelperKillerService(&app)) exit(1); app.exec(); if (!endDBusForHelperKillerService()) exit(1); return 0; } corectrl-v1.4.2/src/helper/helperkiller.h000066400000000000000000000010761467225065400204410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "helperids.h" #include #include class QDBusMessage; class HelperKiller final : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", DBUS_HELPER_KILLER_INTERFACE) public: HelperKiller(QObject *parent) noexcept; ~HelperKiller(); public slots: // D-Bus interface slots bool start(QDBusMessage const &message) const; private: bool isAuthorized(QDBusMessage const &message) const; }; corectrl-v1.4.2/src/helper/helpermonitor.cpp000066400000000000000000000071061467225065400212010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "helpermonitor.h" #include "common/icryptolayer.h" #include "helperids.h" #include #include #include #include #include #include #include #include HelperMonitor::HelperMonitor(std::shared_ptr cryptoLayer, QObject *parent) noexcept : QObject(parent) , cryptoLayer_(std::move(cryptoLayer)) { } void HelperMonitor::addObserver(std::shared_ptr observer) { std::lock_guard lock(mutex_); auto const it = std::find(observers_.begin(), observers_.end(), observer); if (it == observers_.end()) observers_.emplace_back(std::move(observer)); } void HelperMonitor::removeObserver( std::shared_ptr const &observer) { std::lock_guard lock(mutex_); std::erase(observers_, observer); } void HelperMonitor::init() { monitorInterface_ = std::make_unique( QStringLiteral(DBUS_HELPER_SERVICE), QStringLiteral(DBUS_HELPER_PMON_PATH), QStringLiteral(DBUS_HELPER_PMON_INTERFACE), QDBusConnection::systemBus()); if (!monitorInterface_->isValid()) throw std::runtime_error( std::format("Cannot connect to D-Bus interface {} (path: {})", DBUS_HELPER_PMON_INTERFACE, DBUS_HELPER_PMON_PATH)); if (!QDBusConnection::systemBus().connect( QStringLiteral(DBUS_HELPER_SERVICE), QStringLiteral(DBUS_HELPER_PMON_PATH), QStringLiteral(DBUS_HELPER_PMON_INTERFACE), QStringLiteral("appExec"), this, SLOT(notifyAppExec(QByteArray const &, QByteArray const &)))) throw std::runtime_error(std::format( "Cannot connect to 'appExec' in D-Bus interface {} (path: {})", DBUS_HELPER_PMON_INTERFACE, DBUS_HELPER_PMON_PATH)); if (!QDBusConnection::systemBus().connect( QStringLiteral(DBUS_HELPER_SERVICE), QStringLiteral(DBUS_HELPER_PMON_PATH), QStringLiteral(DBUS_HELPER_PMON_INTERFACE), QStringLiteral("appExit"), this, SLOT(notifyAppExit(QByteArray const &, QByteArray const &)))) throw std::runtime_error(std::format( "Cannot connect to 'appExit' in D-Bus interface {} (path: {})", DBUS_HELPER_PMON_INTERFACE, DBUS_HELPER_PMON_PATH)); } void HelperMonitor::watchApp(std::string const &app) { QByteArray data(app.c_str()); auto signature = cryptoLayer_->signature(data); monitorInterface_->asyncCall(QStringLiteral("watchApp"), data, signature); } void HelperMonitor::forgetApp(std::string const &app) { QByteArray data(app.c_str()); auto signature = cryptoLayer_->signature(data); monitorInterface_->asyncCall(QStringLiteral("forgetApp"), data, signature); } void HelperMonitor::notifyAppExec(QByteArray const &data, QByteArray const &signature) { if (!cryptoLayer_->verify(data, signature)) { SPDLOG_DEBUG("Failed to verify received data from D-Bus"); return; } std::lock_guard lock(mutex_); auto const app = data.toStdString(); for (auto &o : observers_) o->appExec(app); } void HelperMonitor::notifyAppExit(QByteArray const &data, QByteArray const &signature) { if (!cryptoLayer_->verify(data, signature)) { SPDLOG_DEBUG("Failed to verify received data from D-Bus"); return; } std::lock_guard lock(mutex_); auto const app = data.toStdString(); for (auto &o : observers_) o->appExit(app); } corectrl-v1.4.2/src/helper/helpermonitor.h000066400000000000000000000022121467225065400206370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "ihelpermonitor.h" #include #include #include #include #include #include class ICryptoLayer; class HelperMonitor final : public QObject , public IHelperMonitor { Q_OBJECT public: HelperMonitor(std::shared_ptr cryptoLayer, QObject *parent = nullptr) noexcept; void addObserver(std::shared_ptr observer) override; void removeObserver( std::shared_ptr const &observer) override; void init() override; void watchApp(std::string const &app) override; void forgetApp(std::string const &app) override; private slots: void notifyAppExec(QByteArray const &appExe, QByteArray const &signature); void notifyAppExit(QByteArray const &appExe, QByteArray const &signature); private: std::shared_ptr cryptoLayer_; std::unique_ptr monitorInterface_; std::vector> observers_; std::mutex mutex_; }; corectrl-v1.4.2/src/helper/helpersysctl.cpp000066400000000000000000000023441467225065400210320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "helpersysctl.h" #include "common/icryptolayer.h" #include "core/icommandqueue.h" #include "helperids.h" #include #include #include #include #include #include #include #include HelperSysCtl::HelperSysCtl(std::shared_ptr cryptoLayer) noexcept : cryptoLayer_(std::move(cryptoLayer)) { } void HelperSysCtl::init() { sysCtlInterface_ = std::make_unique( QStringLiteral(DBUS_HELPER_SERVICE), QStringLiteral(DBUS_HELPER_SYSCTL_PATH), QStringLiteral(DBUS_HELPER_SYSCTL_INTERFACE), QDBusConnection::systemBus()); if (!sysCtlInterface_->isValid()) { throw std::runtime_error( std::format("Cannot connect to D-Bus interface {} (path: {})", DBUS_HELPER_SYSCTL_INTERFACE, DBUS_HELPER_SYSCTL_PATH)); } } void HelperSysCtl::apply(ICommandQueue &ctlCmds) { auto data = ctlCmds.toRawData(); if (!data.isEmpty()) { auto signature = cryptoLayer_->signature(data); sysCtlInterface_->asyncCall(QStringLiteral("apply"), data, signature); } } corectrl-v1.4.2/src/helper/helpersysctl.h000066400000000000000000000010051467225065400204700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "ihelpersysctl.h" #include class ICryptoLayer; class QDBusInterface; class HelperSysCtl final : public IHelperSysCtl { public: HelperSysCtl(std::shared_ptr cryptoLayer) noexcept; void init() override; void apply(ICommandQueue &ctlCmds) override; private: std::shared_ptr cryptoLayer_; std::unique_ptr sysCtlInterface_; }; corectrl-v1.4.2/src/helper/ihelpercontrol.h000066400000000000000000000005661467225065400210130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class IHelperControl { public: virtual units::time::millisecond_t minExitTimeout() const = 0; virtual void init(units::time::millisecond_t autoExitTimeout) = 0; virtual void stop() = 0; virtual ~IHelperControl() = default; }; corectrl-v1.4.2/src/helper/ihelpermonitor.h000066400000000000000000000013171467225065400210150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class IHelperMonitor { public: class Observer { public: virtual void appExec(std::string appExe) = 0; virtual void appExit(std::string appExe) = 0; virtual ~Observer() = default; }; virtual void addObserver(std::shared_ptr observer) = 0; virtual void removeObserver(std::shared_ptr const &observer) = 0; virtual void init() = 0; virtual void watchApp(std::string const &app) = 0; virtual void forgetApp(std::string const &app) = 0; virtual ~IHelperMonitor() = default; }; corectrl-v1.4.2/src/helper/ihelpersysctl.h000066400000000000000000000004411467225065400206440ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once class ICommandQueue; class IHelperSysCtl { public: virtual void init() = 0; virtual void apply(ICommandQueue &ctlCmds) = 0; virtual ~IHelperSysCtl() = default; }; corectrl-v1.4.2/src/helper/org.corectrl.helper.conf000066400000000000000000000010421467225065400223270ustar00rootroot00000000000000 corectrl-v1.4.2/src/helper/org.corectrl.helper.policy000066400000000000000000000010501467225065400227000ustar00rootroot00000000000000 Start control daemon Root privileges are required to control the system no auth_admin_keep corectrl-v1.4.2/src/helper/org.corectrl.helper.service.in000066400000000000000000000001611467225065400234500ustar00rootroot00000000000000[D-BUS Service] Name=org.corectrl.helper Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/corectrl/corectrl_helper User=root corectrl-v1.4.2/src/helper/org.corectrl.helperkiller.conf000066400000000000000000000010111467225065400235260ustar00rootroot00000000000000 corectrl-v1.4.2/src/helper/org.corectrl.helperkiller.policy000066400000000000000000000010621467225065400241060ustar00rootroot00000000000000 Kill control daemon Root privileges are required to kill the control daemon no auth_admin_keep corectrl-v1.4.2/src/helper/org.corectrl.helperkiller.service.in000066400000000000000000000001751467225065400246600ustar00rootroot00000000000000[D-BUS Service] Name=org.corectrl.helperkiller Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/corectrl/corectrl_helperkiller User=root corectrl-v1.4.2/src/helper/pmon/000077500000000000000000000000001467225065400165535ustar00rootroot00000000000000corectrl-v1.4.2/src/helper/pmon/appregistry.cpp000066400000000000000000000026541467225065400216370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "appregistry.h" #include #include void AppRegistry::add(std::string const &app) { std::lock_guard lock(regMutex_); registry_.insert(app); notifyRegisteredApp(app); } void AppRegistry::remove(std::string const &app) { std::lock_guard lock(regMutex_); if (registry_.erase(app) > 0) notifyUnregisteredApp(app); } bool AppRegistry::registered(std::string const &app) { std::lock_guard lock(regMutex_); return registry_.find(app) != registry_.end(); } void AppRegistry::addObserver(std::shared_ptr observer) { std::lock_guard lock(obMutex_); auto const it = std::find(observers_.begin(), observers_.end(), observer); if (it == observers_.end()) observers_.emplace_back(std::move(observer)); } void AppRegistry::removeObserver( std::shared_ptr const &observer) { std::lock_guard lock(obMutex_); std::erase(observers_, observer); } void AppRegistry::notifyRegisteredApp(std::string const &app) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->registeredApp(app); } void AppRegistry::notifyUnregisteredApp(std::string const &app) { std::lock_guard lock(obMutex_); for (auto &o : observers_) o->unregisteredApp(app); } corectrl-v1.4.2/src/helper/pmon/appregistry.h000066400000000000000000000015621467225065400213010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iappregistry.h" #include #include #include #include class AppRegistry final : public IAppRegistry { public: void addObserver(std::shared_ptr observer) override; void removeObserver( std::shared_ptr const &observer) override; void add(std::string const &app) override; void remove(std::string const &app) override; bool registered(std::string const &app) override; private: void notifyRegisteredApp(std::string const &app); void notifyUnregisteredApp(std::string const &app); std::vector> observers_; std::mutex obMutex_; std::unordered_set registry_; std::mutex regMutex_; }; corectrl-v1.4.2/src/helper/pmon/iappregistry.h000066400000000000000000000013601467225065400214460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class IAppRegistry { public: class Observer { public: virtual void registeredApp(std::string const &app) = 0; virtual void unregisteredApp(std::string const &app) = 0; virtual ~Observer() = default; }; virtual void addObserver(std::shared_ptr observer) = 0; virtual void removeObserver(std::shared_ptr const &observer) = 0; virtual void add(std::string const &app) = 0; virtual void remove(std::string const &app) = 0; virtual bool registered(std::string const &app) = 0; virtual ~IAppRegistry() = default; }; corectrl-v1.4.2/src/helper/pmon/ipidsolver.h000066400000000000000000000005721467225065400211100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class IPIDSolver { public: /// Translates a PID to its application executable name /// @param PID application's PID /// @return application executable name virtual std::string app(int PID) = 0; virtual ~IPIDSolver() = default; }; corectrl-v1.4.2/src/helper/pmon/ipmonmsgdispatcher.h000066400000000000000000000005051467225065400226240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include class IPMonMsgDispatcher { public: virtual void sendExec(std::string const &app) = 0; virtual void sendExit(std::string const &app) = 0; virtual ~IPMonMsgDispatcher() = default; }; corectrl-v1.4.2/src/helper/pmon/iprocessmonitor.h000066400000000000000000000005131467225065400221620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once struct ProcessEvent; class IProcessMonitor { public: virtual void start() = 0; virtual void stop() = 0; virtual ~IProcessMonitor() = default; protected: virtual ProcessEvent waitProcessEvent() = 0; }; corectrl-v1.4.2/src/helper/pmon/msgdispatcher.cpp000066400000000000000000000062321467225065400221170ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "msgdispatcher.h" #include "common/icryptolayer.h" #include "iappregistry.h" #include #include #include #include #include #include #include #include DBusSignalDispatcher::DBusSignalDispatcher( std::shared_ptr cryptoLayer, std::shared_ptr appRegistry, QObject *parent) : QObject(parent) , cryptoLayer_(std::move(cryptoLayer)) , appRegistry_(std::move(appRegistry)) { QDBusConnection dbusConnection = QDBusConnection::systemBus(); if (!dbusConnection.isConnected()) throw std::runtime_error("Could not connect to D-Bus system bus"); if (!dbusConnection.registerObject(QStringLiteral(DBUS_HELPER_PMON_PATH), QStringLiteral(DBUS_HELPER_PMON_INTERFACE), this, QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportScriptableSlots)) throw std::runtime_error( std::format("Could not register D-Bus object on path {} " "using the interface {}\n.Last D-Bus error: {}", DBUS_HELPER_PMON_PATH, DBUS_HELPER_PMON_INTERFACE, dbusConnection.lastError().message().toStdString())); } DBusSignalDispatcher::~DBusSignalDispatcher() { QDBusConnection dbusConnection = QDBusConnection::systemBus(); dbusConnection.unregisterObject(QStringLiteral(DBUS_HELPER_PMON_INTERFACE)); } void DBusSignalDispatcher::sendExec(QByteArray const &data) { auto signature = cryptoLayer_->signature(data); emit appExec(data, signature); } void DBusSignalDispatcher::sendExit(QByteArray const &data) { auto signature = cryptoLayer_->signature(data); emit appExit(data, signature); } void DBusSignalDispatcher::watchApp(QByteArray const &data, QByteArray const &signature) { if (cryptoLayer_->verify(data, signature)) appRegistry_->add(data.toStdString()); else SPDLOG_DEBUG("Failed to verify received data from D-Bus"); } void DBusSignalDispatcher::forgetApp(QByteArray const &data, QByteArray const &signature) { if (cryptoLayer_->verify(data, signature)) appRegistry_->remove(data.toStdString()); else SPDLOG_DEBUG("Failed to verify received data from D-Bus"); } MsgDispatcher::MsgDispatcher(std::shared_ptr cryptoLayer, std::shared_ptr appRegistry, QObject *parent) : QObject(parent) , dbusSignalDispatcher_(std::move(cryptoLayer), std::move(appRegistry), this) { connect(this, &MsgDispatcher::appExec, &dbusSignalDispatcher_, &DBusSignalDispatcher::sendExec); connect(this, &MsgDispatcher::appExit, &dbusSignalDispatcher_, &DBusSignalDispatcher::sendExit); } void MsgDispatcher::sendExec(std::string const &app) { emit appExec({app.c_str()}); } void MsgDispatcher::sendExit(std::string const &app) { emit appExit({app.c_str()}); } corectrl-v1.4.2/src/helper/pmon/msgdispatcher.h000066400000000000000000000042461467225065400215670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "helperids.h" #include "ipmonmsgdispatcher.h" #include #include class IAppRegistry; class ICryptoLayer; class QByteArray; // Methods of PMonMsgDispatcher class will be called in the ProcessMonitor // thread. However D-Bus signals must be emitted in the thread of the object // that registered the D-Bus object. For this reason, signals are forwarded // to PMonDBusSignalDispatcher through QObject signal / slot mechanism. // PMonDBusSignalDispatcher, as the object that registered the D-Bus object, // will re-emit the forwaded signals through D-Bus in the event loop. class DBusSignalDispatcher final : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", DBUS_HELPER_PMON_INTERFACE) public: DBusSignalDispatcher(std::shared_ptr cryptoLayer, std::shared_ptr appRegistry, QObject *parent = nullptr); ~DBusSignalDispatcher() override; public slots: void sendExec(QByteArray const &data); void sendExit(QByteArray const &data); // D-Bus interface methods Q_SCRIPTABLE void watchApp(QByteArray const &data, QByteArray const &signature); Q_SCRIPTABLE void forgetApp(QByteArray const &data, QByteArray const &signature); signals: // D-Bus interface signals Q_SCRIPTABLE void appExec(QByteArray const &data, QByteArray const &signature); Q_SCRIPTABLE void appExit(QByteArray const &data, QByteArray const &signature); private: std::shared_ptr cryptoLayer_; std::shared_ptr appRegistry_; }; class MsgDispatcher final : public QObject , public IPMonMsgDispatcher { Q_OBJECT public: MsgDispatcher(std::shared_ptr cryptoLayer, std::shared_ptr appRegistry, QObject *parent = nullptr); void sendExec(std::string const &app) override; void sendExit(std::string const &app) override; signals: void appExec(QByteArray const &data); void appExit(QByteArray const &data); private: DBusSignalDispatcher dbusSignalDispatcher_; }; corectrl-v1.4.2/src/helper/pmon/nlprocexecmonitor.cpp000066400000000000000000000011001467225065400230210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "nlprocexecmonitor.h" #include "processevent.h" #include NLProcExecMonitor::NLProcExecMonitor( std::shared_ptr appRegistry, std::unique_ptr &&pidSolver, std::unique_ptr &&msgDispatcher) noexcept : ProcessMonitor(std::move(appRegistry), std::move(pidSolver), std::move(msgDispatcher)) { } ProcessEvent NLProcExecMonitor::waitProcessEvent() { return nlSock_.waitForEvent(); } corectrl-v1.4.2/src/helper/pmon/nlprocexecmonitor.h000066400000000000000000000011661467225065400225020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "nlprocexecsocket.h" #include "processmonitor.h" #include class IAppRegistry; class IPIDSolver; class IPMonMsgDispatcher; class NLProcExecMonitor final : public ProcessMonitor { public: NLProcExecMonitor(std::shared_ptr appRegistry, std::unique_ptr &&pidSolver, std::unique_ptr &&msgDispatcher) noexcept; protected: ProcessEvent waitProcessEvent() override; private: NLProcExecSocket nlSock_; }; corectrl-v1.4.2/src/helper/pmon/nlprocexecsocket.cpp000066400000000000000000000027501467225065400226360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "nlprocexecsocket.h" #include "processevent.h" extern "C" { #include "processeventconnector.h" } NLProcExecSocket::FDHandle::~FDHandle() { process_event_connector_close(fd); } NLProcExecSocket::NLProcExecSocket() { sockFd_.fd = process_event_connector_new(); if (sockFd_.fd < 0) throw std::runtime_error("Cannot create netlink socket"); if (process_event_connector_set_timeout(sockFd_.fd, 5) < 0) throw std::runtime_error("Cannot set socket timeout"); if (process_event_connector_install_filter(sockFd_.fd) < 0) throw std::runtime_error("Cannot install socket filters"); if (process_event_connector_bind(sockFd_.fd) < 0) throw BindError("Cannot bind to socket"); if (process_event_connector_subscribe(sockFd_.fd, true) < 0) throw std::runtime_error("Cannot subscribe to proc events"); } NLProcExecSocket::~NLProcExecSocket() { process_event_connector_subscribe(sockFd_.fd, false); } ProcessEvent NLProcExecSocket::waitForEvent() const { auto event = process_event_connector_read_event(sockFd_.fd); switch (event.type) { case process_event_type::PROCESS_EVENT_EXEC: return ProcessEvent{ProcessEvent::Type::EXEC, event.pid}; break; case process_event_type::PROCESS_EVENT_EXIT: return ProcessEvent{ProcessEvent::Type::EXIT, event.pid}; break; default: return ProcessEvent{ProcessEvent::Type::IGNORE, -1}; } } corectrl-v1.4.2/src/helper/pmon/nlprocexecsocket.h000066400000000000000000000007361467225065400223050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include struct ProcessEvent; class NLProcExecSocket final { public: class BindError : public std::runtime_error { public: using std::runtime_error::runtime_error; }; NLProcExecSocket(); ~NLProcExecSocket(); ProcessEvent waitForEvent() const; private: struct FDHandle { int fd{-1}; ~FDHandle(); } sockFd_; }; corectrl-v1.4.2/src/helper/pmon/processevent.h000066400000000000000000000003311467225065400214410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once struct ProcessEvent { enum class Type { IGNORE, EXEC, EXIT, } event; int pid; }; corectrl-v1.4.2/src/helper/pmon/processeventconnector.c000066400000000000000000000154511467225065400233600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include "processeventconnector.h" #include #include #include #include #include #include #include #include #include #include #include #define SUBSCRIBE_MSG_SIZE \ NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op)) #define READ_EVENT_MSG_SIZE \ NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(struct proc_event)) int process_event_connector_new() { return socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); } int process_event_connector_close(int socket_fd) { if (socket_fd >= 0) return close(socket_fd); return 0; } int process_event_connector_set_timeout(int socket_fd, unsigned int seconds) { struct timeval duration; duration.tv_sec = seconds; duration.tv_usec = 0; return setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &duration, sizeof(duration)); } int process_event_connector_bind(int socket_fd) { struct sockaddr_nl sa_nl; sa_nl.nl_family = AF_NETLINK; sa_nl.nl_groups = CN_IDX_PROC; sa_nl.nl_pid = 0; // 0 = lets the kernel to handle nl_pid return bind(socket_fd, (struct sockaddr *)(&sa_nl), sizeof(sa_nl)); } int process_event_connector_subscribe(int socket_fd, bool subscribe) { typedef struct nlcn_msg_t { struct nlmsghdr nl_hdr __attribute__((aligned(NLMSG_ALIGNTO))); struct cn_msg cn_msg; } nlcn_msg; char msg_buffer[SUBSCRIBE_MSG_SIZE] = {0}; nlcn_msg *msg = (nlcn_msg *)msg_buffer; msg->nl_hdr.nlmsg_len = SUBSCRIBE_MSG_SIZE; msg->nl_hdr.nlmsg_pid = 0; msg->nl_hdr.nlmsg_type = NLMSG_DONE; msg->cn_msg.id.idx = CN_IDX_PROC; msg->cn_msg.id.val = CN_VAL_PROC; msg->cn_msg.len = sizeof(enum proc_cn_mcast_op); enum proc_cn_mcast_op *mcast = (enum proc_cn_mcast_op *)msg->cn_msg.data; *mcast = subscribe ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE; if (send(socket_fd, msg, SUBSCRIBE_MSG_SIZE, 0) < 0) return -1; return 0; } int process_event_connector_install_filter(int socket_fd) { struct sock_filter filter[] = { // clang-format off // check message from kernel BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct nlmsghdr, nlmsg_pid)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, 0), BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message // check message type NLMSG_DONE BPF_STMT(BPF_LD | BPF_H | BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(NLMSG_DONE), 1, 0), BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message // check proc connector event CN_IDX_PROC BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, id) + offsetof(struct cb_id, idx)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(CN_IDX_PROC), 1, 0), BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message // check proc connector event CN_VAL_PROC BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, id) + offsetof(struct cb_id, val)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(CN_VAL_PROC), 1, 0), BPF_STMT(BPF_RET | BPF_K, 0x0), // drop message // accept exec messages from processes BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, data) + offsetof(struct proc_event, what)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(PROC_EVENT_EXEC), 0, 6), // processes have process_pid == process_tgid (thread group leaders) BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, data) + offsetof(struct proc_event, event_data.exec.process_pid)), BPF_STMT(BPF_ST, 0), BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, data) + offsetof(struct proc_event, event_data.exec.process_tgid)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 9), BPF_STMT(BPF_RET | BPF_K, 0xffffffff), // accept exit messages from processes BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, data) + offsetof(struct proc_event, what)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(PROC_EVENT_EXIT), 0, 6), // processes have process_pid == process_tgid BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, data) + offsetof(struct proc_event, event_data.exit.process_pid)), BPF_STMT(BPF_ST, 0), BPF_STMT(BPF_LDX | BPF_W | BPF_MEM, 0), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, NLMSG_LENGTH(0) + offsetof(struct cn_msg, data) + offsetof(struct proc_event, event_data.exit.process_tgid)), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 1), BPF_STMT(BPF_RET | BPF_K, 0xffffffff), // drop any other messages BPF_STMT(BPF_RET | BPF_K, 0x0), // clang-format on }; struct sock_fprog fprog; memset(&fprog, 0, sizeof(fprog)); fprog.filter = filter; fprog.len = sizeof(filter) / sizeof(*filter); return setsockopt(socket_fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); } process_event process_event_connector_read_event(int socket_fd) { typedef struct nlcn_msg_t { struct nlmsghdr nl_hdr __attribute__((aligned(NLMSG_ALIGNTO))); struct cn_msg cn_msg; } nlcn_msg; char msg_buffer[READ_EVENT_MSG_SIZE] = {0}; nlcn_msg *msg = (nlcn_msg *)msg_buffer; ssize_t const rc = recv(socket_fd, msg, READ_EVENT_MSG_SIZE, 0); if (rc > 0) { struct proc_event *event = ((struct proc_event *)msg->cn_msg.data); switch (event->what) { case PROC_EVENT_EXEC: return (process_event){.type = PROCESS_EVENT_EXEC, .pid = event->event_data.exec.process_pid}; case PROC_EVENT_EXIT: return (process_event){.type = PROCESS_EVENT_EXIT, .pid = event->event_data.exit.process_pid}; default: return (process_event){.type = PROCESS_EVENT_OTHER, .pid = -1}; } } return (process_event){.type = PROCESS_EVENT_OTHER, .pid = -1}; } corectrl-v1.4.2/src/helper/pmon/processeventconnector.h000066400000000000000000000014141467225065400233570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #pragma once #include #include typedef enum process_event_type_t { PROCESS_EVENT_EXEC, PROCESS_EVENT_EXIT, PROCESS_EVENT_OTHER, } process_event_type; typedef struct process_event_t { process_event_type type; int pid; } process_event; int process_event_connector_new(); int process_event_connector_close(int socket_fd); int process_event_connector_set_timeout(int socket_fd, unsigned int seconds); int process_event_connector_bind(int socket_fd); int process_event_connector_subscribe(int socket_fd, bool subscribe); int process_event_connector_install_filter(int socket_fd); process_event process_event_connector_read_event(int socket_fd); corectrl-v1.4.2/src/helper/pmon/processmonitor.cpp000066400000000000000000000032521467225065400223470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "processmonitor.h" #include "iappregistry.h" #include "ipidsolver.h" #include "ipmonmsgdispatcher.h" #include "processevent.h" #include "processregistry.h" #include ProcessMonitor::ProcessMonitor( std::shared_ptr appRegistry, std::unique_ptr &&pidSolver, std::unique_ptr &&msgDispatcher) noexcept : appRegistry_(std::move(appRegistry)) , pidSolver_(std::move(pidSolver)) , msgDispatcher_(std::move(msgDispatcher)) { procRegistry_ = std::make_unique(this->appRegistry_); } ProcessMonitor::~ProcessMonitor() = default; void ProcessMonitor::start() { while (!stopSignal_.load(std::memory_order_relaxed)) { ProcessEvent const e = waitProcessEvent(); switch (e.event) { case ProcessEvent::Type::IGNORE: continue; case ProcessEvent::Type::EXEC: processExec(e.pid); break; case ProcessEvent::Type::EXIT: processExit(e.pid); break; } } } void ProcessMonitor::stop() { stopSignal_.store(true, std::memory_order_relaxed); } void ProcessMonitor::processExec(int pid) { auto const app = pidSolver_->app(pid); if (!appRegistry_->registered(app)) return; if (!procRegistry_->running(app)) msgDispatcher_->sendExec(app); procRegistry_->add(pid, app); } void ProcessMonitor::processExit(int pid) { auto app = procRegistry_->findApp(pid); if (!app) // no app registered to that PID return; procRegistry_->remove(pid); if (!procRegistry_->running(app.value())) msgDispatcher_->sendExit(app.value()); } corectrl-v1.4.2/src/helper/pmon/processmonitor.h000066400000000000000000000016351467225065400220170ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "iprocessmonitor.h" #include #include class IAppRegistry; class IPIDSolver; class IPMonMsgDispatcher; class ProcessRegistry; class ProcessMonitor : public IProcessMonitor { public: ProcessMonitor(std::shared_ptr appRegistry, std::unique_ptr &&pidSolver, std::unique_ptr &&msgDispatcher) noexcept; ~ProcessMonitor() override; void start() override; void stop() override; private: void processExec(int pid); void processExit(int pid); std::shared_ptr const appRegistry_; std::unique_ptr const pidSolver_; std::unique_ptr procRegistry_; std::unique_ptr msgDispatcher_; std::atomic stopSignal_{false}; }; corectrl-v1.4.2/src/helper/pmon/processregistry.cpp000066400000000000000000000051321467225065400225270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "processregistry.h" #include "iappregistry.h" #include #include class ProcessRegistry::AppRegistryObserver : public IAppRegistry::Observer { public: AppRegistryObserver(ProcessRegistry &outer) noexcept; void registeredApp(std::string const &app) override; void unregisteredApp(std::string const &app) override; private: ProcessRegistry &outer_; }; ProcessRegistry::AppRegistryObserver::AppRegistryObserver( ProcessRegistry &outer) noexcept : outer_(outer) { } void ProcessRegistry::AppRegistryObserver::registeredApp(std::string const &app) { outer_.registeredApp(app); } void ProcessRegistry::AppRegistryObserver::unregisteredApp(std::string const &app) { outer_.unregisteredApp(app); } ProcessRegistry::ProcessRegistry(std::shared_ptr appRegistry) noexcept : appRegObserver_(std::make_shared(*this)) { appRegistry->addObserver(appRegObserver_); } void ProcessRegistry::add(int PID, std::string const &app) { std::lock_guard lock(mutex_); auto const pidIt = pidReg_.find(PID); if (pidIt == pidReg_.cend()) { pidReg_.insert({PID, app}); // increment counter auto const appIt = appCounterReg_.find(app); if (appIt != appCounterReg_.cend()) ++appIt->second; } } void ProcessRegistry::remove(int PID) { std::lock_guard lock(mutex_); auto const pidIt = pidReg_.find(PID); if (pidIt != pidReg_.cend()) { auto const app = std::move(pidIt->second); pidReg_.erase(pidIt); // decrement counter auto appIt = appCounterReg_.find(app); if (appIt != appCounterReg_.end()) --appIt->second; } } bool ProcessRegistry::running(std::string const &app) { std::lock_guard lock(mutex_); auto const it = appCounterReg_.find(app); if (it != appCounterReg_.cend()) return it->second > 0; return false; } std::optional ProcessRegistry::findApp(int PID) { std::lock_guard lock(mutex_); auto const it = pidReg_.find(PID); if (it != pidReg_.end()) return it->second; return {}; } void ProcessRegistry::registeredApp(std::string const &app) { std::lock_guard lock(mutex_); appCounterReg_.insert({app, 0}); } void ProcessRegistry::unregisteredApp(std::string const &app) { std::lock_guard lock(mutex_); for (auto it = pidReg_.begin(); it != pidReg_.end();) { if (it->second == app) it = pidReg_.erase(it); else ++it; } appCounterReg_.erase(app); } corectrl-v1.4.2/src/helper/pmon/processregistry.h000066400000000000000000000014751467225065400222020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include #include #include #include class IAppRegistry; class ProcessRegistry final { public: ProcessRegistry(std::shared_ptr appRegistry) noexcept; void add(int PID, std::string const &app); void remove(int PID); bool running(std::string const &app); std::optional findApp(int PID); private: void registeredApp(std::string const &app); void unregisteredApp(std::string const &app); class AppRegistryObserver; std::shared_ptr const appRegObserver_; std::unordered_map pidReg_; std::unordered_map appCounterReg_; std::mutex mutex_; }; corectrl-v1.4.2/src/helper/pmon/procpidsolver.cpp000066400000000000000000000033671467225065400221630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "procpidsolver.h" #include "common/fileutils.h" #include #include #include #include std::string ProcPIDSolver::app(int PID) { auto const procPIDPath = procPath_ / std::to_string(PID); auto exeName = procExeFileName(procPIDPath); // Handle wine apps. if (wineExecutables_.find(exeName) != wineExecutables_.cend()) { auto const entries = Utils::File::readFileLines(procPIDPath / "cmdline", '\0'); auto const wineExeName = wineAppName(entries); if (!wineExeName.empty()) exeName = wineExeName; } return exeName; } std::string ProcPIDSolver::procExeFileName(std::filesystem::path const &procPIDPath) const { std::error_code ec; return std::filesystem::read_symlink(procPIDPath / "exe", ec).filename(); } std::string ProcPIDSolver::lastComponent(std::string const &path) const { size_t const pos = path.find_last_of("\\/"); if (pos == std::string::npos) return path; return path.substr(pos + 1); } std::string ProcPIDSolver::wineAppName(std::vector const &cmdline) const { for (auto const &entry : cmdline) { // skip wine executable files std::filesystem::path const entryPath(entry); if (entryPath.is_absolute() && wineExecutables_.find(entryPath.filename()) != wineExecutables_.cend()) continue; // look for .exe extension std::string extension = entryPath.extension(); std::transform(extension.cbegin(), extension.cend(), extension.begin(), ::tolower); if (extension != ".exe") break; return lastComponent(entry); } return ""; } corectrl-v1.4.2/src/helper/pmon/procpidsolver.h000066400000000000000000000023631467225065400216230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "ipidsolver.h" #include #include #include #include class ProcPIDSolver final : public IPIDSolver { public: std::string app(int PID) override; private: /// Gets the canonical path of the file procPIDPath/exe /// @param procPIDPath the process /proc/PID path /// @return canonical path of the file or empty string if procPIDPath/exe /// is not a valid path std::string procExeFileName(std::filesystem::path const &procPIDPath) const; /// Returns the last component of a windows or unix path std::string lastComponent(std::string const &path) const; /// Gets the executable name (.exe) from a wine launch command line /// @param cmdline /proc/PID/cmline file entries /// @return executable name or empty string when the command line is not a valid wine /// executable launch command line std::string wineAppName(std::vector const &cmdline) const; std::filesystem::path const procPath_{"/proc"}; std::set const wineExecutables_{ "wine-preloader", "wine64-preloader", "wine", "wine64", "wineloader", "wineloader64"}; }; corectrl-v1.4.2/src/helper/polkit.cpp000066400000000000000000000043531467225065400176150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Juan Palacios #include "polkit.h" #define QT_NO_KEYWORDS #include #include namespace Polkit { class Authority { public: Authority() noexcept; ~Authority(); PolkitAuthority *get() const; private: PolkitAuthority *authority_; }; Authority::Authority() noexcept : authority_(nullptr) { GError *error = nullptr; authority_ = polkit_authority_get_sync(nullptr, &error); if (authority_ == nullptr) { SPDLOG_DEBUG("Could not get Polkit authority: {}", error->message); g_error_free(error); return; } } Authority::~Authority() { g_object_unref(authority_); } PolkitAuthority *Authority::get() const { return authority_; } class BusNameSubjectImpl { public: BusNameSubjectImpl(BusNameSubject const &subject) noexcept; ~BusNameSubjectImpl(); PolkitSubject *get() const; private: PolkitSubject *subject_; }; BusNameSubjectImpl::BusNameSubjectImpl(BusNameSubject const &subject) noexcept : subject_(nullptr) { subject_ = polkit_system_bus_name_new(subject.bus.c_str()); } BusNameSubjectImpl::~BusNameSubjectImpl() { g_object_unref(subject_); } PolkitSubject *BusNameSubjectImpl::get() const { return subject_; } AuthResult checkAuthorizationSync(std::string const &actionId, BusNameSubject const &subject) { auto polkitAuthority = Authority(); if (polkitAuthority.get() == nullptr) return AuthResult::Error; auto polkitSubject = BusNameSubjectImpl(subject); if (polkitSubject.get() == nullptr) return AuthResult::Error; GError *error = nullptr; auto polkitResult = polkit_authority_check_authorization_sync( polkitAuthority.get(), polkitSubject.get(), actionId.c_str(), nullptr, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, nullptr, &error); if (error) { SPDLOG_DEBUG("Could not check Polkit authorization: {}", error->message); g_error_free(error); return AuthResult::Error; } auto result = polkit_authorization_result_get_is_authorized(polkitResult) ? AuthResult::Yes : AuthResult::No; g_object_unref(polkitResult); return result; } } // namespace Polkit corectrl-v1.4.2/src/helper/polkit.h000066400000000000000000000010501467225065400172510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Juan Palacios #pragma once #include namespace Polkit { enum class AuthResult { Yes, No, Error, }; struct BusNameSubject { std::string bus; }; /// Checks whether a subject, identified by its bus name, is authorized to /// perform an action. This operation requires user interaction. AuthResult checkAuthorizationSync(std::string const &actionId, BusNameSubject const &busNameSubject); } // namespace Polkit corectrl-v1.4.2/src/helper/sysctl/000077500000000000000000000000001467225065400171235ustar00rootroot00000000000000corectrl-v1.4.2/src/helper/sysctl/isysfswriter.h000066400000000000000000000005271467225065400220550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include #include class ISysfsWriter { public: virtual void write(std::filesystem::path const &sysfsEntry, std::string const &value) = 0; virtual ~ISysfsWriter() = default; }; corectrl-v1.4.2/src/helper/sysctl/msgreceiver.cpp000066400000000000000000000035221467225065400221440ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "msgreceiver.h" #include "common/icryptolayer.h" #include "isysfswriter.h" #include #include #include #include #include #include #include #include MsgReceiver::MsgReceiver(std::shared_ptr cryptoLayer, std::unique_ptr &&sysfsWriter, QObject *parent) : QObject(parent) , cryptoLayer_(std::move(cryptoLayer)) , sysfsWriter_(std::move(sysfsWriter)) { QDBusConnection dbusConnection = QDBusConnection::systemBus(); if (!dbusConnection.isConnected()) throw std::runtime_error("Could not connect to D-Bus system bus"); if (!dbusConnection.registerObject( QStringLiteral(DBUS_HELPER_SYSCTL_PATH), QStringLiteral(DBUS_HELPER_SYSCTL_INTERFACE), this, QDBusConnection::ExportScriptableSlots)) throw std::runtime_error( std::format("Could not register D-Bus object on path {} " "using the interface {}\n.Last D-Bus error: {}", DBUS_HELPER_SYSCTL_PATH, DBUS_HELPER_SYSCTL_INTERFACE, dbusConnection.lastError().message().toStdString())); } MsgReceiver::~MsgReceiver() { QDBusConnection dbusConnection = QDBusConnection::systemBus(); dbusConnection.unregisterObject(QStringLiteral(DBUS_HELPER_SYSCTL_INTERFACE)); } void MsgReceiver::apply(QByteArray const &data, QByteArray const &signature) { if (cryptoLayer_->verify(data, signature)) { auto cmdList = data.split('\0'); for (int i = 0; i + 1 < cmdList.size(); i += 2) sysfsWriter_->write(cmdList[i].data(), cmdList[i + 1].data()); } else SPDLOG_DEBUG("Failed to verify received data from D-Bus"); } corectrl-v1.4.2/src/helper/sysctl/msgreceiver.h000066400000000000000000000014031467225065400216050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "helperids.h" #include #include class ICryptoLayer; class ISysfsWriter; class QByteArray; class MsgReceiver final : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", DBUS_HELPER_SYSCTL_INTERFACE) public: MsgReceiver(std::shared_ptr cryptoLayer, std::unique_ptr &&sysfsWriter, QObject *parent = nullptr); ~MsgReceiver(); public slots: // D-Bus interface methods Q_SCRIPTABLE void apply(QByteArray const &data, QByteArray const &signature); private: std::shared_ptr cryptoLayer_; std::unique_ptr sysfsWriter_; }; corectrl-v1.4.2/src/helper/sysctl/sysfswriter.cpp000066400000000000000000000022171467225065400222350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "sysfswriter.h" #include "common/fileutils.h" #include #include #include void SysfsWriter::write(std::filesystem::path const &sysfsEntry, std::string const &value) { if (!Utils::File::isFilePathValid(sysfsEntry)) { SPDLOG_DEBUG("Invalid file path {}", sysfsEntry.c_str()); return; } if (!isSysfsPath(sysfsEntry)) { SPDLOG_DEBUG("{} is not a sysfs path. Value {} wont be written.", sysfsEntry.c_str(), value); return; } std::ofstream file(sysfsEntry); if (!file.is_open()) { SPDLOG_DEBUG("Cannot write {} to file {}", value, sysfsEntry.c_str()); return; } file << value << std::endl; } bool SysfsWriter::isSysfsPath(std::filesystem::path const &path) const { try { // check whether canonical path starts with '/sys' return std::filesystem::canonical(path).string().compare( 0, sysfsPath.length(), sysfsPath) == 0; } catch (std::exception const &e) { SPDLOG_DEBUG(e.what()); } return false; } corectrl-v1.4.2/src/helper/sysctl/sysfswriter.h000066400000000000000000000007401467225065400217010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "isysfswriter.h" #include #include class SysfsWriter final : public ISysfsWriter { public: void write(std::filesystem::path const &sysfsEntry, std::string const &value) override; private: static constexpr std::string_view sysfsPath{"/sys"}; bool isSysfsPath(std::filesystem::path const &path) const; }; corectrl-v1.4.2/src/images/000077500000000000000000000000001467225065400155705ustar00rootroot00000000000000corectrl-v1.4.2/src/images/AppIcon.svg000077700000000000000000000000001467225065400251202../../resources/icon/app_128.svgustar00rootroot00000000000000corectrl-v1.4.2/src/images/DefaultIcon.svg000077700000000000000000000000001467225065400257002../../resources/icon/app_16.svgustar00rootroot00000000000000corectrl-v1.4.2/src/images/GlobalProfile.svg000066400000000000000000000060701467225065400210350ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/src/images/WarningIcon.svg000066400000000000000000000057321467225065400205360ustar00rootroot00000000000000 image/svg+xml corectrl-v1.4.2/src/main.cpp000066400000000000000000000023671467225065400157630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include "app/app.h" #include "app/appfactory.h" #include "common/logger.h" #include #include // Handle easily unix signals // // Credits: Amir Zamani // https://gist.github.com/azadkuh/a2ac6869661ebd3f8588#file-qt-unix-signals-md void catchUnixSignals(std::initializer_list quitSignals) { auto handler = [](int) -> void { QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); }; sigset_t blocking_mask; sigemptyset(&blocking_mask); for (auto sig : quitSignals) sigaddset(&blocking_mask, sig); struct sigaction sa; sa.sa_handler = handler; sa.sa_mask = blocking_mask; sa.sa_flags = 0; for (auto sig : quitSignals) sigaction(sig, &sa, nullptr); } int main(int argc, char **argv) { setupLogger(std::filesystem::temp_directory_path() / (std::string(App::Name) + ".log")); SPDLOG_DEBUG("----- Application started -----"); catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP}); AppFactory appFactory; auto app = appFactory.build(); if (app != nullptr) return app->exec(argc, argv); else return -1; } corectrl-v1.4.2/src/qml/000077500000000000000000000000001467225065400151145ustar00rootroot00000000000000corectrl-v1.4.2/src/qml/AMDFanAutoForm.qml000066400000000000000000000003131467225065400203270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_FAN_AUTO { objectName: "AMD_FAN_AUTO" } corectrl-v1.4.2/src/qml/AMDFanCurveForm.qml000066400000000000000000000057371467225065400205220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_FAN_CURVE { id: fanCurve objectName: "AMD_FAN_CURVE" width: contents.width height: contents.height onCurveChanged: points => { curveControl.removeCurve("curve") curveControl.addCurve("curve", Material.accent, points) } onFanStopChanged: enabled => { if (enabled) p.showFanStartCurve() else p.hideFanStartCurve() fanStop.checked = enabled } onFanStartValueChanged: value => { if (fanCurve.fanStop) { p.hideFanStartCurve() p.showFanStartCurve() } fanStartValue.value = value } onTemperatureRangeChanged: (min, max) => { curveControl.configureAxes(qsTr("Temperature"), "\u00B0C", min, max, qsTr("PWM"), "%", 0, 100) // Reposition fanStart curve as its control point position depends // on temperature range if (fanCurve.fanStop) { p.hideFanStartCurve() p.showFanStartCurve() } } QtObject { // private stuff id: p function hideFanStartCurve() { curveControl.removeCurve("fanStart") } function showFanStartCurve() { var points = [] points.push(Qt.point(fanCurve.maxTemp - (fanCurve.maxTemp - fanCurve.minTemp) * .15, fanCurve.fanStartValue)) curveControl.addCurve("fanStart", Style.CurveControl.curve_amd_start_color, points) } } TextMetrics { id: tFMetrics text: "100" } Pane { id: contents padding: Style.g_padding ColumnLayout { spacing: 8 CurveControl { id: curveControl minXDistance: 5 clampPointsYCoordinate: true width: 480 height: 240 onCurveChanged: (name, oldPoint, newPoint) => { if (name === "curve") fanCurve.updateCurvePoint(oldPoint, newPoint) else if (name === "fanStart") fanCurve.fanStartValue = parseInt(Math.round(newPoint.y)) } } RowLayout { spacing: 8 Item { Layout.fillWidth: true } Item { implicitWidth: fanStop.width / (1 + Style.g_tweakScale) Switch { id: fanStop scale: Style.g_tweakScale anchors.centerIn: parent onToggled: fanCurve.fanStop = checked } } Label { text: qsTr("Fan start") enabled: fanStop.checked } CIntInput { id: fanStartValue minValue: 0 maxValue: 100 enabled: fanStop.checked Layout.preferredWidth: tFMetrics.width + padding * 2 onValueChanged: fanCurve.fanStartValue = value } } } } } corectrl-v1.4.2/src/qml/AMDFanFixedForm.qml000066400000000000000000000037601467225065400204670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_FAN_FIXED { id: fanFixed objectName: "AMD_FAN_FIXED" width: contents.width height: contents.height onValueChanged: value => fanValue.value = value onFanStopChanged: enabled => fanStop.checked = enabled onFanStartValueChanged: value => fanStartValue.value = value TextMetrics { id: tFMetrics text: "100" } Pane { id: contents padding: Style.g_padding ColumnLayout { RowLayout { spacing: 8 Slider { id: fanValue from: 0 to: 100 stepSize: 1 onPressedChanged: pressed => { if (!pressed) fanFixed.changeValue(fanValue.value) } } CIntInput { value: fanValue.value minValue: fanValue.from maxValue: fanValue.to Layout.preferredWidth: tFMetrics.width + padding * 2 onValueChanged: { fanValue.value = value fanFixed.changeValue(value) } } } RowLayout { spacing: 8 Item { Layout.fillWidth: true } Item { implicitWidth: fanStop.width / (1 + Style.g_tweakScale) Switch { id: fanStop scale: Style.g_tweakScale anchors.centerIn: parent onToggled: fanFixed.enableFanStop(checked) } } Label { text: qsTr("Fan start") enabled: fanStop.checked } CIntInput { id: fanStartValue enabled: fanStop.checked minValue: fanValue.from maxValue: fanValue.to Layout.preferredWidth: tFMetrics.width + padding * 2 onValueChanged: fanFixed.changeFanStartValue(value) } } } } } corectrl-v1.4.2/src/qml/AMDFanModeForm.qml000066400000000000000000000011461467225065400203100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_FAN_MODE { id: fMode objectName: "AMD_FAN_MODE" width: modeSelector.width height: modeSelector.height onModesChanged: modes => modeSelector.setModes(modes) onModeChanged: mode => modeSelector.select(mode) ModeSelector { id: modeSelector headerTitle: qsTr("Ventilation") contentParentObject: "AMD_FAN_MODE_Plug" onSelectionChanged: mode => fMode.changeMode(mode) onChildAdded: child => fMode.setupChild(child) } } corectrl-v1.4.2/src/qml/AMDOdFanAutoForm.qml000066400000000000000000000003211467225065400206110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_OD_FAN_AUTO { objectName: "AMD_OD_FAN_AUTO" } corectrl-v1.4.2/src/qml/AMDOdFanCurveForm.qml000066400000000000000000000022201467225065400207650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_OD_FAN_CURVE { id: fanCurve objectName: "AMD_OD_FAN_CURVE" width: contents.width height: contents.height onCurveChanged: curve => { curveControl.removeCurve("curve") curveControl.addCurve("curve", Material.accent, curve) } onCurveRangeChanged: (tempMin, tempMax, speedMin, speedMax) => { curveControl.configureAxes(qsTr("Temperature"), "\u00B0C", tempMin, tempMax, qsTr("Speed"), "%", speedMin, speedMax) } TextMetrics { id: tFMetrics text: "100" } Pane { id: contents padding: Style.g_padding ColumnLayout { spacing: 8 CurveControl { id: curveControl minXDistance: 5 clampPointsYCoordinate: true width: 480 height: 240 onCurveChanged: (name, oldPoint, newPoint) => fanCurve.updateCurvePoint(oldPoint, newPoint) } } } } corectrl-v1.4.2/src/qml/AMDPMAdvancedForm.qml000066400000000000000000000015701467225065400207420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import CoreCtrl.UIComponents 1.0 AMD_PM_ADVANCED { id: pmAdv objectName: "AMD_PM_ADVANCED" width: controls.width height: controls.height Pane { id: controls padding: 0 Flow { objectName: "AMD_PM_ADVANCED_Plug" width: { var maxWidth = 0 for (var i = 0; i < children.length; ++i) maxWidth = Math.max(maxWidth, children[i].width) return maxWidth } property var childrenAdded: [] onChildrenChanged: { for (var i = 0; i < children.length; ++i) { if (childrenAdded[children[i]] === undefined) { childrenAdded[children[i]] = children[i] pmAdv.setupChild(children[i]) } } } } } } corectrl-v1.4.2/src/qml/AMDPMAutoForm.qml000066400000000000000000000003111467225065400201350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_PM_AUTO { objectName: "AMD_PM_AUTO" } corectrl-v1.4.2/src/qml/AMDPMDynamicFreqForm.qml000066400000000000000000000003311467225065400214310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_PM_DYNAMIC_FREQ { objectName: "AMD_PM_DYNAMIC_FREQ" } corectrl-v1.4.2/src/qml/AMDPMFixedForm.qml000066400000000000000000000024741467225065400203000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_FIXED { id: pmFixed objectName: "AMD_PM_FIXED" width: contents.width height: contents.height Component { id: modeButton Button { property string mode; checkable: true; } } onModesChanged: modes => { for (var i = 0; i < modes.length; i+=2) { var button = modeButton.createObject(btnContainer); button.mode = modes[i] button.text = modes[i + 1] } btnContainer.forceLayout() } onModeChanged: mode => { // check the button specified by mode var buttons = btnContainer.children for (var i = 0; i < buttons.length; i++) { if (buttons[i].mode === mode) { buttons[i].checked = true btnGroup.lastChecked = buttons[i] break; } } } ButtonGroup { id: btnGroup property var lastChecked buttons: btnContainer.children onClicked: button => { if (lastChecked !== button) { lastChecked = button pmFixed.changeMode(button.mode) } } } Pane { id: contents padding: Style.g_padding Row { id: btnContainer spacing: 8 } } } corectrl-v1.4.2/src/qml/AMDPMFixedFreqForm.qml000066400000000000000000000054701467225065400211150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_FIXED_FREQ { id: pmFrequency objectName: "AMD_PM_FIXED_FREQ" width: contents.width height: contents.height onSclkIndexChanged: index => sclkIndex.value = index onMclkIndexChanged: index => mclkIndex.value = index onSclkStatesChanged: states => { if (states.length > 0) { p.sclkStateLbls.length = 0 p.sclkStateIndices.length = 0 for (var i = 0; i < states.length; i += 2) { p.sclkStateIndices.push(states[i]) p.sclkStateLbls.push(states[i + 1]) } sclkIndex.to = p.sclkStateLbls.length - 1 } } onMclkStatesChanged: states => { if (states.length > 0) { p.mclkStateLbls.length = 0 p.mclkStateIndices.length = 0 for (var i = 0; i < states.length; i += 2) { p.mclkStateIndices.push(states[i]) p.mclkStateLbls.push(states[i + 1]) } mclkIndex.to = p.mclkStateLbls.length - 1 } } QtObject { id: p property var sclkStateLbls: [] property var mclkStateLbls: [] property var sclkStateIndices: [] property var mclkStateIndices: [] } TextMetrics { id: tFMetrics text: "0000 MHz" } Pane { id: contents padding: Style.g_padding ColumnLayout { spacing: 0 RowLayout { spacing: 8 visible: sclkIndex.from < sclkIndex.to Item { Layout.fillWidth: true } Label { text: qsTr("GPU") } Slider { id: sclkIndex value: 0 from: 0 to: 0 stepSize: 1 onPressedChanged: pressed => { if (!pressed) pmFrequency.changeSclkIndex(p.sclkStateIndices[sclkIndex.value]) } } Label { text: sclkIndex.to > 0 ? p.sclkStateLbls[sclkIndex.value] : "" horizontalAlignment: Text.AlignRight Layout.preferredWidth: tFMetrics.width } } RowLayout { spacing: 8 visible: mclkIndex.from < mclkIndex.to Item { Layout.fillWidth: true } Label { text: qsTr("Memory") } Slider { id: mclkIndex value: 0 from: 0 to: 0 stepSize: 1 onPressedChanged: pressed => { if (!pressed) pmFrequency.changeMclkIndex(p.mclkStateIndices[mclkIndex.value]) } } Label { text: mclkIndex.to > 0 ? p.mclkStateLbls[mclkIndex.value] : "" horizontalAlignment: Text.AlignRight Layout.preferredWidth: tFMetrics.width } } } } } corectrl-v1.4.2/src/qml/AMDPMFreqModeForm.qml000066400000000000000000000013131467225065400207320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_FREQ_MODE { id: freqMode objectName: "AMD_PM_FREQ_MODE" width: modeSelector.width height: modeSelector.height onModesChanged: modes => modeSelector.setModes(modes) onModeChanged: mode => modeSelector.select(mode) ModeSelector { id: modeSelector headerTitle: qsTr("Frequency") headerBackground: Style.ModeSelector.body.bg_color contentParentObject: "AMD_PM_FREQ_MODE_Plug" onSelectionChanged: mode => freqMode.changeMode(mode) onChildAdded: child => freqMode.setupChild(child) } } corectrl-v1.4.2/src/qml/AMDPMFreqOdForm.qml000066400000000000000000000042061467225065400204140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_FREQ_OD { id: pmFreqOd objectName: "AMD_PM_FREQ_OD" width: contents.width height: contents.height onSclkOdChanged: value => sclkOd.value = value onMclkOdChanged: value => mclkOd.value = value onSclkChanged: value => sclkFreq.text = value; onMclkChanged: value => mclkFreq.text = value; TextMetrics { id: freqTFMetrics text: "0000 MHz" } TextMetrics { id: odTFMetrics text: "+ 00 %" } Pane { id: contents padding: Style.g_padding ColumnLayout { spacing: 0 RowLayout { spacing: 8 Item { Layout.fillWidth: true } Label { text: qsTr("GPU") } Slider { id: sclkOd value: 0 from: 0 to: 20 stepSize: 1 onPressedChanged: pressed => { if (!pressed) pmFreqOd.changeSclkOd(sclkOd.value) } } Label { text: "+ " + sclkOd.value + " %" horizontalAlignment: Text.AlignRight Layout.preferredWidth: odTFMetrics.width } Label { id: sclkFreq horizontalAlignment: Text.AlignRight Layout.preferredWidth: freqTFMetrics.width } } RowLayout { spacing: 8 Item { Layout.fillWidth: true } Label { text: qsTr("Memory") } Slider { id: mclkOd value: 0 from: 0 to: 20 stepSize: 1 onPressedChanged: pressed => { if (!pressed) pmFreqOd.changeMclkOd(mclkOd.value) } } Label { text: "+ " + mclkOd.value + " %" horizontalAlignment: Text.AlignRight Layout.preferredWidth: odTFMetrics.width } Label { id: mclkFreq horizontalAlignment: Text.AlignRight Layout.preferredWidth: freqTFMetrics.width } } } } } corectrl-v1.4.2/src/qml/AMDPMFreqRangeForm.qml000066400000000000000000000017101467225065400211030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 AMD_PM_FREQ_RANGE { id: pmFreqRange objectName: "AMD_PM_FREQ_RANGE" width: contents.width height: contents.height onControlLabelChanged: label => freqState.title = label onStateRangeChanged: (min, max) => { p.min = min p.max = max freqState.setFreqRange(min, max) } onStatesChanged: states => freqState.setFStates(states, p.min, p.max) onStateChanged: (index, freq) => freqState.updateFState(index, freq) QtObject { id: p property int min: 0 property int max: 0 } Pane { id: contents padding: 0 RowLayout { FreqStateControl { id: freqState Layout.fillHeight: true onStateChanged: (index, freq) => pmFreqRange.changeState(index, freq) } } } } corectrl-v1.4.2/src/qml/AMDPMFreqVoltForm.qml000066400000000000000000000032131467225065400207730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 AMD_PM_FREQ_VOLT { id: pmFreqVolt objectName: "AMD_PM_FREQ_VOLT" width: contents.width height: contents.height onControlLabelChanged: label => fv.title = label onVoltRangeChanged: (min, max) => { p.voltMin = min p.voltMax = max fv.setVoltRange(min, max) } onFreqRangeChanged: (min, max) => { p.freqMin = min p.freqMax = max fv.setFreqRange(min, max) } onVoltModeChanged: mode => fv.voltManual = mode === "manual" onStatesChanged: states => fv.setFVStates(states, p.activeStates, p.freqMin, p.freqMax, p.voltMin, p.voltMax) onStateChanged: (index, freq, volt) => fv.updateFVState(index, freq, volt) onActiveStatesChanged: states => { p.activeStates.length = 0 p.activeStates = states fv.activeStates(states) } QtObject { id: p property int freqMin: 0 property int freqMax: 0 property int voltMin: 0 property int voltMax: 0 property var activeStates: [] } Pane { id: contents padding: 0 RowLayout { FVControl { id: fv Layout.fillHeight: true onVoltManualChanged: pmFreqVolt.changeVoltMode(voltManual ? "manual" : "auto") onStateChanged: (index, freq, volt) => pmFreqVolt.changeState(index, freq, volt) onActiveStateChanged: (index, active) => pmFreqVolt.changeActiveState(index, active) } } } } corectrl-v1.4.2/src/qml/AMDPMOverclockForm.qml000066400000000000000000000013111467225065400211550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import CoreCtrl.UIComponents 1.0 AMD_PM_OVERCLOCK { id: pmOclk objectName: "AMD_PM_OVERCLOCK" width: controls.width height: controls.height Pane { id: controls padding: 0 Column { objectName: "AMD_PM_OVERCLOCK_Plug" property var childrenAdded: [] onChildrenChanged: { for (var i = 0; i < children.length; ++i) { if (childrenAdded[children[i]] === undefined) { childrenAdded[children[i]] = children[i] pmOclk.setupChild(children[i]) } } } } } } corectrl-v1.4.2/src/qml/AMDPMOverdriveForm.qml000066400000000000000000000014121467225065400211750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_OVERDRIVE { id: pmOverdrive objectName: "AMD_PM_OVERDRIVE" width: controls.width height: controls.height Pane { id: controls padding: Style.g_padding Row { objectName: "AMD_PM_OVERDRIVE_Plug" spacing: 5 property var childrenAdded: [] onChildrenChanged: { for (var i = 0; i < children.length; ++i) { if (childrenAdded[children[i]] === undefined) { childrenAdded[children[i]] = children[i] pmOverdrive.setupChild(children[i]) } } } } } } corectrl-v1.4.2/src/qml/AMDPMPerfModeForm.qml000066400000000000000000000011641467225065400207350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_PM_PERFMODE { id: pMode objectName: "AMD_PM_PERFMODE" width: modeSelector.width height: modeSelector.height onModesChanged: modes => modeSelector.setModes(modes) onModeChanged: mode => modeSelector.select(mode) ModeSelector { id: modeSelector headerTitle: qsTr("Performance mode") contentParentObject: "AMD_PM_PERFMODE_Plug" onSelectionChanged: mode => pMode.changeMode(mode) onChildAdded: child => pMode.setupChild(child) } } corectrl-v1.4.2/src/qml/AMDPMPowerCapForm.qml000066400000000000000000000023131467225065400207510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_POWERCAP { id: powerCap objectName: "AMD_PM_POWERCAP" width: contents.width height: contents.height onValueChanged: value => { powerValue.value = value valueInput.value = value } onRangeChanged: (min, max) => { powerValue.from = min powerValue.to = max } TextMetrics { id: tFMetrics text: "999" } Pane { id: contents padding: Style.g_padding RowLayout { Label { text: qsTr("Power limit") + " (W)" } Slider { id: powerValue from: 0 to: 0 stepSize: 1 onPressedChanged: pressed => { if (!pressed) powerCap.changeValue(powerValue.value) } onMoved: valueInput.value = value } CIntInput { id: valueInput Layout.preferredWidth: tFMetrics.width + padding * 2 minValue: powerValue.from maxValue: powerValue.to onValueChanged: powerCap.changeValue(value) } } } } corectrl-v1.4.2/src/qml/AMDPMPowerProfileForm.qml000066400000000000000000000027461467225065400216600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_POWER_PROFILE { id: pmPowerProfile objectName: "AMD_PM_POWER_PROFILE" width: contents.width height: contents.height onModeChanged: mode => { for (var i = 0; i < listModel.count; ++i) { if (listModel.get(i).mode === mode) { cbMode.lastIndex = i cbMode.currentIndex = i break; } } } onModesChanged: modes => { listModel.clear() for (var i = 0; i < modes.length; i+=2) { var element = listElement.createObject() element.mode = modes[i] element.text = modes[i + 1] listModel.append(element) } cbMode.updateWidth() } ListModel { id: listModel } Component { id: listElement ListElement { property string text property string mode } } Pane { id: contents padding: Style.g_padding RowLayout { Label { text: qsTr("Power profile") rightPadding: 6 } CComboBox { id: cbMode model: listModel property int lastIndex: 0 onActivated: { if (lastIndex !== currentIndex) { lastIndex = currentIndex var mode = model.get(currentIndex).mode pmPowerProfile.changeMode(mode) } } } } } } corectrl-v1.4.2/src/qml/AMDPMPowerStateForm.qml000066400000000000000000000025141467225065400213310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_POWERSTATE { id: pmPowerState objectName: "AMD_PM_POWERSTATE" width: contents.width height: contents.height Component { id: modeButton Button { property string mode; checkable: true; } } onModesChanged: modes => { for (var i = 0; i < modes.length; i+=2) { var button = modeButton.createObject(btnContainer); button.mode = modes[i] button.text = modes[i + 1] } btnContainer.forceLayout() } onModeChanged: mode => { var buttons = btnContainer.children for (var i = 0; i < buttons.length; i++) { if (buttons[i].mode === mode) { buttons[i].checked = true btnGroup.lastChecked = buttons[i] break; } } } ButtonGroup { id: btnGroup property var lastChecked buttons: btnContainer.children onClicked: button => { if (lastChecked !== button) { lastChecked = button pmPowerState.changeMode(button.mode) } } } Pane { id: contents padding: Style.g_padding Row { id: btnContainer spacing: 8 } } } corectrl-v1.4.2/src/qml/AMDPMPowerStateModeForm.qml000066400000000000000000000012351467225065400221350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 AMD_PM_POWERSTATE_MODE { id: pStateMode objectName: "AMD_PM_POWERSTATE_MODE" width: modeSelector.width height: modeSelector.height onModesChanged: modes => modeSelector.setModes(modes) onModeChanged: mode => modeSelector.select(mode) ModeSelector { id: modeSelector headerTitle: qsTr("Power management mode") contentParentObject: "AMD_PM_POWERSTATE_MODE_Plug" onSelectionChanged: mode => pStateMode.changeMode(mode) onChildAdded: child => pStateMode.setupChild(child) } } corectrl-v1.4.2/src/qml/AMDPMVoltCurveForm.qml000066400000000000000000000042341467225065400211660ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_VOLT_CURVE { id: pmVoltCurve objectName: "AMD_PM_VOLT_CURVE" width: contents.width height: contents.height onModeChanged: mode => modeSw.checked = mode === "manual" onPointsRangeChanged: (freqMin, freqMax, voltMin, voltMax) => { voltCurve.configureAxes(qsTr("Frequency"), "MHz", freqMin, freqMax, qsTr("Voltage"), "mV", voltMin, voltMax) } onPointsChanged: points => { voltCurve.removeCurve("volt") voltCurve.addCurve("volt", Material.accent, points) } Pane { id: contents padding: 0 anchors.fill: parent RowLayout { anchors.fill: parent Pane { Layout.fillHeight: true padding: Style.g_padding background: Rectangle { border.color: Style.FVControl.border_color border.width: 2 color: "#00000000" } ColumnLayout { anchors.fill: parent RowLayout { Label { text: qsTr("Voltage") font.pointSize: 11 font.bold: true } Item { implicitWidth: modeSw.width / (1 + Style.g_tweakScale) Switch { id: modeSw scale: Style.g_tweakScale anchors.centerIn: parent onToggled: pmVoltCurve.changeMode(checked ? "manual" : "auto") } } Item { Layout.fillWidth: true } } CurveControl { id: voltCurve Layout.fillHeight: true minXDistance: 5 xTickCount: 3 xMinorTickCount: 1 yTickCount: 3 yMinorTickCount: 1 width: 400 height: 299 enabled: modeSw.checked onCurveChanged: (name, oldPoint, newPoint) => pmVoltCurve.updatePoint(oldPoint, newPoint) } } } } } } corectrl-v1.4.2/src/qml/AMDPMVoltOffsetForm.qml000066400000000000000000000054711467225065400213340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls.Material 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style AMD_PM_VOLT_OFFSET { id: pmVoltOffset objectName: "AMD_PM_VOLT_OFFSET" width: contents.width height: contents.height onValueChanged: value => offsetSld.value = value onRangeChanged: (min, max) => { offsetSld.from = min offsetSld.to = max } Pane { id: contents padding: Style.g_padding background: Rectangle { border.color: Style.FVControl.border_color border.width: 2 color: "#00000000" } TextMetrics { id: tFMetrics text: "-000" } GridLayout { columns: 2 anchors.fill: parent RowLayout { Layout.columnSpan: 2 Label { id: title text: qsTr("Voltage") font.pointSize: 11 font.bold: true } Item { Layout.fillWidth: true } Item { visible: offsetSld.value > 0 implicitWidth: warningIcn.width implicitHeight: warningIcn.height ToolTip.text: qsTr("WARNING: Operating range not available. Use with caution!") ToolTip.visible: ma.containsMouse MouseArea { id: ma anchors.fill: parent hoverEnabled: true } Image { id: warningIcn source: "qrc:/images/WarningIcon" anchors.fill: parent fillMode: Image.PreserveAspectFit width: Style.g_icon.small_size height: Style.g_icon.small_size sourceSize.width: Style.g_icon.size } } } Pane { padding: Style.FVControl.inner_padding bottomPadding: 0 Layout.columnSpan: 2 ColumnLayout { Layout.fillWidth: true Label { text: qsTr("OFFSET") Layout.alignment: Qt.AlignHCenter } Label { text: "mV" font.pointSize: 8 Layout.alignment: Qt.AlignHCenter } Slider { id: offsetSld Layout.alignment: Qt.AlignHCenter orientation: Qt.Vertical stepSize: 1 onPressedChanged: pressed => { if (!pressed) pmVoltOffset.changeValue(value) } } CIntInput { value: offsetSld.value minValue: offsetSld.from maxValue: offsetSld.to Layout.preferredWidth: tFMetrics.width + padding * 2 Layout.alignment: Qt.AlignHCenter onValueChanged: pmVoltOffset.changeValue(value) } } } } } } corectrl-v1.4.2/src/qml/About.qml000066400000000000000000000036731467225065400167120ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Pane { ColumnLayout { spacing: 20 RowLayout { spacing: 20 Image { source: "qrc:/images/AppIcon" fillMode: Image.PreserveAspectFit width: 128 height: 128 sourceSize.width: 128 } ColumnLayout { Item { Layout.fillHeight: true } Label { text: appInfo.name font.pointSize: Style.g_text.size + 5 font.bold: true } Label { text: appInfo.version font.pointSize: Style.g_text.size + 2 } Label { text: qsTr("Control your hardware with ease using application profiles") font.pointSize: Style.g_text.size + 1 } Label { text: qsTr("by") + " Juan Palacios" font.bold: true } } ColumnLayout { Item { Layout.fillHeight: true } Label { text: qsTr("Links") + ": " font.pointSize: Style.g_text.size + 1 onLinkActivated: Qt.openUrlExternally(link) MouseArea { anchors.fill: parent acceptedButtons: Qt.NoButton cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } } } } } } corectrl-v1.4.2/src/qml/CComboBox.qml000066400000000000000000000013641467225065400174460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import "Style.js" as Style ComboBox { id: comboBox textRole: 'text' implicitWidth: modelWidth + rightPadding + leftPadding Material.elevation: Style.Material.elevation wheelEnabled: true property real modelWidth function updateWidth() { modelWidth = 0; for (var i = 0; i < model.count; i++) { metrics.text = model.get(i).text modelWidth = Math.max(metrics.width, modelWidth) } metrics.text = "##" // add extra space for the ComboBox decoration modelWidth += metrics.width } TextMetrics { id: metrics } } corectrl-v1.4.2/src/qml/CGroupBox.qml000066400000000000000000000013051467225065400174760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import "Style.js" as Style GroupBox { id: control property alias showLine: bg.visible label: Label { text: control.title font.pointSize: Style.GroupBox.text_size font.bold: Style.GroupBox.text_bold width: control.width horizontalAlignment: Text.AlignHCenter y: control.padding / 2 } background: Rectangle { id: bg color: Style.GroupBox.bg_color border.color: enabled ? Style.GroupBox.bg_border_color : Style.GroupBox.bg_border_color_alt radius: Style.GroupBox.bg_radius } } corectrl-v1.4.2/src/qml/CIntInput.qml000066400000000000000000000042061467225065400175060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQml 2.15 import "Style.js" as Style TextField { property int value: 0 property alias minValue: range.bottom property alias maxValue: range.top text: value hoverEnabled: Style.g_hover selectByMouse: true padding: Style.TextField.padding horizontalAlignment: TextInput.AlignHCenter validator: IntValidator { id: range bottom: 0 top: 0 } onEditingFinished: { var newValue = parseInt(text) if (newValue !== value) p.updateValue(newValue) } QtObject { id: p property bool restoreTextRequest: false property string newText: "" property bool updateValueRequest: false property int newValue: 0 function restoreText(text) { newText = text restoreTextRequest = true restoreTextRequest = false } function updateValue(value) { newValue = value updateValueRequest = true updateValueRequest = false } function validateInput() { if (!(text && text.length > 0)) { restoreText(value) } else { var newValue = parseInt(text) if (newValue < range.bottom) { if (value !== range.bottom) updateValue(range.bottom) else restoreText(value) } else if (newValue > range.top) { if (value !== range.top) updateValue(range.top) else restoreText(value) } } } } Binding on value { when: p.updateValueRequest value: p.newValue restoreMode: Binding.RestoreBinding } Binding on text { when: p.restoreTextRequest value: p.newText restoreMode: Binding.RestoreBinding } Keys.onPressed: event => { if (event.key === Qt.Key_Tab || event.key === Qt.Key_Enter || event.key === Qt.Key_Return) p.validateInput() else if (event.key === Qt.Key_Escape) p.restoreText(value) } onFocusChanged: { if (!activeFocus) p.validateInput() } } corectrl-v1.4.2/src/qml/CPUForm.qml000066400000000000000000000053301467225065400171030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style import "Settings.js" as Settings CPU { id: cpu objectName: "CPU" onNewGraphItem: item => { sensorGraph.addItem(item) Settings.addComponentData("CPU" + cpu.physicalId, "CPU " + cpu.physicalId, item.name, qsTranslate("SensorGraph", item.name)) } Connections { target: settings function onSettingChanged(key, value) { if (key === "Workarounds/ignoredSensors") { var sensors = Settings.componentIgnoredSensors("CPU" + cpu.physicalId, value) sensorGraph.ignoredSensors(sensors) } else if (key === "UI/splitview-sysmodel-sensorgraph-height") { sensorGraph.SplitView.preferredHeight = value } } } SplitView { spacing: 0 anchors.fill: parent orientation: Qt.Vertical onResizingChanged: { if (!resizing) { settings.setValue("UI/splitview-sysmodel-sensorgraph-height", sensorGraph.SplitView.preferredHeight) } } SensorGraph { id: sensorGraph } Pane { padding: 0 SplitView.fillHeight: true ScrollView { id: scrollview anchors.fill: parent clip: true ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.horizontal.visible: ScrollBar.horizontal.size < 1 ScrollBar.vertical.visible: ScrollBar.vertical.size < 1 Flow { id: flow objectName: "CPU_Plug" width: scrollview.availableWidth height: scrollview.availableHeight spacing: Style.Controls.items_spacing property var childrenAdded: [] onChildrenChanged: { for (var i = 0; i < children.length; ++i) if (childrenAdded[children[i].objectName] === undefined) { childrenAdded[children[i].objectName] = children[i] cpu.setupChild(children[i]) } } move: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad } } } Component.onCompleted: { // BUG Scroll on control views does not work. // ScrollView will interfere with any children that uses MouseArea. // This stops that behaviour, but also disables scroll on the ScrollView. scrollview.contentItem.interactive = false } } } } } corectrl-v1.4.2/src/qml/CPUFreqForm.qml000066400000000000000000000063251467225065400177260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style CPU_CPUFREQ { id: cpuFreq objectName: "CPU_CPUFREQ" width: contents.width height: contents.height onScalingGovernorsChanged: governors => { scalingGovernorListModel.clear() for (var i = 0; i < governors.length; i+=2) { var element = scalingGovernorListElement.createObject() element.governor= governors[i] element.text = governors[i + 1] scalingGovernorListModel.append(element) } cbScalingGovernor.updateWidth() } onScalingGovernorChanged: governor => { for (var i = 0; i < scalingGovernorListModel.count; ++i) { if (scalingGovernorListModel.get(i).governor === governor) { cbScalingGovernor.lastIndex = i cbScalingGovernor.currentIndex = i break; } } } onEppHintsChanged: hints => { eppHintListModel.clear() for (var i = 0; i < hints.length; i+=2) { var element = eppHintListElement.createObject() element.hint = hints[i] element.text = hints[i + 1] eppHintListModel.append(element) } cbEppHint.updateWidth() } onEppHintChanged: hint => { for (var i = 0; i < eppHintListModel.count; ++i) { if (eppHintListModel.get(i).hint === hint) { cbEppHint.lastIndex = i cbEppHint.currentIndex = i break; } } } onToggleEppHint: enable => { lbEppHint.visible = enable cbEppHint.visible = enable } ListModel { id: scalingGovernorListModel } Component { id: scalingGovernorListElement ListElement { property string text property string governor } } ListModel { id: eppHintListModel } Component { id: eppHintListElement ListElement { property string text property string hint } } Pane { id: contents padding: Style.g_padding GridLayout { columns: 2 columnSpacing: 10 Label { text: qsTr("Frequency governor") Layout.alignment: Qt.AlignRight } CComboBox { id: cbScalingGovernor model: scalingGovernorListModel Layout.alignment: Qt.AlignLeft Layout.fillWidth: true property int lastIndex: 0 onActivated: { if (lastIndex !== currentIndex) { lastIndex = currentIndex var governor = model.get(currentIndex).governor cpuFreq.changeScalingGovernor(governor) } } } Label { id: lbEppHint text: qsTr("Energy Performance Preference") Layout.alignment: Qt.AlignRight visible: false } CComboBox { id: cbEppHint model: eppHintListModel Layout.alignment: Qt.AlignLeft Layout.fillWidth: true visible: false property int lastIndex: 0 onActivated: { if (lastIndex !== currentIndex) { lastIndex = currentIndex var hint = model.get(currentIndex).hint cpuFreq.changeEPPHint(hint) } } } } } } corectrl-v1.4.2/src/qml/CPUFreqModeForm.qml000066400000000000000000000012141467225065400205230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import CoreCtrl.UIComponents 1.0 CPU_CPUFREQ_MODE { id: cpuFreqMode objectName: "CPU_CPUFREQ_MODE" width: modeSelector.width height: modeSelector.height onModesChanged: modes => modeSelector.setModes(modes) onModeChanged: mode => modeSelector.select(mode) ModeSelector { id: modeSelector headerTitle: qsTr("Performance scaling") contentParentObject: "CPU_CPUFREQ_MODE_Plug" onSelectionChanged: mode => cpuFreqMode.changeMode(mode) onChildAdded: child => cpuFreqMode.setupChild(child) } } corectrl-v1.4.2/src/qml/CurveControl.qml000066400000000000000000000314221467225065400202560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtCharts 2.15 import "Style.js" as Style ChartView { property real minXDistance: 1.0 property bool clampPointsYCoordinate: false property alias xTickCount: xAxis.tickCount property alias xMinorTickCount: xAxis.minorTickCount property alias yTickCount: yAxis.tickCount property alias yMinorTickCount: yAxis.minorTickCount id: chart antialiasing: true legend.visible: false backgroundColor: "#00000000" margins.top: 0 margins.bottom: 0 margins.left: 0 margins.right: 0 axes: [ValueAxis { id: xAxis labelFormat: Style.CurveControl.axis_label_format minorGridVisible: true minorTickCount: 1 tickCount: 5 } , ValueAxis { id: yAxis labelFormat: Style.CurveControl.axis_label_format minorGridVisible: true minorTickCount: 1 tickCount: 3 } ] signal curveChanged(var name, var oldPoint, var newPoint) function configureAxes(xName, xUnit, xMin, xMax, yName, yUnit, yMin, yMax) { p.setAxisRange(xMin, xMax, yMin, yMax) p.setAxisTitleData(xName, yName, xUnit, yUnit) p.refreshAxes(enabled) // update outer range curve points for (var curveName in p.lineSeries) { var series = p.lineSeries[curveName] var oldFirst = series.at(0) var oldLast = series.at(series.count - 1) series.replace(oldFirst.x, oldFirst.y, p.lineFirstX, oldFirst.y) series.replace(oldLast.x, oldLast.y, p.lineLastX, oldLast.y) } } function addCurve(name, color, points) { if (p.lineSeries[name] === undefined) { var line = p.createLineSeries(name, color, points) p.lineSeries[name] = line // recreate control series, so control points are always on top var controlColors = p.controlColors() var controlPoints = p.controlPoints() for (var key in controlPoints) { chart.removeSeries(p.controlSeries[key]) p.controlSeries[key] = p.createControlSeries(name, controlColors[key], controlPoints[key]) } p.controlSeries[name] = p.createControlSeries(name, color, points) } } function removeCurve(name) { var line = p.lineSeries[name] if (line !== undefined) { var control = p.controlSeries[name] chart.removeSeries(line) chart.removeSeries(control) delete p.lineSeries[name] delete p.controlSeries[name] } } onEnabledChanged: enabled => p.onEnableChanged(enabled) QtObject { // private stuff id: p property var lineSeries: [] property var controlSeries: [] property string selectedCurve property var selectedPoint: undefined property int selectedPointIndex: -1 property real prevX: 0 property real nextX: 0 property string xName: "" property string xUnit: "" property string yName: "" property string yUnit: "" property real xMin: 0 property real xMax: 1 property real yMin: 0 property real yMax: 1 property real lineFirstX: xMin - 1 property real lineLastX: xMax + 1 function createLineSeries(name, color, points) { var series = chart.createSeries(ChartView.SeriesTypeLine, name, xAxis, yAxis) series.name = name series.color = color series.opacity = chart.enabled ? Style.CurveControl.curve_opacity : Style.CurveControl.curve_opacity_alt series.width = 2 // line first outer range point series.append(p.lineFirstX, points[0].y) for (var i = 0; i < points.length; ++i) series.append(points[i].x, points[i].y) // line last outer range point series.append(p.lineLastX, points[points.length - 1].y) return series } function createControlSeries(name, color, points) { var series = chart.createSeries(ChartView.SeriesTypeScatter, name, xAxis, yAxis) series.name = name series.color = color series.opacity = chart.enabled ? Style.CurveControl.curve_opacity : Style.CurveControl.curve_opacity_alt series.borderColor = color series.markerSize = 10 series.borderWidth = 0 for (var i = 0; i < points.length; ++i) series.append(points[i].x, points[i].y) return series } function onEnableChanged(enabled) { refreshAxes(enabled) // series opactity var opacity = enabled ? Style.CurveControl.curve_opacity : Style.CurveControl.curve_opacity_alt for (var curveName in lineSeries) { var lseries = lineSeries[curveName] lseries.opacity = opacity var cseries = controlSeries[curveName] cseries.opacity = opacity } } function controlPoints() { var controlPoints = [] for (var key in controlSeries) { var series = controlSeries[key] var points = [] for (var i = 0; i < series.count; ++i) points.push(series.at(i)) controlPoints[key] = points } return controlPoints } function controlColors() { var controlColors = [] for (var key in controlSeries) { var series = controlSeries[key] controlColors[key] = series.color } return controlColors } function hasSeries() { for (var key in lineSeries) return true return false } function hasSelection() { return selectedPoint !== undefined } function mapToChart(point) { for (var key in controlSeries) return chart.mapToValue(point, controlSeries[key]) } function setAxisRange(xMin, xMax, yMin, yMax) { xAxis.min = xMin xAxis.max = xMax yAxis.min = yMin yAxis.max = yMax this.xMin = xMin; this.xMax = xMax; this.yMin = yMin; this.yMax = yMax; } function setAxisTitleData(xName, yName, xUnit, yUnit) { this.xName = xName; this.yName = yName; this.xUnit = xUnit this.yUnit = yUnit } function refreshAxes(enabled) { xAxis.titleText = "" + xName + " (" + xUnit + ")" xAxis.labelsColor = enabled ? Style.CurveControl.axis_label_color : Style.CurveControl.axis_label_color_alt xAxis.color = enabled ? Style.CurveControl.axis_color : Style.CurveControl.axis_color_alt xAxis.gridLineColor = enabled ? Style.CurveControl.axis_grid_color : Style.CurveControl.axis_grid_color_alt xAxis.minorGridLineColor = enabled ? Style.CurveControl.axis_grid_minor_color : Style.CurveControl.axis_grid_minor_color_alt yAxis.titleText = "" + yName + " (" + yUnit + ")" yAxis.labelsColor = enabled ? Style.CurveControl.axis_label_color : Style.CurveControl.axis_label_color_alt yAxis.color = enabled ? Style.CurveControl.axis_color : Style.CurveControl.axis_color_alt yAxis.gridLineColor = enabled ? Style.CurveControl.axis_grid_color : Style.CurveControl.axis_grid_color_alt yAxis.minorGridLineColor = enabled ? Style.CurveControl.axis_grid_minor_color : Style.CurveControl.axis_grid_minor_color_alt } function updateGraphPoint(oldPoint, newPoint) { lineSeries[selectedCurve].replace(oldPoint.x, oldPoint.y, newPoint.x, newPoint.y) controlSeries[selectedCurve].replace(oldPoint.x, oldPoint.y, newPoint.x, newPoint.y) } function updateOuterRangePoints(oldY, newY) { if (selectedPointIndex == 0) lineSeries[selectedCurve].replace(lineFirstX, oldY, lineFirstX, newY) if (selectedPointIndex == controlSeries[selectedCurve].count - 1) lineSeries[selectedCurve].replace(lineLastX, oldY, lineLastX, newY) } function moveSelection(point) { // clamp point coordinates to axes range point.x = Math.min(Math.max(point.x, xMin), xMax) point.y = Math.min(Math.max(point.y, yMin), yMax) // limit x movement between points using minXDistance if (selectedPointIndex > 0) point.x = Math.max(point.x, prevX + minXDistance) if (selectedPointIndex < controlSeries[selectedCurve].count - 1) point.x = Math.min(point.x, nextX - minXDistance) if (clampPointsYCoordinate) clampOtherPointsYCoordinate() updateGraphPoint(selectedPoint, point) updateOuterRangePoints(selectedPoint.y, point.y) // emit curveChanged signal curveChanged(selectedCurve, selectedPoint, point) selectedPoint = point return point } function clampOtherPointsYCoordinate() { var series = controlSeries[selectedCurve] for (var i = 0; i < series.count; ++i) { // skip selected point if (selectedPointIndex == i) continue var point = series.at(i) if ((i < selectedPointIndex && point.y > selectedPoint.y) || (i > selectedPointIndex && point.y < selectedPoint.y)) { point.y = selectedPoint.y var oldPoint = series.at(i) updateGraphPoint(oldPoint, point) curveChanged(selectedCurve, oldPoint, point) } } } function findCloserIndex(series, target) { var distRange = (xAxis.max - xAxis.min) / 20 var closerPointIndex = -1 var minDist = 10000 for (var i = 0; i < series.count; ++i) { var point = series.at(i) var distance = Math.sqrt(Math.pow(point.x - target.x, 2) + Math.pow(point.y - target.y, 2)) if (distance < minDist && distance < distRange) { minDist = distance closerPointIndex = i } } return closerPointIndex } function selectCloser(point) { // pick the first closer point in controls for (var key in controlSeries) { var control = controlSeries[key] selectedPointIndex = findCloserIndex(control, point) if (selectedPointIndex != -1) break } if (selectedPointIndex != -1) { selectedPoint = control.at(selectedPointIndex) // find point's curve var curveFound = false for (var curveName in lineSeries) { var series = lineSeries[curveName] for (var i = 0; i < series.count; ++i) { if (series.at(i) === selectedPoint) { curveFound = true break } } if (curveFound) { selectedCurve = curveName break } } if (selectedPointIndex > 0) prevX = control.at(selectedPointIndex - 1).x if (selectedPointIndex < control.count - 1) nextX = control.at(selectedPointIndex + 1).x } else { deselect() } return selectedPoint } function deselect() { selectedPoint = undefined selectedPointIndex = -1 selectedCurve = "" } } ToolTip { id: tooltip delay: 0 timeout: -1 margins: -1 function updatePosition(x, y) { x = Math.max(0, Math.min(x, Math.round(parent.width - width))) y = Math.max(0, Math.min(y + 25, Math.round(parent.height - height))) tooltip.x = x tooltip.y = y } } MouseArea { id: mouseArea anchors.fill: parent onPressed: mouse => { if (p.hasSeries()) { var outerPoint = p.mapToChart(Qt.point(mouse.x, mouse.y)) var point = p.selectCloser(outerPoint) // update tooltip if (point !== undefined) { tooltip.updatePosition(mouse.x, mouse.y) tooltip.text = Math.round(point.x) + p.xUnit + " " + Math.round(point.y) + p.yUnit tooltip.visible = true } } } onReleased: mouse => { if (p.hasSeries()) { p.deselect() tooltip.visible = false } } onPositionChanged: mouse => { if (p.hasSeries() && p.hasSelection()) { var point = p.mapToChart(Qt.point(mouse.x, mouse.y)) point = p.moveSelection(point) // update tooltip tooltip.updatePosition(mouse.x, mouse.y) tooltip.text = Math.round(point.x) + p.xUnit + " " + Math.round(point.y) + p.yUnit } } } } corectrl-v1.4.2/src/qml/FVControl.qml000066400000000000000000000130431467225065400175040ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Pane { id: control padding: Style.g_padding background: Rectangle { border.color: Style.FVControl.border_color border.width: 2 color: "#00000000" } property alias title: title.text property alias voltManual: manualVolt.checked signal activeStateChanged(int index, bool active) signal stateChanged(int index, int freq, int volt) function setFVStates(states, activeStates, freqMin, freqMax, voltMin, voltMax) { stateModel.clear() for (var i = 0; i < states.length; i += 3) { var activeState = false for (var j = 0; j < activeStates.length; ++j) if (activeStates[j] === states[i]) { activeState = true break } stateModel.append({"_index": states[i], "_active": activeState, "_freq": states[i + 1], "_freqMin": freqMin, "_freqMax": freqMax, "_volt": states[i + 2], "_voltMin": voltMin, "_voltMax": voltMax}) } } function updateFVState(index, freq, volt) { for (var i = 0; i < stateModel.count; ++i) { if (stateModel.get(i)._index === index) { stateModel.set(i, {"_freq": freq, "_volt": volt}) break } } } function setFreqRange(min, max) { for (var i = 0; i < stateModel.count; ++i) stateModel.set(i, {"_freqMin": min, "_freqMax": max}) } function setVoltRange(min, max) { for (var i = 0; i < stateModel.count; ++i) stateModel.set(i, {"_voltMin": min, "_voltMax": max}) } function activeStates(indices) { if (indices.length > 0) { var activeStatesCount = 0; for (var i = 0; i < stateModel.count; ++i) { var stateIndex = stateModel.get(i)._index var activeState = false for (var j = 0; j < indices.length; ++j) if (indices[j] === stateIndex) { activeState = true ++activeStatesCount break } stateModel.set(i, {"_active": activeState}) } stateModel.activeStatesCount = activeStatesCount } } TextMetrics { id: tFMetrics text: "9999" } ListModel { id: stateModel property int activeStatesCount: 0 } Component { id: stateCtl ColumnLayout { Label { text: qsTr("STATE") + " " + _index enabled: stateCkb.checked Layout.alignment: Qt.AlignHCenter } CheckBox { id: stateCkb checked: _active enabled: stateModel.activeStatesCount === 1 && !checked || stateModel.activeStatesCount > 1 Layout.alignment: Qt.AlignHCenter scale: 0.75 topPadding: -1 bottomPadding: -1 onToggled: control.activeStateChanged(_index, checked) } Slider { id: stateFreqSld enabled: stateCkb.checked Layout.alignment: Qt.AlignHCenter orientation: Qt.Vertical value: _freq from: _freqMin to: _freqMax stepSize: 1 onPressedChanged: pressed => { if (!pressed) control.stateChanged(_index, value, _volt) } } CIntInput { value: stateFreqSld.value minValue: stateFreqSld.from maxValue: stateFreqSld.to enabled: stateCkb.checked Layout.preferredWidth: tFMetrics.width + padding * 2 Layout.alignment: Qt.AlignHCenter onValueChanged: control.stateChanged(_index, value, _volt) } CIntInput { value: _volt minValue: _voltMin maxValue: _voltMax enabled: stateCkb.checked visible: manualVolt.checked Layout.preferredWidth: tFMetrics.width + padding * 2 Layout.alignment: Qt.AlignHCenter onValueChanged: control.stateChanged(_index, _freq, value) } TextField { text: qsTr("Auto") enabled: false visible: !manualVolt.checked padding: Style.TextField.padding horizontalAlignment: TextInput.AlignHCenter Layout.preferredWidth: tFMetrics.width + padding * 2 Layout.alignment: Qt.AlignHCenter } } } ColumnLayout { anchors.fill: parent GridLayout { columns: 2 ColumnLayout { Layout.fillHeight: true Label { id: title font.pointSize: 11 font.bold: true } Item { Layout.fillHeight: true } Label { id: freqLbl text: qsTr("Frequency") + " (MHz)" Layout.alignment: Qt.AlignRight } Item { Layout.preferredHeight: 10 } ColumnLayout { Item { Layout.preferredHeight: 5 } RowLayout { Item { Layout.fillWidth: true } Item { implicitWidth: manualVolt.width / (1 + Style.g_tweakScale) Switch { id: manualVolt scale: Style.g_tweakScale anchors.centerIn: parent } } Label { text: qsTr("Voltage") + " (mV)" } } Item { Layout.preferredHeight: 10 } } } RowLayout { id: freqStates spacing: 15 Layout.fillWidth: true Repeater { model: stateModel delegate: stateCtl } } } } } corectrl-v1.4.2/src/qml/FreqStateControl.qml000066400000000000000000000057541467225065400211010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Pane { id: control padding: Style.g_padding background: Rectangle { border.color: Style.FVControl.border_color border.width: 2 color: "#00000000" } property alias title: title.text signal activeStateChanged(int index, bool active) signal stateChanged(int index, int freq) function setFStates(states, freqMin, freqMax) { stateModel.clear() for (var i = 0; i < states.length; i += 2) { stateModel.append({"_index": states[i], "_freq": states[i + 1], "_freqMin": freqMin, "_freqMax": freqMax}) } } function updateFState(index, freq) { for (var i = 0; i < stateModel.count; ++i) { if (stateModel.get(i)._index === index) { stateModel.set(i, {"_freq": freq}) break } } } function setFreqRange(min, max) { for (var i = 0; i < stateModel.count; ++i) stateModel.set(i, {"_freqMin": min, "_freqMax": max}) } TextMetrics { id: tFMetrics text: "9999" } ListModel { id: stateModel function getStateLabel(stateIndex) { if (stateIndex === 0) return qsTr("MINIMUM") else if (stateModel.count === 1 || stateIndex === stateModel.count - 1) return qsTr("MAXIMUM") else return qsTr("STATE") + " " + stateIndex } } Component { id: stateCtl ColumnLayout { Label { text: stateModel.getStateLabel(_index) Layout.alignment: Qt.AlignHCenter } Label { text: "MHz" font.pointSize: 8 Layout.alignment: Qt.AlignHCenter } Slider { id: stateFreqSld Layout.alignment: Qt.AlignHCenter orientation: Qt.Vertical value: _freq from: _freqMin to: _freqMax stepSize: 1 onPressedChanged: pressed => { if (!pressed) control.stateChanged(_index, value) } } CIntInput { value: stateFreqSld.value minValue: stateFreqSld.from maxValue: stateFreqSld.to Layout.preferredWidth: tFMetrics.width + padding * 2 Layout.alignment: Qt.AlignHCenter onValueChanged: control.stateChanged(_index, value) } } } ColumnLayout { anchors.fill: parent GridLayout { columns: 2 Label { id: title font.pointSize: 11 font.bold: true Layout.columnSpan: 2 } Pane { padding: Style.FVControl.inner_padding bottomPadding: 0 Layout.columnSpan: 2 RowLayout { id: freqStates spacing: 15 Layout.fillWidth: true Repeater { model: stateModel delegate: stateCtl } } } } } } corectrl-v1.4.2/src/qml/GPUForm.qml000066400000000000000000000053101467225065400171050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style import "Settings.js" as Settings GPU { id: gpu objectName: "GPU" onNewGraphItem: item => { sensorGraph.addItem(item) Settings.addComponentData("GPU" + gpu.index, "GPU " + gpu.index, item.name, qsTranslate("SensorGraph", item.name)) } Connections { target: settings function onSettingChanged(key, value) { if (key === "Workarounds/ignoredSensors") { var sensors = Settings.componentIgnoredSensors("GPU" + gpu.index, value) sensorGraph.ignoredSensors(sensors) } else if (key === "UI/splitview-sysmodel-sensorgraph-height") { sensorGraph.SplitView.preferredHeight = value } } } SplitView { spacing: 0 anchors.fill: parent orientation: Qt.Vertical onResizingChanged: { if (!resizing) { settings.setValue("UI/splitview-sysmodel-sensorgraph-height", sensorGraph.SplitView.preferredHeight) } } SensorGraph { id: sensorGraph } Pane { padding: 0 SplitView.fillHeight: true ScrollView { id: scrollview anchors.fill: parent clip: true ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.horizontal.visible: ScrollBar.horizontal.size < 1 ScrollBar.vertical.visible: ScrollBar.vertical.size < 1 Flow { id: flow objectName: "GPU_Plug" width: scrollview.availableWidth height: scrollview.availableHeight spacing: Style.Controls.items_spacing property var childrenAdded: [] onChildrenChanged: { for (var i = 0; i < children.length; ++i) if (childrenAdded[children[i].objectName] === undefined) { childrenAdded[children[i].objectName] = children[i] gpu.setupChild(children[i]) } } move: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad } } } Component.onCompleted: { // BUG Scroll on control views does not work. // ScrollView will interfere with any children that uses MouseArea. // This stops that behaviour, but also disables scroll on the ScrollView. scrollview.contentItem.interactive = false } } } } } corectrl-v1.4.2/src/qml/InfoPane.qml000066400000000000000000000040771467225065400173360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Pane { width: parent.width height: parent.height padding: 2 function addInfo(infoPairArray) { for (var i = 0; i < infoPairArray.length; i+=2) { infoModel.append({ "_title": infoPairArray[i], "_text": infoPairArray[i + 1]}) } } ListModel { id: infoModel } Component { id: infoUnit Pane { implicitWidth: 237 implicitHeight: 60 padding: Style.RectItem.padding background: Rectangle { color: hovered ? Style.RectItem.bg_color_hover : Style.RectItem.bg_color } ToolTip.delay: Style.ToolTip.delay ToolTip.timeout: Style.ToolTip.timeout ToolTip.visible: hovered ToolTip.text: title.text + ": " + info.text ColumnLayout { spacing: 4 anchors.fill: parent Label { id: title text: _title elide: Text.ElideRight color: Style.RectItem.text_color Layout.fillWidth: true } Label { id: info text: _text elide: Text.ElideRight color: Style.RectItem.text_color_alt Layout.fillWidth: true } } } } ScrollView { id: scrollview anchors.fill: parent clip: true ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.horizontal.visible: ScrollBar.horizontal.size < 1 ScrollBar.vertical.visible: ScrollBar.vertical.size < 1 Flow { id: flow width: scrollview.availableWidth height: scrollview.availableHeight spacing: Style.RectItemList.items_spacing Repeater { model: infoModel delegate: infoUnit } move: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad } } } } } corectrl-v1.4.2/src/qml/ModeSelector.qml000066400000000000000000000064221467225065400202200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Page { id: modeSelector property alias headerTitle: label.text property var headerBackground: Style.ModeSelector.header.bg_color property alias contentParentObject: contentsAnchor.objectName property var contentBackground: Style.ModeSelector.body.bg_color /// Fired when the selected mode changed. /// @param mode key of the new selected mode signal selectionChanged(string mode) /// Fired when a new child is added /// @param added child signal childAdded(var child) // Sets the modes of the selector. // @param modes array of elements where each pair of elements // corresponds to [mode_key, mode_text] for each [i, i+1] function setModes(modes) { listModel.clear() for (var i = 0; i < modes.length; i+=2) { var element = listElement.createObject() element.mode = modes[i] element.text = modes[i + 1] listModel.append(element) } cbMode.updateWidth() } /// Selects a mode. /// @param mode key of the mode to be selected function select(mode) { if (cbMode.currentMode !== mode) cbMode.setMode(mode) } ListModel { id: listModel } Component { id: listElement ListElement { property string text property string mode } } header: Pane { padding: Style.ModeSelector.header.padding Material.background: headerBackground RowLayout { Label { id: label rightPadding: 20 } CComboBox { id: cbMode model: listModel property string currentMode: "" function setMode(mode) { for (var i = 0; i < listModel.count; i++) { if (listModel.get(i).mode === mode) { var lastMode = currentMode currentMode = mode currentIndex = i contentsAnchor.toggleActive(lastMode, currentMode) break; } } } onActivated: { if (currentMode !== model.get(currentIndex).mode) { var lastMode = currentMode currentMode = model.get(currentIndex).mode contentsAnchor.toggleActive(lastMode, currentMode) } } } Rectangle { Layout.fillWidth: true } } } Pane { padding: 0 anchors.fill: parent Material.background: contentBackground Row { id: contentsAnchor anchors.centerIn: parent function toggleActive(from, to) { if (childrenAdded[from] !== undefined && childrenAdded[to] !== undefined) { childrenAdded[from].activate(false) } if (childrenAdded[to] !== undefined) { childrenAdded[to].activate(true) modeSelector.selectionChanged(to) } } property var childrenAdded: [] onChildrenChanged: { for (var i = 0; i < children.length; ++i) { if (childrenAdded[children[i].objectName] === undefined) { childrenAdded[children[i].objectName] = children[i] modeSelector.childAdded(children[i]) } } } } } } corectrl-v1.4.2/src/qml/NativeFileDialog.qml000066400000000000000000000011671467225065400210020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import Qt.labs.platform 1.1 // Native file dialog // Requires: // · link against Qt5::Widgets // · use QApplication instead QGuiApplication FileDialog { property bool saveDlg: false fileMode: saveDlg ? FileDialog.SaveFile : FileDialog.OpenFile folder: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0] options: FileDialog.ReadOnly /// Returns the selected file name. function fileName() { var path = file.toString() return path.slice(path.lastIndexOf("/") + 1) } } corectrl-v1.4.2/src/qml/NoopForm.qml000066400000000000000000000021011467225065400173600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style NOOP { objectName: "NOOP" width: contents.width height: contents.height Pane { id: contents padding: Style.g_padding RowLayout { anchors.fill: parent Item { Layout.rightMargin: Style.g_padding implicitWidth: warningIcn.width implicitHeight: warningIcn.height Image { id: warningIcn source: "qrc:/images/WarningIcon" fillMode: Image.PreserveAspectFit anchors.fill: parent width: Style.g_icon.size height: Style.g_icon.size sourceSize.width: Style.g_icon.source_size } } ColumnLayout { Label { text: qsTr("Warning!") font.pointSize: 12 font.bold: true } Label { text: qsTr("The component will not be controlled") } } } } } corectrl-v1.4.2/src/qml/ProfileButton.qml000066400000000000000000000101111467225065400204150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Pane { id: btn property alias label: btnText.text property string name: "" property alias icon : icn.source property string exe: "" property bool isGlobal: false property bool profileActivated: true property alias toggledManual: manualSwc.checked implicitWidth: 240 implicitHeight: 60 padding: 0 signal clicked() signal enableProfile(bool enable) signal toggleManualProfile(string name) signal edit() signal clone() signal exportTo() signal remove() ToolTip.delay: Style.ToolTip.delay ToolTip.timeout: Style.ToolTip.timeout ToolTip.visible: hovered ToolTip.text: label MouseArea { anchors.fill: parent propagateComposedEvents: true onClicked: mouse => btn.clicked() } background: Rectangle { color: btn.hovered ? Style.RectItem.bg_color_hover : btn.profileActivated ? Style.RectItem.bg_color : Style.RectItem.bg_color_alt } RowLayout { anchors.fill: parent spacing: 0 Item { Layout.fillHeight: true Layout.alignment: Qt.AlignLeft Layout.leftMargin: Style.RectItem.padding width: icn.width height: icn.height Image { id: icn cache: false anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: Style.g_icon.size height: Style.g_icon.size sourceSize.width: Style.g_icon.source_size } } Item { Layout.fillWidth: true Layout.fillHeight: true Layout.leftMargin: 10 Label { id: btnText width: parent.width anchors.centerIn: parent elide: Text.ElideRight wrapMode: Text.WordWrap color: btn.profileActivated ? Style.RectItem.text_color : Style.RectItem.text_color_alt onTextChanged: { if (parent.height > 0) { height = parent.height height = Math.min(contentHeight, height) } } onContentSizeChanged: { // set height dynamically, to obtain centered wrapped and unwrapped text if (parent.height > 0) height = Math.min(contentHeight, parent.height) } } } Item { Layout.fillHeight: true Layout.alignment: Qt.AlignRight implicitWidth: manualSwc.width / 3 Switch { id: manualSwc visible: exe.length == 0 padding: 0 rotation: -90 scale: Style.g_tweakScale anchors.centerIn: parent onToggled: btn.toggleManualProfile(name) } } Item { Layout.fillHeight: true Layout.alignment: Qt.AlignRight Layout.rightMargin: 0 implicitWidth: editBtn.width ToolButton { id: editBtn text: Style.g_icon.MENU; font.pointSize: Style.g_text.icon_size anchors.centerIn: parent onClicked: menu.open() Menu { id: menu MenuItem { text: btn.profileActivated ? qsTr("Disable") : qsTr("Enable") enabled: !isGlobal && exe.length > 0 hoverEnabled: Style.g_hover onTriggered: btn.enableProfile(!btn.profileActivated) } MenuItem { text: qsTr("Edit...") enabled: !isGlobal hoverEnabled: Style.g_hover onTriggered: btn.edit() } MenuItem { text: qsTr("Clone...") hoverEnabled: Style.g_hover onTriggered: btn.clone() } MenuItem { text: qsTr("Export to...") hoverEnabled: Style.g_hover onTriggered: btn.exportTo() } MenuSeparator {} MenuItem { text: qsTr("Remove") enabled: !isGlobal hoverEnabled: Style.g_hover onTriggered: btn.remove() } } } } } } corectrl-v1.4.2/src/qml/ProfileInfoDialog.qml000066400000000000000000000150301467225065400211620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Dialog { id: dlg property string name property string exe property url icon property url defaultIcon property bool hasCustomIcon property bool forceAutomaticActivation: false property var newInfoAction: function(name, exe, icon) {} signal updateProfileNameUsed(string profileName) property bool profileNameUsed: false signal updateExecutableNameUsed(string executableName) property bool executableNameUsed: false focus: true modal: true standardButtons: Dialog.Ok | Dialog.Cancel closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 QtObject { // private stuff id: p property url originalIcon property url selectedIcon property bool nameOK: false property bool exeOK: false property bool iconOK: false function validProfileName(name) { return name && name.trim().length > 0 } function validFileName(name) { return name && name.trim().length > 0 && !/\\|\/|\||\x00|\*|`|;|:|'|"/.test(name) } function validateName() { nameOK = activationCb.currentIndex === 0 ? validProfileName(name) : validFileName(name) return nameOK } function validateExe() { exeOK = activationCb.currentIndex === 0 ? validFileName(exe) : true return exeOK } function updateOKButtonState() { dlg.footer.standardButton(Dialog.Ok).enabled = nameOK && exeOK && iconOK } function resetState() { newInfoAction = function(name, exe, icon) {} originalIcon = "" selectedIcon = "" forceAutomaticActivation = false activationCb.currentIndex = -1 } } onAboutToShow: { activationCb.currentIndex = forceAutomaticActivation ? 0 : exe.length > 0 ? 0 : 1 customizeIconCb.checked = hasCustomIcon p.originalIcon = icon } onClosed: p.resetState() onAccepted: newInfoAction(dlg.name, activationCb.currentIndex === 0 ? dlg.exe : "", dlg.icon) onNameChanged: { if (name !== nameTf.text) nameTf.text = name if (p.validateName()) { updateProfileNameUsed(name) p.nameOK &= !profileNameUsed } p.updateOKButtonState() } onExeChanged: { if (exe !== exeTf.text) exeTf.text = exe if (p.validateExe()) { updateExecutableNameUsed(exe) p.exeOK &= !executableNameUsed } p.updateOKButtonState() } onIconChanged: { if (icon !== icnBtn.path) icnBtn.path = icon p.iconOK = icon.toString().length > 0 p.updateOKButtonState() } GridLayout { anchors.fill: parent columns: 2 columnSpacing: 10 Label { text: qsTr("Name:") Layout.alignment: Qt.AlignRight } TextField { id: nameTf Layout.alignment: Qt.AlignLeft selectByMouse: true hoverEnabled: Style.g_hover placeholderText: qsTr("Profile name") onTextEdited: dlg.name = text } Label { text: qsTr("Activation:") Layout.alignment: Qt.AlignRight } CComboBox { id: activationCb Layout.alignment: Qt.AlignLeft Layout.fillWidth: true hoverEnabled: Style.g_hover model: ListModel { ListElement { text: qsTr("Automatic") } ListElement { text: qsTr("Manual") } } onCurrentIndexChanged: { p.validateName() p.validateExe() p.updateOKButtonState() } } Label { text: qsTr("Executable:") Layout.alignment: Qt.AlignRight visible: activationCb.currentIndex === 0 } Row { visible: activationCb.currentIndex === 0 spacing: 5 TextField { id: exeTf selectByMouse: true hoverEnabled: Style.g_hover placeholderText: qsTr("Executable name") onTextEdited: dlg.exe = text } Button { text: Style.g_icon.MORE font.pointSize: Style.g_text.icon_size implicitWidth: 25 implicitHeight: 35 spacing: 0 padding: 0 hoverEnabled: Style.g_hover Material.elevation: Style.Material.elevation NativeFileDialog { id: exeFDialog title: qsTr("Select an executable file") onAccepted: { var fileName = exeFDialog.fileName() exeTf.text = fileName dlg.exe = fileName } } onClicked: exeFDialog.open() } } Label { text: qsTr("Icon:") Layout.alignment: Qt.AlignRight } Button { id: icnBtn Layout.alignment: Qt.AlignLeft enabled: customizeIconCb.checked property alias path: icnBtnImage.source hoverEnabled: Style.g_hover Material.elevation: Style.Material.elevation contentItem: Item { implicitWidth: icnBtnImage.width implicitHeight: icnBtnImage.height Image { id: icnBtnImage anchors.centerIn: parent fillMode: Image.PreserveAspectFit width: Style.g_icon.size height: Style.g_icon.size sourceSize.width: Style.g_icon.source_size } } NativeFileDialog { id: icnFDialog title: qsTr("Select an icon") nameFilters: [qsTr("Images") + "(*.png *.bmp *.jpg *.jpeg *.ico *.icns *.svg)"] onAccepted: { icnBtnImage.source = file dlg.icon = file p.selectedIcon = file } } onClicked: icnFDialog.open() } CheckBox { id: customizeIconCb Layout.alignment: Qt.AlignLeft Layout.row: activationCb.currentIndex === 0 ? 4 : 3 Layout.column: 1 text: qsTr("Customize icon") hoverEnabled: Style.g_hover leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 onToggled: { var customIcon = dlg.hasCustomIcon ? p.originalIcon : "" var customIconToShow = p.selectedIcon.toString().length > 0 ? p.selectedIcon : customIcon dlg.icon = checked ? customIconToShow : dlg.defaultIcon } } } Component.onCompleted: { p.resetState() p.updateOKButtonState() dlg.footer.standardButton(Dialog.Ok).hoverEnabled = Style.g_hover dlg.footer.standardButton(Dialog.Cancel).hoverEnabled = Style.g_hover } } corectrl-v1.4.2/src/qml/Profiles.qml000066400000000000000000000433601467225065400174200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style Page { hoverEnabled: Style.g_hover PROFILE_MANAGER { id: profileManager objectName: "PROFILE_MANAGER" onInitProfiles: profiles => p.initProfileButtons(profiles) onProfileAdded: (name, exe, icon, hasCustomIcon, isActive) => p.createProfileButton(name, exe, icon, hasCustomIcon, isActive) onProfileRemoved: name => p.removeProfileButton(name) onProfileSaved: name => p.updateToolBarButtonsOnProfileSaved() onProfileInfoChanged: (oldName, newName, exe, icon, hasCustomIcon, isActive) => p.updateProfileButton(oldName, newName, exe, icon, hasCustomIcon, isActive) onProfileChanged: name => p.updateProfileUIState(name) onProfileActiveChanged: (name, active) => p.updateProfileButtonActiveState(name, active); onManualProfileToggled: (name, active) => p.updateProfileButtonManualToggle(name, active); } QtObject { // private stuff id: p property bool restoringProfile: false property bool unappliedSettings: false property bool unsavedSettings: false property var editedProfileBtn: undefined function initProfileButtons(profiles) { for (var i = 0; i < profiles.length; i+=5) { var name = profiles[i] var exe = profiles[i+1] var icon = profiles[i+2] var isActive = profiles[i+3] var hasCustomIcon = profiles[i+4] var isGlobal = i === 0 profileModel.append({ "_label": isGlobal ? qsTranslate("ProfileManagerUI", name) : name, "_name": name, "_exe": exe, "_icon": icon, "_isGlobal": isGlobal, "_hasCustomIcon": hasCustomIcon, "_active": isActive, "_toggledManual": false }) } } function createProfileButton(name, exe, icon, hasCustomIcon, isActive) { profileModel.append({ "_label": name, "_name": name, "_exe": exe, "_icon": icon, "_isGlobal": false, "_hasCustomIcon": hasCustomIcon, "_active": isActive, "_toggledManual": false }) // move model element to the correct position for (var i = 1; i < profileModel.count; ++i) { if (name < profileModel.get(i)._name) { profileModel.move(profileModel.count - 1, i, 1) break } } } function removeProfileButton(name) { for (var i = 0; i < profileModel.count; ++i) { if (profileModel.get(i)._name === name) { profileModel.remove(i) break } } } function updateProfileButton(oldName, newName, exe, icon, hasCustomIcon, isActive) { // get model element old and new positions var from = -1 var to = profileModel.count for (var i = 1; i < profileModel.count; ++i) { var itemName = profileModel.get(i)._name if (from < 0 && oldName === itemName) { from = i if (to < profileModel.count) break } if (to === profileModel.count && newName < itemName) { to = i if (from > 0) break } } if (from > 0) { // model element found to = from < to ? to - 1 : to profileModel.move(from, to, 1) // update model element var toggledManual = profileModel.get(to)._toggledManual profileModel.set(to, {"_label": newName, "_name": newName, "_exe": exe, "_icon": icon, "_hasCustomIcon": hasCustomIcon, "_active": isActive, "_toggledManual": exe.length > 0 ? false : toggledManual }) refreshProfileButtonsIcon(icon) } } function updateProfileButtonActiveState(name, active) { for (var i = 1; i < profileModel.count; ++i) { if (profileModel.get(i)._name === name && profileModel.get(i)._active !== active) { profileModel.set(i, {"_active": active}) break } } } function updateProfileButtonManualToggle(name, active) { for (var i = 1; i < profileModel.count; ++i) { if (profileModel.get(i)._name === name) { profileModel.set(i, {"_toggledManual": active}) break } } } function refreshProfileButtonsIcon(icon) { for (var i = 1; i < profileModel.count; ++i) { if (profileModel.get(i)._icon === icon) { profileModel.set(i, {"_icon": ""}) // force icon update profileModel.set(i, {"_icon": icon}) } } } function updateToolBarProfileInfo(name, icon, isActive) { tbLabel.text = isActive ? name : name + " (" + qsTr("Disabled") + ")" tbLabel.color = isActive ? Style.ToolBar.text_color : Style.ToolBar.text_color_alt tbIcon.source = icon } function updateToolBarButtonsOnSettingsChanged() { unappliedSettings = true unsavedSettings = false } function updateToolBarButtonsOnProfileChanged() { unappliedSettings = false unsavedSettings = true } function updateToolBarButtonsOnProfileSaved() { unsavedSettings = false } function updateProfileUIState(name) { if (editedProfileBtn !== undefined) { var active = profileManager.isProfileActive(name) updateToolBarProfileInfo(editedProfileBtn.label, tbIcon.source, active) if (restoringProfile) { restoringProfile = false updateToolBarButtonsOnProfileSaved() } else { updateToolBarButtonsOnProfileChanged() } } } function goToProfileView() { if (unappliedSettings) applyProfileSettingsDlg.open() else exitProfileSettings() } function exitProfileSettings() { stack.pop() sysModelView.visible = false unappliedSettings = false unsavedSettings = false editedProfileBtn = undefined } function goToProfileSettingsView() { sysModelView.visible = true stack.push(sysModelView) } } ListModel { id: profileModel } Component { id: profileModelDelegate ProfileButton { id: pBtn label: _label name: _name icon: _icon exe: _exe isGlobal: _isGlobal profileActivated: _active toggledManual: _toggledManual onClicked: { p.editedProfileBtn = pBtn p.updateToolBarProfileInfo(label, icon, profileActivated) profileManager.loadSettings(name) p.goToProfileSettingsView() if (profileManager.isProfileUnsaved(name)) p.unsavedSettings = true } onEnableProfile: enable => profileManager.activate(name, enable) onEdit: { p.editedProfileBtn = pBtn infoDlg.title = qsTr("Profile properties") infoDlg.name = name infoDlg.exe = exe infoDlg.icon = icon infoDlg.hasCustomIcon = _hasCustomIcon infoDlg.newInfoAction = function(name, exe, icon) { p.editedProfileBtn = undefined if (pBtn.name !== name || pBtn.exe !== exe || pBtn.icon !== icon) profileManager.updateInfo(pBtn.name, name, exe, icon) } infoDlg.open() } onClone: { infoDlg.title = qsTr("New profile properties") infoDlg.name = "" infoDlg.exe = "" infoDlg.icon = isGlobal ? infoDlg.defaultIcon : icon infoDlg.hasCustomIcon = _hasCustomIcon infoDlg.forceAutomaticActivation = exe.length > 0 infoDlg.newInfoAction = function(name, exe, icon) { profileManager.add(name, exe, icon, pBtn.name) } infoDlg.open() } onExportTo: { exportToDialog.profileName = name exportToDialog.open() } onRemove: { removeWarningDlg.profileBtn = pBtn removeWarningDlg.profileName = pBtn.name removeWarningDlg.open() } onToggleManualProfile: name => profileManager.toggleManualProfile(name) } } NativeFileDialog { id: exportToDialog title: qsTr("Export profile to...") nameFilters: [qsTr("CoreCtrl profile") + " (ccpro)(*.ccpro)"] defaultSuffix: "ccpro" saveDlg: true property string profileName: "" onAccepted: { if(!profileManager.exportProfile(profileName, file)) { errorDlg.textDlg = qsTr("Cannot export profile.\nCheck the permissions of the destination file and directory.") errorDlg.open() } } } ProfileInfoDialog { id: infoDlg defaultIcon: profileManager.defaultIcon() function openNewProfileDialog() { title = qsTr("New profile properties") name = "" exe = "" icon = defaultIcon hasCustomIcon = false newInfoAction = function(name, exe, icon) { profileManager.add(name, exe, icon, "defaultProfile") } open() } onUpdateProfileNameUsed: profileName => { if (p.editedProfileBtn !== undefined && profileName === p.editedProfileBtn.name) profileNameUsed = false else profileNameUsed = profileManager.isProfileNameInUse(profileName) } onUpdateExecutableNameUsed: executableName => { if (p.editedProfileBtn !== undefined && executableName === p.editedProfileBtn.exe) executableNameUsed = false else executableNameUsed = profileManager.isExecutableNameInUse(executableName) } } Dialog { id: errorDlg property alias textDlg: errorDlgLbl.text title: qsTr("Error") focus: true modal: true standardButtons: Dialog.Ok closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 Label { id: errorDlgLbl } Component.onCompleted: { footer.standardButton(Dialog.Ok).hoverEnabled = Style.g_hover } } Dialog { id: removeWarningDlg title: qsTr("Warning") property var profileName property var profileBtn focus: true modal: true standardButtons: Dialog.Yes | Dialog.No closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 Label { text: qsTr("This action is permantent.\nDo you really want to remove %1?") .arg(removeWarningDlg.profileName) } onAccepted: profileManager.remove(profileName) Component.onCompleted: { footer.standardButton(Dialog.Yes).hoverEnabled = Style.g_hover footer.standardButton(Dialog.No).hoverEnabled = Style.g_hover } } Dialog { id: applyProfileSettingsDlg title: qsTr("Warning") focus: true modal: true standardButtons: Dialog.Ok | Dialog.Cancel closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 Label { text: qsTr("Unapplied settings will be lost.\nDo you want to apply them now?") } onAccepted: { profileManager.applySettings(p.editedProfileBtn.name) p.exitProfileSettings() close() } onRejected: { p.exitProfileSettings() close() } Component.onCompleted: { footer.standardButton(Dialog.Ok).hoverEnabled = Style.g_hover footer.standardButton(Dialog.Cancel).hoverEnabled = Style.g_hover } } Dialog { id: resetProfileSettingsDlg title: qsTr("Warning") focus: true modal: true standardButtons: Dialog.Yes | Dialog.No closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 Label { text: (p.unsavedSettings ? qsTr("Unsaved settings will be lost.\n") : "") + qsTr("Do you want to load the default settings?") } onAccepted: { profileManager.resetSettings(p.editedProfileBtn.name) } Component.onCompleted: { footer.standardButton(Dialog.Yes).hoverEnabled = Style.g_hover footer.standardButton(Dialog.No).hoverEnabled = Style.g_hover } } Dialog { id: restoreProfileSettingsDlg title: qsTr("Warning") focus: true modal: true standardButtons: Dialog.Yes | Dialog.No closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 Label { text: (p.unsavedSettings ? qsTr("Current settings will be discarded.\n") : "") + qsTr("Do you want to load the saved settings?") } onAccepted: { p.restoringProfile = true profileManager.restoreSettings(p.editedProfileBtn.name) } Component.onCompleted: { footer.standardButton(Dialog.Yes).hoverEnabled = Style.g_hover footer.standardButton(Dialog.No).hoverEnabled = Style.g_hover } } header: ToolBar { Material.elevation: Style.ToolBar.Material.elevation Material.background: Style.ToolBar.bg_color RowLayout { anchors.fill: parent Label { text: qsTr("Manage profiles for your applications...") leftPadding: 10 color: Style.ToolBar.text_color_msg visible: stack.depth === 1 } ToolButton { text: Style.g_icon.BACK font.pointSize: Style.g_text.icon_size_tabbar visible: stack.depth > 1 onClicked: p.goToProfileView() } Item { implicitWidth: tbIcon.width implicitHeight: tbIcon.height Image { id: tbIcon anchors.fill: parent fillMode: Image.PreserveAspectFit width: Style.g_icon.size height: Style.g_icon.size sourceSize.width: Style.g_icon.source_size visible: stack.depth > 1 } } Label { id: tbLabel leftPadding: 5 font.pointSize: Style.g_text.size + 2 elide: Text.ElideRight Layout.maximumWidth: 300 visible: stack.depth > 1 } Rectangle { Layout.fillWidth: true } ToolButton { text: Style.g_icon.ADD font.pointSize: Style.g_text.icon_size_tabbar visible: stack.depth === 1 onClicked: infoDlg.openNewProfileDialog() } ToolButton { text: qsTr("Save") visible: stack.depth > 1 && p.unsavedSettings onClicked: profileManager.saveSettings(p.editedProfileBtn.name) } ToolButton { text: qsTr("Apply") visible: stack.depth > 1 && p.unappliedSettings onClicked: profileManager.applySettings(p.editedProfileBtn.name) } ToolButton { text: qsTr("Restore") visible: stack.depth > 1 && p.unsavedSettings onClicked: restoreProfileSettingsDlg.open() } Label { text: Style.g_icon.SPLIT font.pointSize: Style.g_text.icon_size visible: stack.depth > 1 } ToolButton { text: qsTr("Load from...") visible: stack.depth > 1 NativeFileDialog { id: importFDialog title: qsTr("Load settings from...") nameFilters: [qsTr("CoreCtrl profile") + " (ccpro)(*.ccpro)"] defaultSuffix: "ccpro" onAccepted: { if (!profileManager.loadSettings(p.editedProfileBtn.name, file)) { errorDlg.textDlg = qsTr("Cannot load profile.\nInvalid or corrupted file.") errorDlg.open() } } } onClicked: importFDialog.open() } ToolButton { text: qsTr("Reset") visible: stack.depth > 1 onClicked: resetProfileSettingsDlg.open() } } } StackView { id: stack initialItem: profilesView anchors.fill: parent clip: true Item { id: sysModelView objectName: "PROFILE_SYS_MODEL_Plug" visible: false onChildrenChanged: { for (var i = 0; i < children.length; ++i) { children[i].settingsChanged.disconnect(p.updateToolBarButtonsOnSettingsChanged) children[i].settingsChanged.connect(p.updateToolBarButtonsOnSettingsChanged) } } } Pane { id: profilesView padding: 2 ScrollView { id: scrollview anchors.fill: parent clip: true ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.horizontal.visible: ScrollBar.horizontal.size < 1 ScrollBar.vertical.visible: ScrollBar.vertical.size < 1 Flow { width: scrollview.availableWidth height: scrollview.availableHeight spacing: Style.RectItemList.items_spacing Repeater { model: profileModel delegate: profileModelDelegate } move: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad } } } } } pushEnter: Transition { PropertyAnimation { property: "opacity" from: 0 to: 1 duration: Style.Profiles.opacity_anim_duration } } pushExit: Transition { PropertyAnimation { property: "opacity" from: 1 to: 0 duration: Style.Profiles.opacity_anim_duration } } popEnter: Transition { PropertyAnimation { property: "opacity" from: 0 to: 1 duration: Style.Profiles.opacity_anim_duration } } popExit: Transition { PropertyAnimation { property: "opacity" from: 1 to: 0 duration: Style.Profiles.opacity_anim_duration } } } } corectrl-v1.4.2/src/qml/SensorGraph.qml000066400000000000000000000124231467225065400200640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import QtCharts 2.15 import "Style.js" as Style Rectangle { id: graph objectName: "SensorGraph" implicitWidth: parent.width implicitHeight: 210 color: Style.Graph.bg_color function addItem(item) { p.addGrapItem(item) } function ignoredSensors(sensors) { p.refreshIgnored(sensors) } QtObject { // private stuff id: p property var itemsArray: [] function refreshIgnored(sensors) { for (var i = 0; i < itemsArray.length; ++i) { itemsArray[i].ignored = sensors.some(function(item) { return itemsArray[i].name === item }) } } function updateItems() { for (var i = 0; i < itemsArray.length; ++i) itemsArray[i].update() } function activateGraphItem(index, active) { itemsArray[index].active = active controlsModel.set(index, { "_active": active }) } function addGrapItem(item) { itemsArray.push(item) configureItem(item) addItemControl(item) } function configureItem(item) { var xAxis = axis.createObject(chart) var yAxis = axis.createObject(chart) var series = chart.createSeries(ChartView.SeriesTypeLine, qsTranslate("SensorGraph", item.name), xAxis, yAxis) item.configure(series, xAxis, yAxis) } function addItemControl(item) { var itemIndex = controlsModel.count item.valueChanged.connect(function (value) { controlsModel.set(itemIndex, { "_value": value }) }) item.activeChanged.connect(function (active) { controlsModel.set(itemIndex, { "_active": active }) }) item.colorChanged.connect(function (color) { controlsModel.set(itemIndex, { "_color": color }) }) item.ignoredChanged.connect(function (ignored) { controlsModel.set(itemIndex, { "_ignored": ignored}) }) item.yAxisRangeChanged.connect(function (min, max) { for (var i = 0; i < itemsArray.length; ++i) if (itemsArray[i] !== item && itemsArray[i].unit === item.unit) itemsArray[i].updateYAxisRange(min, max) }) controlsModel.append({ "_index": itemIndex, "_label": qsTranslate("SensorGraph", item.name), "_name": item.name, "_value": item.value, "_unit": item.unit, "_color": item.color, "_active": true, "_ignored": false }) } } Component { id: axis ValueAxis { visible: false } } Component { id: controlsModelDelegate RowLayout { property var index: _index spacing: 0 enabled: !_ignored CheckBox { checked: _active leftPadding: -5 rightPadding: 0 topPadding: -2 bottomPadding: -2 scale: 0.75 Material.accent: _color onToggled: p.activateGraphItem(index, checked) } Label { text: _label + ": " font.pointSize: Style.g_text.size - 1 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } Label { text: _ignored ? qsTr("n/a") : _value font.pointSize: Style.g_text.size - 1 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } Label { text: " " + _unit visible: !_ignored font.pointSize: Style.g_text.size - 1 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } } } ListModel { id: controlsModel } Connections { target: settings function onSettingChanged(key, value) { if (key === "UI/splitview-sensorgraph-controls-width") { controls.SplitView.preferredWidth = value } } } SplitView { spacing: 0 anchors.fill: parent orientation: Qt.Horizontal onResizingChanged: { if (!resizing) { settings.setValue("UI/splitview-sensorgraph-controls-width", controls.SplitView.preferredWidth) } } Rectangle { id: controls implicitWidth: 220 color: Style.Graph.ctl_bg_color ScrollView { id: ctlScrollView anchors.fill: parent leftPadding: 8 rightPadding: 8 topPadding: 10 bottomPadding: 10 clip: true ScrollBar.horizontal.policy: ScrollBar.AlwaysOn ScrollBar.vertical.policy: ScrollBar.AlwaysOn ScrollBar.horizontal.visible: ScrollBar.horizontal.size < 1 ScrollBar.vertical.visible: ScrollBar.vertical.size < 1 ColumnLayout { id: columnLayout Repeater { model: controlsModel delegate: controlsModelDelegate } } } } ChartView { id: chart SplitView.fillWidth: true antialiasing: true legend.visible: false backgroundColor: "#00000000" margins.left: 0 margins.right: 0 Timer { interval: 1000 running: true repeat: true onTriggered: p.updateItems() } } } } corectrl-v1.4.2/src/qml/Settings.js000066400000000000000000000026121467225065400172530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios .pragma library; var SysemTrayDefaults = { enabled: true, startMinimized: false, saveWindowGeometry: true, }; var ComponentData = { components: [], // component labels indexed by component id sensors: [] // sensors data indexed by component id }; function addComponentData(componentId, componentLabel, sensorId, sensorLabel) { if (ComponentData.components[componentId] === undefined) ComponentData.components[componentId] = componentLabel if (ComponentData.sensors[componentId] === undefined) ComponentData.sensors[componentId] = [] var sensor = { id: sensorId, label: sensorLabel }; ComponentData.sensors[componentId].push(sensor) } function componentIgnoredSensors(componentId, ignoredSensorsList) { var sensorList = [] // Handle all input as a list. // NOTE This is needed because QSettings will return a QString // instead of a QStringList when there is only one ignored sensor. if (typeof(ignoredSensorsList) === "string") { var sensor = ignoredSensorsList ignoredSensorsList = [] ignoredSensorsList.push(sensor) } for (var i = 0; i < ignoredSensorsList.length; ++i) { var componentList = ignoredSensorsList[i].split('/') if (componentId === componentList[0]) sensorList.push(componentList[1]) } return sensorList } corectrl-v1.4.2/src/qml/SettingsDialog.qml000066400000000000000000000032251467225065400205510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style Dialog { id: settingsDlg title: qsTr("Settings") focus: true modal: true standardButtons: Dialog.Ok | Dialog.Cancel closePolicy: Popup.CloseOnEscape // center in parent x: (parent.width - width) / 2 y: (parent.height - height) / 2 ColumnLayout { anchors.fill: parent TabBar { id: tabBar Layout.fillWidth: true hoverEnabled: Style.g_hover Repeater { model: [qsTr("General"), qsTr("Workarounds")] TabButton { text: modelData background: Rectangle { color: hovered ? Style.Dialog.tabs.bg_color_alt : Style.Dialog.tabs.bg_color } } } } StackLayout { currentIndex: tabBar.currentIndex SettingsGeneral { id: general onSettingsChanged: footer.standardButton(Dialog.Ok).enabled = true } SettingsWorkarounds { id: workarounds onSettingsChanged: footer.standardButton(Dialog.Ok).enabled = true } } } onOpened: { general.opened() workarounds.opened() footer.standardButton(Dialog.Ok).enabled = false } onAccepted: { general.accepted() workarounds.accepted() close() } onRejected: close() Component.onCompleted: { footer.standardButton(Dialog.Ok).enabled = false footer.standardButton(Dialog.Ok).hoverEnabled = Style.g_hover footer.standardButton(Dialog.Cancel).hoverEnabled = Style.g_hover } } corectrl-v1.4.2/src/qml/SettingsGeneral.qml000066400000000000000000000047521467225065400207350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style import "Settings.js" as Settings ColumnLayout { signal settingsChanged() function opened() { p.refreshState() } function accepted() { p.updateSettings() } Component.onCompleted: p.readSettings() QtObject { id: p property bool sysTrayIcon: Settings.SysemTrayDefaults.enabled property bool startOnSysTray: Settings.SysemTrayDefaults.startMinimized property bool saveWindowGeometry: Settings.SysemTrayDefaults.saveWindowGeometry function refreshState() { sysTrayIconCb.enabled = systemTray.isAvailable() sysTrayIconCb.checked = sysTrayIcon startOnSysTrayCb.checked = startOnSysTray saveWindowGeometryCb.checked = saveWindowGeometry } function readSettings() { sysTrayIcon = settings.getValue("sysTray", sysTrayIcon) startOnSysTray = settings.getValue("startOnSysTray", startOnSysTray) saveWindowGeometry = settings.getValue("saveWindowGeometry", saveWindowGeometry) } function updateSettings() { if (sysTrayIconCb.checked !== sysTrayIcon) { sysTrayIcon = sysTrayIconCb.checked settings.setValue("sysTray", sysTrayIconCb.checked) } if (startOnSysTrayCb.checked !== startOnSysTray) { startOnSysTray = startOnSysTrayCb.checked settings.setValue("startOnSysTray", startOnSysTrayCb.checked) } if (saveWindowGeometryCb.checked !== saveWindowGeometry) { saveWindowGeometry = saveWindowGeometryCb.checked settings.setValue("saveWindowGeometry", saveWindowGeometryCb.checked) } } } CheckBox { id: sysTrayIconCb text: qsTr("Show system tray icon") hoverEnabled: Style.g_hover leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 onToggled: settingsChanged() } CheckBox { id: startOnSysTrayCb enabled: sysTrayIconCb.enabled && sysTrayIconCb.checked text: qsTr("Start minimized on system tray") hoverEnabled: Style.g_hover leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 onToggled: settingsChanged() } CheckBox { id: saveWindowGeometryCb text: qsTr("Save window geometry") hoverEnabled: Style.g_hover leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 onToggled: settingsChanged() } } corectrl-v1.4.2/src/qml/SettingsWorkarounds.qml000066400000000000000000000135221467225065400216710ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style import "Settings.js" as Settings ColumnLayout { signal settingsChanged() function opened() { if (sensorComponentsModel.count < 1) p.initialize() else p.refreshState() } function accepted() { p.updateSettings() } Component.onCompleted: p.readSettings() QtObject { id: p property var ignoredSensors: [] function sensorIsIgnored(sensor) { return ignoredSensors.some(function(element) { return element === sensor }) } function initialize() { sensorComponentsModel.clear() for (var component in Settings.ComponentData.components) { var element = sensorComponentsModelElement.createObject() element.id = component element.text = Settings.ComponentData.components[component] sensorComponentsModel.append(element) var sensorsModelElement = sensorsModel.createObject() sensorComponentsModel.sensorsModels.push(sensorsModelElement) var componentIdx = sensorComponentsModel.count - 1 var sensors = Settings.ComponentData.sensors[component] for (var i = 0; i < sensors.length; ++i) { sensorsModelElement.append({"_componentIdx": componentIdx, "_index": i, "_id": sensors[i].id, "_label": sensors[i].label, "_active": !sensorIsIgnored(component + "/" + sensors[i].id)}) } var sensorListViewElement = sensorListView.createObject(sensorViews) sensorListViewElement.parent = sensorViews sensorListViewElement.model = sensorsModelElement sensorListViewElement.visible = false sensorViews.views.push(sensorListViewElement) } if (sensorComponentsModel.count > 0) { cbSensorsComponents.currentIndex = 0 cbSensorsComponents.updateWidth() } } function refreshState() { sensorComponentsModel.sensorsModels.forEach(function(sensorModel) { for (var i = 0; i < sensorModel.count; ++i) { var sensor = sensorModel.get(i) var sensorName = sensorComponentsModel.get(sensor._componentIdx).id + "/" + sensor._id sensorModel.set(i, {"_active": !sensorIsIgnored(sensorName)}) } }) } function readSettings() { ignoredSensors = settings.getStringList("Workarounds/ignoredSensors", []) } function updateSettings() { var newIgnoredSensors = [] sensorComponentsModel.sensorsModels.forEach(function(sensorModel) { for (var i = 0; i < sensorModel.count; ++i) { var sensor = sensorModel.get(i) if (!sensor._active) { var sensorName = sensorComponentsModel.get(sensor._componentIdx).id + "/" + sensor._id newIgnoredSensors.push(sensorName) } } }) if (!(ignoredSensors.length === newIgnoredSensors.length && ignoredSensors.every(function(element, index) { return element === newIgnoredSensors[index]; }))) { ignoredSensors = newIgnoredSensors settings.setStringList("Workarounds/ignoredSensors", ignoredSensors) } } } CGroupBox { title: qsTr("Sensors") showLine: false Layout.fillWidth: true Layout.fillHeight: true padding: 0 ColumnLayout { anchors.fill: parent TextArea { text: qsTr("Disabled sensors won't be updated from hardware") font.pointSize: Style.g_text.size - 1 readOnly: true activeFocusOnPress: false wrapMode: TextEdit.WordWrap horizontalAlignment: TextEdit.AlignHCenter width: 280 } RowLayout { Label { text: qsTr("Device") } CComboBox { id: cbSensorsComponents model: sensorComponentsModel hoverEnabled: Style.g_hover property int lastIndex: -1 onCurrentIndexChanged: { if (lastIndex !== -1) sensorViews.views[lastIndex].visible = false if (currentIndex !== -1) sensorViews.views[currentIndex].visible = true lastIndex = currentIndex } } } Rectangle { id: sensorViews property var views: [] Layout.fillWidth: true height: 120 color: Style.Dialog.bg_list_color } } } ListModel { id: sensorComponentsModel property var sensorsModels: [] } Component { id: sensorComponentsModelElement ListElement { property string id property string text } } Component { id: sensorsModel ListModel {} } Component { id: sensorsModelDelegate RowLayout { CheckBox { checked: _active hoverEnabled: Style.g_hover leftPadding: 0 rightPadding: 0 topPadding: 1 bottomPadding: 1 onToggled: { if (sensorComponentsModel.sensorsModels[_componentIdx] !== undefined) { sensorComponentsModel.sensorsModels[_componentIdx].set(_index, {"_active": checked}) settingsChanged() } } } Label { text: _label Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } } } Component { id: sensorListView ListView { delegate: sensorsModelDelegate anchors.fill: parent clip: true ScrollBar.vertical: ScrollBar { policy: ScrollBar.AlwaysOn visible: size < 1 hoverEnabled: Style.g_hover } ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOn visible: size < 1 hoverEnabled: Style.g_hover } } } } corectrl-v1.4.2/src/qml/Style.js000066400000000000000000000044441467225065400165600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios .pragma library; var g_padding = 12; var g_hover = true; var g_tweakScale = 0.78; var g_text = { size: 9, icon_size: 12, icon_size_tabbar: 16, family: "Sans" }; var g_icon = { size: 32, small_size: 18, source_size: 64, // unicode button icons MENU: "\u22EE", // ⋮ MORE: "\u22EF", // ⋯ BACK: "\u2190", // ← ADD: "+", SPLIT: "|", }; var ToolBar = { bg_color: "#2A2A2A", text_color_msg: "#DADADA", text_color: "#FFFFFF", text_color_alt: "#909090", Material: { elevation: 1 } } var RectItem = { bg_color: "#484848", bg_color_alt: "#404040", bg_color_hover: "#505050", text_color: "#FAFAFA", text_color_alt: "#909090", padding: 10 } var RectItemList = { items_spacing: 2 }; var TabBar = { main_footer: { bg_color: "#555555", } }; var TabButton = { bg_color: "#FF383838", bg_color_alt: "#FF484848" }; var TextField = { padding: 8, }; var Material = { elevation: 1, accent: "orangered", accent_alt: "#909090" }; var ModeSelector = { header: { bg_color: "#FF404040", padding: 8, }, body: { bg_color: "#FF393939" } }; var Controls = { items_spacing: 4 }; var Graph = { bg_color: "#20FFFFFF", ctl_bg_color: "#AA202020" }; var Profiles = { opacity_anim_duration: 200 }; var ToolTip = { delay: 1000, timeout: 3500 }; var CurveControl = { curve_amd_start_color: "lightskyblue", curve_color: "#ABFFFFFF", curve_opacity: 1.0, curve_opacity_alt: 0.3, axis_title_color: "#F0FFFFFF", axis_title_color_alt: "#80FFFFFF", axis_label_format: "%i", axis_label_color: "#C7FFFFFF", axis_label_color_alt: "#77FFFFFF", axis_color: "#E0FFFFFF", axis_color_alt: "#20FFFFFF", axis_grid_color: "#80FFFFFF", axis_grid_color_alt: "#20FFFFFF", axis_grid_minor_color: "#30FFFFFF", axis_grid_minor_color_alt: "#09FFFFFF", }; var FVControl = { border_color: "#40666666", inner_padding: 18, }; var Dialog = { bg_list_color: "#FF343434", tabs: { bg_color: "#FF525252", bg_color_alt: "#FF626262", }, }; var GroupBox = { text_size: 11, text_bold: true, bg_color: "transparent", bg_border_color: "#FF747474", bg_border_color_alt: "#40747474", bg_radius: 2 }; corectrl-v1.4.2/src/qml/SysModelForm.qml000066400000000000000000000051641467225065400202200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style SYS_MODEL { id: sysModel objectName: "SYS_MODEL" anchors.fill: parent Component { id: tabButtonComponent TabButton { id: tabBtn property var component: null property bool active: component != null ? component.enabled : true text: component != null ? component.name : "" width: implicitWidth contentItem: RowLayout { Text { id: tabBtnText text: tabBtn.text font: tabBtn.font color: tabBtn.active ? tabBtn.checked ? Style.Material.accent : Material.foreground : Style.Material.accent_alt horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight } Item { implicitWidth: swc.width / 2 Switch { id: swc padding: 0 rotation: -90 scale: Style.g_tweakScale checked: tabBtn.active anchors.centerIn: parent onToggled: { tabBtn.component.enabled = swc.checked tabBtn.component.activate(swc.checked) sysModel.settingsChanged() } } } } background: Rectangle { color: tabBtn.hovered ? Style.TabButton.bg_color_alt : Style.TabButton.bg_color } } } ColumnLayout { spacing: 0 anchors.fill: parent TabBar { id: tabBar Layout.fillWidth: true } StackLayout { id: sysModelplug objectName: "SYS_MODEL_Plug" currentIndex: tabBar.currentIndex property var childrenAdded: [] function isNewChild(child) { for (var i = 0; i < childrenAdded.length; ++i) if (childrenAdded[i] === child) return false return true } onChildrenChanged: { for (var i = 0; i < children.length; ++i) { var sysComponent = children[i] if (isNewChild(sysComponent)) { childrenAdded.push(sysComponent) // create and setup the new component var tab = tabButtonComponent.createObject(tabBar) tab.component = sysComponent tabBar.addItem(tab) sysModel.setupChild(sysComponent) } } } } } } corectrl-v1.4.2/src/qml/System.qml000066400000000000000000000042161467225065400171160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import CoreCtrl.UIComponents 1.0 import "Style.js" as Style Page { hoverEnabled: Style.g_hover SYSTEM_INFO { id: systemInfo objectName: "SYSTEM_INFO" onAddSystemInfo: (componentName, info) => p.newInfoComponent(componentName, info) } QtObject { id: p function newInfoComponent(componentName, info) { var tab = tabBtnComponent.createObject(tabBar) tab.text = componentName tabBar.addItem(tab) var infoPane = infoPaneComponent.createObject(infoPages) infoPane.addInfo(info) } } Component { id: infoPaneComponent InfoPane {} } Component { id: tabBtnComponent TabButton { id: tabBtn background: Rectangle { color: tabBtn.hovered ? Style.TabButton.bg_color_alt : Style.TabButton.bg_color } } } SettingsDialog { id: settingsDlg } ColumnLayout { spacing: 0 anchors.fill: parent TabBar { id: tabBar Layout.fillWidth: true Component.onCompleted: { var aboutTab = tabBtnComponent.createObject(tabBar) aboutTab.text = appInfo.name tabBar.addItem(aboutTab) } } StackLayout { id: infoPages currentIndex: tabBar.currentIndex About {} } } header: ToolBar { Material.elevation: Style.ToolBar.Material.elevation Material.background: Style.ToolBar.bg_color RowLayout { anchors.fill: parent Label { text: qsTr("Information and application settings...") leftPadding: 10 color: Style.ToolBar.text_color_msg } Rectangle { Layout.fillWidth: true } ToolButton { text: qsTr("Settings") visible: tabBar.currentIndex === 0 onClicked: settingsDlg.open() } ToolButton { text: qsTr("Copy all") visible: tabBar.currentIndex > 0 onClicked: systemInfo.copyToClipboard() } } } } corectrl-v1.4.2/src/qml/main.qml000066400000000000000000000021321467225065400165510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Controls.Material 2.15 import QtQuick.Layouts 1.15 import "Style.js" as Style import "Settings.js" as Settings ApplicationWindow { id: appWindow title: appInfo.name font.family: Style.g_text.family font.pointSize: Style.g_text.size font.capitalization: Font.MixedCase Material.theme: Material.Dark Material.accent: Style.Material.accent StackLayout { id: components anchors.fill: parent currentIndex: tabBar.currentIndex Profiles {} System {} } onVisibleChanged: components.visible = visible footer: TabBar { id: tabBar font.bold: true font.capitalization: Font.AllUppercase Material.background: Style.TabBar.main_footer.bg_color hoverEnabled: Style.g_hover TabButton { text: qsTr("Profiles") } TabButton { text: qsTr("System") } } onClosing: close => { if (!systemTray.isAvailable() || !systemTray.isVisible()) Qt.quit() } } corectrl-v1.4.2/src/qtquickcontrols2.conf000066400000000000000000000003251467225065400205210ustar00rootroot00000000000000; This file can be edited to change the style of the application ; See Styling Qt Quick Controls 2 in the documentation for details: ; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html [Controls] Style=Material corectrl-v1.4.2/src/resources.qrc000066400000000000000000000064241467225065400170520ustar00rootroot00000000000000 qtquickcontrols2.conf qml/Style.js qml/Settings.js qml/main.qml qml/Profiles.qml qml/System.qml qml/CComboBox.qml qml/CGroupBox.qml qml/CIntInput.qml qml/CurveControl.qml qml/FVControl.qml qml/FreqStateControl.qml qml/SensorGraph.qml qml/ModeSelector.qml qml/SysModelForm.qml qml/GPUForm.qml qml/CPUForm.qml qml/NoopForm.qml qml/AMDPMPerfModeForm.qml qml/AMDPMAutoForm.qml qml/AMDPMFixedForm.qml qml/AMDPMAdvancedForm.qml qml/AMDPMDynamicFreqForm.qml qml/AMDPMFixedFreqForm.qml qml/AMDPMPowerCapForm.qml qml/AMDPMFreqModeForm.qml qml/AMDPMOverclockForm.qml qml/AMDPMFreqOdForm.qml qml/AMDPMOverdriveForm.qml qml/AMDPMFreqVoltForm.qml qml/AMDPMFreqRangeForm.qml qml/AMDPMVoltCurveForm.qml qml/AMDPMVoltOffsetForm.qml qml/AMDPMPowerProfileForm.qml qml/AMDPMPowerStateForm.qml qml/AMDPMPowerStateModeForm.qml qml/AMDFanModeForm.qml qml/AMDFanAutoForm.qml qml/AMDFanFixedForm.qml qml/AMDFanCurveForm.qml qml/AMDOdFanAutoForm.qml qml/AMDOdFanCurveForm.qml qml/CPUFreqForm.qml qml/CPUFreqModeForm.qml qml/ProfileButton.qml qml/ProfileInfoDialog.qml qml/NativeFileDialog.qml qml/About.qml qml/InfoPane.qml qml/SettingsDialog.qml qml/SettingsWorkarounds.qml qml/SettingsGeneral.qml translations/lang_en_EN.qm translations/lang_es_ES.qm translations/lang_ru_RU.qm translations/lang_fr_FR.qm translations/lang_ca_ES.qm translations/lang_bg_BG.qm translations/lang_cs_CZ.qm translations/lang_nl_NL.qm translations/lang_de_DE.qm translations/lang_sv_SE.qm images/GlobalProfile.svg images/DefaultIcon.svg images/WarningIcon.svg images/AppIcon.svg corectrl-v1.4.2/src/translations/000077500000000000000000000000001467225065400170445ustar00rootroot00000000000000corectrl-v1.4.2/src/translations/lang_bg_BG.ts000066400000000000000000001222101467225065400213530ustar00rootroot00000000000000 AMD::PMFixedQMLItem low ниско mid средно high високо AMD::PMFreqRangeQMLItem SCLK Видео Карта MCLK Памет AMD::PMFreqVoltQMLItem SCLK Видео Карта MCLK Памет AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D_ЦЯЛ_ЕКРАН POWER_SAVING ИКОНОМИЯ_НА_ЕНЕРГИЯ VIDEO ВИДЕО VR Виртуална реалност COMPUTE ПРЕСМЯТАНЕ AMD::PMPowerStateQMLItem battery батерия balanced балансирано performance мощност AMDFanCurveForm Temperature Температура PWM PWM Fan start Начало на вентилатор AMDFanFixedForm Fan start Начало на вентилатор AMDFanModeForm Ventilation Вентилация AMDOdFanCurveForm Temperature Температура Speed Скорост AMDPMFixedFreqForm GPU Видео Карта Memory Памет AMDPMFreqModeForm Frequency Честота AMDPMFreqOdForm GPU Видео Карта Memory Памет AMDPMPerfModeForm Performance mode Режим на мощност AMDPMPowerCapForm Power limit Лимит на енергия AMDPMPowerProfileForm Power profile Профил на енергия AMDPMPowerStateModeForm Power management mode Режим на управление на захранването AMDPMVoltCurveForm Frequency Честота Voltage Волтове AMDPMVoltOffsetForm Voltage Волтове WARNING: Operating range not available. Use with caution! ПРЕДУПРЕЖДЕНИЕ: Работният обхват не е наличен. Използвайте с повишено внимание! OFFSET ОФСЕТ About Control your hardware with ease using application profiles Управлявайте хардуера си с лекота използвайки профили за приложенията си by от Links Линкове Project Проект Issue tracker Следване на проблеми Wiki Wiki FAQ Често задавани въпроси CPUFreqForm Frequency governor Управление на честотата Energy Performance Preference Енергийна ефективност на предпочитанията CPUFreqModeForm Performance scaling Мащабиране на производителността CPUFreqQMLItem performance мощност powersave икономия на енергия schedutil изполваемост на процесора ondemand при нужда conservative консервативно default По подразбиране balance_performance Балансиране на производителността balance_power Балансирайте на мощността power мощност ControlModeQMLItem AMD_PM_AUTO Автоматично AMD_PM_FIXED Фиксирано AMD_FAN_AUTO Автоматично AMD_FAN_FIXED Фиксирано AMD_FAN_CURVE Извивка AMD_PM_ADVANCED Напраденало AMD_PM_FIXED_FREQ Фиксирана честота AMD_PM_DYNAMIC_FREQ Динамична честота CPU_CPUFREQ Персонализиран AMD_PM_POWERSTATE Персонализиран NOOP Не контрол AMD_OD_FAN_AUTO Автоматично AMD_OD_FAN_CURVE Извивка FVControl STATE СЪСТОЯНИЕ Auto Авто Frequency Честота Voltage Волтове FreqStateControl MINIMUM MAXIMUM STATE СЪСТОЯНИЕ NoopForm Warning! Предупреждение! The component will not be controlled Компонентът няма да бъде контролиран ProfileButton Disable Излкючи Enable Включи Edit... Редактиране... Clone... Дубликиране... Export to... Запазване до... Remove Премахване ProfileInfoDialog Name: Име: Profile name Име на профила Activation: Активиране: Automatic Автоматично Manual Ръчен Executable: Изпълним файл: Executable name Име на изпълним файл Select an executable file Избиране на изпълним файл Icon: Икона: Select an icon Избиране на икона Images Снимки Customize icon Персонализиране на икона ProfileManagerUI _global_ Общ профил Profiles Disabled Изключено Profile properties Свойства на профила New profile properties Нови свойства на профила Error Грешка Warning Предупреждение This action is permantent. Do you really want to remove %1? Това действие е постоянно. Сигурни ли сте, че искате да премахнете %1? Unapplied settings will be lost. Do you want to apply them now? Незапазените настройки ще бъдат премахнати. Искате ли да ги приложите сега? Manage profiles for your applications... Управлявайте профили за приложенията си... Load from... Заредете от... Load settings from... Заредете настройки от... Cannot load profile. Invalid or corrupted file. Неможе да се зареди файла. Невалиден или повреден файл. Unsaved settings will be lost. Незапазените настрой ще бъдат премахнати. Do you want to load the default settings? Искате ли да заредите настройките по подразбиране? Current settings will be discarded. Сегашните настройки ще бъдат премахнати. Do you want to load the saved settings? Искате ли да заредите запазените настройки? Save Запазване Apply Прилагане Restore Възстановяване Export profile to... Запазете профила до... CoreCtrl profile CoreCtrl профил Cannot export profile. Check the permissions of the destination file and directory. Неможе да бъде запазен файла. Проверете правомощията на файла и папката. Reset Рестартиране SensorGraph AMD_MEM_FREQ Честота на памет AMD_GPU_FREQ Честота на видео карта AMD_GPU_TEMP Температура на видео карта AMD_POWER Енергия AMD_ACTIVITY Активност AMD_MEM_USAGE Използвана памет AMD_FAN_SPEED_PERC Скорост на вентилатор в проценти AMD_FAN_SPEED_RPM Скорост на вентилатор в RPM CPU_FREQ_PACK Честота на процесор n/a недостъпно AMD_GPU_VOLT Волтаж AMD_GPU_JUNCTION_TEMP Температура на кръстовището AMD_GPU_MEMORY_TEMP Температура на паметта CPU_USAGE Използване CPU_CORE_TEMP Температура SettingsDialog Settings Настройки General Общи Workarounds Заобиколки SettingsGeneral Show system tray icon Показване на икона в панела Start minimized on system tray Започни минимизирано Save window geometry Запазване на геометрията на прозореца SettingsWorkarounds Sensors Сензори Disabled sensors won't be updated from hardware Изключени сензори няма да бъдат обновени от хардуера Device Устройство SysTray Hide Крия Show Покажи Manual profiles Ръчни профили Quit Затваряне System Information and application settings... Информация и настройки на приложенията... Settings Настройки Copy all Копиране на всичко SystemInfoUI kernelv версия на кърнъла mesav версия на Mesa vkapiv версия на Vulkan API glcorev версия на OpenGL(core) glcompv версия на OpenGL(compat) vendorid ИД на производителя deviceid ИД на устройстовото svendorid ИД на модела на производителя sdeviceid ИД на модела на устройсвото vendor производител device устройство sdevice модел на устройството pcislot PCI прорез driver драйвър revision ревизия memory памет gputype вид на видео картата biosv версия на BIOS cpufamily семейство на процесора model модел modname име на модел stepping степинг ucodev версия на microcode l3cache L3 кеш cores ядра flags знамена bugs бъгове bogomips bogomips arch архитектура opmode режими на работа byteorder ред на байтовете virt витруализация l1dcache L1 кеш (информация) l1icache L1 кеш (инструкции) l2cache L2 кеш uniqueid Уникален идентификатор exeunits изпълними единици main Profiles Профили System Система corectrl-v1.4.2/src/translations/lang_ca_ES.ts000066400000000000000000001146001467225065400213710ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Baix mid Mig high Alt AMD::PMFreqRangeQMLItem SCLK GPU MCLK Memòria AMD::PMFreqVoltQMLItem SCLK GPU MCLK Memòria AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D a pantalla completa POWER_SAVING Estalvi d'energia VIDEO Video VR Realitat virtual COMPUTE Computació AMD::PMPowerStateQMLItem battery Bateria balanced Balancejat performance Rendiment AMDFanCurveForm Temperature Temperatura PWM PWM Fan start Inici del ventilador AMDFanFixedForm Fan start Inici del ventilador AMDFanModeForm Ventilation Ventilació AMDOdFanCurveForm Temperature Temperatura Speed Velocitat AMDPMFixedFreqForm GPU GPU Memory Memòria AMDPMFreqModeForm Frequency Frequència AMDPMFreqOdForm GPU GPU Memory Memòria AMDPMPerfModeForm Performance mode Mode de rendiment AMDPMPowerCapForm Power limit Limit d'energia AMDPMPowerProfileForm Power profile Perfil d'energia AMDPMPowerStateModeForm Power management mode Mode de gestió d'energia AMDPMVoltCurveForm Frequency Frequència Voltage Voltatge AMDPMVoltOffsetForm Voltage Voltatge WARNING: Operating range not available. Use with caution! AVÍS: El rang de funcionament no està disponible. Utilitzeu-lo amb precaució! OFFSET COMPENSACIÓ About Control your hardware with ease using application profiles Controla el teu maquinari amb facilitat utilitzant perfils d'aplicacions by per Links Enllaços Project Projecte Issue tracker Seguimient de problemes Wiki Wiki FAQ Preguntes freqüents CPUFreqForm Frequency governor Gobernador de frequència Energy Performance Preference Preferència de rendiment energètic CPUFreqModeForm Performance scaling Escalat de rendiment CPUFreqQMLItem performance Rendiment powersave Estalvi d'energia schedutil Utilització de la CPU ondemand Sota demanda conservative Conservador default Per defecte balance_performance Equilibrar rendiment balance_power Equilibrar energia power Energia ControlModeQMLItem AMD_PM_AUTO Automàtic AMD_PM_FIXED Fixe AMD_FAN_AUTO Automàtic AMD_FAN_FIXED Fixe AMD_FAN_CURVE Corba AMD_PM_ADVANCED Avançat AMD_PM_FIXED_FREQ Fixe AMD_PM_DYNAMIC_FREQ Dinàmica CPU_CPUFREQ Personalitzat AMD_PM_POWERSTATE Personalitzat NOOP No controlar AMD_OD_FAN_AUTO Automàtic AMD_OD_FAN_CURVE Corba FVControl STATE ESTAT Auto Auto Frequency Frequència Voltage Voltatge FreqStateControl MINIMUM MÍNIMA MAXIMUM MÁXIMA STATE ESTAT NoopForm Warning! ¡Advertència! The component will not be controlled El component no es controlarà ProfileButton Disable Deshabilitar Enable Habilitar Edit... Editar... Clone... Duplicar... Export to... Exportar a... Remove Eliminar ProfileInfoDialog Name: Nom: Profile name Nom del perfil Activation: Activació: Automatic Automàtic Manual Manual Executable: Executable: Executable name Nom del executable Select an executable file Seleciona un fitxer executable Icon: Icona: Select an icon Selecciona una icona Images Imatges Customize icon Personalitza la icona ProfileManagerUI _global_ Perfil Global Profiles Disabled Deshabilitat Profile properties Propietats del perfil New profile properties Propietats del nou perfil Error Error Warning Atenció This action is permantent. Do you really want to remove %1? Aquesta acció és permanent. Segur que vols eliminar %1? Unapplied settings will be lost. Do you want to apply them now? Els paràmetres sense aplicar es perderán. Vols aplicar-los ara? Manage profiles for your applications... Gestiona perfils per a les teves aplicacions... Load from... Carregar des de ... Load settings from... Carregar paràmetres des de ... Cannot load profile. Invalid or corrupted file. No es pot carregar el perfil. Arxiu erròni o corrupte. Unsaved settings will be lost. Els paràmetres sense guardar es perderán. Do you want to load the default settings? Vols carregar els paràmetres per defecte? Current settings will be discarded. Els paràmetres actuals serán descartats. Do you want to load the saved settings? Vols carregar els paràmetres guardats? Save Guardar Apply Aplicar Restore Restaurar Export profile to... Exportar perfil a... CoreCtrl profile Perfil de CoreCtrl Cannot export profile. Check the permissions of the destination file and directory. El perfil no es pot exportar. Comprova els permisos del fitxer i del directori de destí. Reset Reinicialitza SensorGraph AMD_MEM_FREQ Memòria AMD_GPU_FREQ GPU AMD_GPU_TEMP Temperatura AMD_POWER Consum AMD_ACTIVITY Activitat AMD_MEM_USAGE Memòria usada AMD_FAN_SPEED_PERC Ventilador AMD_FAN_SPEED_RPM Ventilador CPU_FREQ_PACK CPU n/a n/a AMD_GPU_VOLT Voltatge AMD_GPU_JUNCTION_TEMP Temperatura (unió) AMD_GPU_MEMORY_TEMP Temperatura (memòria) CPU_USAGE Ús CPU_CORE_TEMP Temperatura SettingsDialog Settings Paràmetres General General Workarounds Resolucions SettingsGeneral Show system tray icon Mostrar icona a la safata del sistema Start minimized on system tray Iniciar minimitzat a la safata del sistema Save window geometry Desar la geometria de la finestra SettingsWorkarounds Sensors Sensors Disabled sensors won't be updated from hardware Els sensors deshabilitats no s'actualizarán des del maquinari Device Dispositiu SysTray Hide Amagar Show Mostrar Manual profiles Perfils manuals Quit Sortir System Information and application settings... Informació i paràmetres de la aplicació... Settings Paràmetres Copy all Copiar tot SystemInfoUI kernelv Versió del nucli mesav Versió de Mesa vkapiv Versió de la API de Vulkan glcorev Versió de OpenGL (core) glcompv Versió de OpenGL (compat) vendorid ID del proveïdor deviceid ID del dispositiu svendorid ID del model del proveïdor sdeviceid ID del model vendor Proveïdor device Dispositiu sdevice Model de dispositiu pcislot Slot PCI driver Controlador revision Revisió memory Memòria gputype Tipus de GPU biosv Versió de BIOS cpufamily Familia de CPU model Model modname Nom del model stepping Revisió ucodev Versió del microcódi l3cache Caché L3 cores Nuclis flags Indicadors bugs Bugs bogomips Bogomips arch Arquitectura opmode Mode d'operació byteorder Ordre de bytes virt Virtualizació l1dcache Caché L1 (dades) l1icache Caché L1 (instruccions) l2cache Caché L2 uniqueid ID únic exeunits Unitats d'execució main Profiles Perfils System Sistema corectrl-v1.4.2/src/translations/lang_cs_CZ.ts000066400000000000000000001144221467225065400214220ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Nízký mid Střední high Vysoký AMD::PMFreqRangeQMLItem SCLK GPU MCLK Paměť AMD::PMFreqVoltQMLItem SCLK GPU MCLK Paměť AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D na celou obrazovku POWER_SAVING Úspora energie VIDEO Video VR Virtuálńí realita COMPUTE Výpočty AMD::PMPowerStateQMLItem battery Baterie balanced Vyvážený performance Výkon AMDFanCurveForm Temperature Teplota PWM PWM Fan start Spouštění ventilátoru AMDFanFixedForm Fan start Spouštění ventilátoru AMDFanModeForm Ventilation Odvětrávání AMDOdFanCurveForm Temperature Teplota Speed Rychlost AMDPMFixedFreqForm GPU GPU Memory Paměť AMDPMFreqModeForm Frequency Frekvence AMDPMFreqOdForm GPU GPU Memory Paměť AMDPMPerfModeForm Performance mode Výkonnostní režim AMDPMPowerCapForm Power limit Omezené výkonu AMDPMPowerProfileForm Power profile Profil výkonu AMDPMPowerStateModeForm Power management mode Režim správy napájení AMDPMVoltCurveForm Frequency Frekvence Voltage Napětí AMDPMVoltOffsetForm Voltage Napětí WARNING: Operating range not available. Use with caution! VAROVANÍ: Provozní rozsah není k dispozici. Používejte s opatrností! OFFSET Nastavit vypnutí About Control your hardware with ease using application profiles Snadné ovládání hardwaru pomocí profilů aplikací by od Links Odkazy Project Projekt Issue tracker Nahlásit chybu Wiki Вики FAQ Často kladené otázky CPUFreqForm Frequency governor Regulátor frekvence Energy Performance Preference Preference energetické náročnosti CPUFreqModeForm Performance scaling Škálování výkonnosti CPUFreqQMLItem performance Výkon powersave Úspora energie schedutil Použití procesoru ondemand Na vyžádání conservative Konzervativní default Výchozí balance_performance Vyvážení výkonu balance_power Vyvážení energie power Energie ControlModeQMLItem AMD_PM_AUTO Automatický AMD_PM_FIXED Pevný AMD_FAN_AUTO Automatický AMD_FAN_FIXED Pevný AMD_FAN_CURVE Křivka AMD_PM_ADVANCED Pokročilý AMD_PM_FIXED_FREQ Pevný AMD_PM_DYNAMIC_FREQ Dinamický CPU_CPUFREQ Přizpůsobit AMD_PM_POWERSTATE Přizpůsobit NOOP Nekontrolovat AMD_OD_FAN_AUTO Automatický AMD_OD_FAN_CURVE Křivka FVControl STATE Stav Auto Automatický Frequency Frekvence Voltage Napětí FreqStateControl MINIMUM MINIMUM MAXIMUM MAXIMUM STATE STAV NoopForm Warning! Varování! The component will not be controlled Komponenta nebude spravována ProfileButton Disable Vypnout Enable Zapnout Edit... Upravit... Clone... Klonovat... Export to... Exportovat do... Remove Odstranit ProfileInfoDialog Name: Název: Profile name Název profilu Activation: Aktivace: Automatic Automatický Manual Manuální Executable: Spustitelný: Executable name Název spustitelného souboru Select an executable file Vybrat spustitelný soubor Icon: Ikona: Select an icon Vybrat ikonu Images Obrázky Customize icon Přizpůsobit ikonu ProfileManagerUI _global_ Výchozí profil Profiles Disabled Vypnutý Profile properties Vlastnosti profilu New profile properties Nové vlastnosti profilu Error Chyba Warning Varování This action is permantent. Do you really want to remove %1? Tato akce je nevratná. Opravdu chcete odstranit %1? Unapplied settings will be lost. Do you want to apply them now? Nepoužitá nastavení budou ztracena. Chcete je použít hned? Manage profiles for your applications... Správa profilů pro vaše aplikace... Load from... Načíst z... Load settings from... Načíst nastavení z... Cannot load profile. Invalid or corrupted file. Nelze načíst profil. Nesprávný nebo poškozený soubor. Unsaved settings will be lost. Neuložená nastavení budou ztracena. Do you want to load the default settings? Chcete načíst výchozí nastavení? Current settings will be discarded. Aktuální nastavení se resetuje. Do you want to load the saved settings? Chcete stáhnout uložená nastavení? Save Uložit Apply Použít Restore Obnovit Export profile to... Exportovat profil... CoreCtrl profile Profil CoreCtrl Cannot export profile. Check the permissions of the destination file and directory. Nelze exportovat profil. Zkontrolujte přístupová práva k cílovému souboru a adresáři. Reset Resetovat SensorGraph AMD_MEM_FREQ Paměť AMD_GPU_FREQ Frekvence GPU AMD_GPU_TEMP Teplota AMD_POWER Spotřeba AMD_ACTIVITY Aktivita AMD_MEM_USAGE Využití paměti AMD_FAN_SPEED_PERC Ventilátor (%) AMD_FAN_SPEED_RPM Rychlost ventilítoru (ot/min) CPU_FREQ_PACK CPU n/a neznámý AMD_GPU_VOLT Napětí AMD_GPU_JUNCTION_TEMP Teplota (přechodová) AMD_GPU_MEMORY_TEMP Teplota (pamět) CPU_USAGE Využití CPU_CORE_TEMP Teplota SettingsDialog Settings Nastavení General Obecné Workarounds Řešení SettingsGeneral Show system tray icon Zobrazit ikonu v oznamovací oblasti Start minimized on system tray Spuštění minimalizovanév v oznamovací oblasti Save window geometry Uložení geometrie okna SettingsWorkarounds Sensors Senzory Disabled sensors won't be updated from hardware Zakázané senzory nebudou aktualizovány z hardwaru Device Zařízení SysTray Hide Skrýt Show Ukázat Manual profiles Manuální profily Quit Opustit System Information and application settings... Nastavení informací a aplikace... Settings Nastavení Copy all Kopírovat vše SystemInfoUI kernelv Verze jádra mesav Verze Mesa vkapiv Verze Vulkan API glcorev Verze openGL (jádro) glcompv Verze openGL (kompaktní) vendorid ID výrobce deviceid ID zařízení svendorid ID modelu dodavatele sdeviceid ID modelu zařízení vendor Výrobce device Zařízení sdevice Model zařízení pcislot Slot PCI driver Ovladač revision Revize memory Operační paměť gputype Typ CPU biosv Verze BIOSu cpufamily Rodina CPU model Model modname Název modelu stepping Stepping ucodev Verze mikrokódu l3cache Mezipaměť L3 cores Počet jader flags Příznaky bugs Chyby bogomips Bogomips arch Architektura opmode Režim CPU byteorder bajtový řád virt Virtualizace l1dcache Mezipaměť L1 l1icache Mezipaměť L1 (instrukce) l2cache Mezipaměť L2 uniqueid Jedinečné ID exeunits Výkonné jednotky main Profiles Profily System Systém corectrl-v1.4.2/src/translations/lang_de_DE.ts000066400000000000000000001147631467225065400213710ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Niedrig mid Mittel high Hoch AMD::PMFreqRangeQMLItem SCLK GPU MCLK Speicher AMD::PMFreqVoltQMLItem SCLK GPU MCLK Speicher AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D-Vollbild POWER_SAVING Energiesparen VIDEO Video VR VR COMPUTE Compute AMD::PMPowerStateQMLItem battery Akku balanced Ausgewogen performance Max. Leistung AMDFanCurveForm Temperature Temperatur PWM PWM Fan start Lüfterstart AMDFanFixedForm Fan start Lüfterstart AMDFanModeForm Ventilation Lüfter AMDOdFanCurveForm Temperature Temperatur Speed Geschwindigkeit AMDPMFixedFreqForm GPU GPU Memory Speicher AMDPMFreqModeForm Frequency Frequenz AMDPMFreqOdForm GPU GPU Memory Speicher AMDPMPerfModeForm Performance mode Aktiver Modus AMDPMPowerCapForm Power limit Max. Leistungsaufnahme AMDPMPowerProfileForm Power profile Leistungsprofil AMDPMPowerStateModeForm Power management mode Energieverwaltungsmodus AMDPMVoltCurveForm Frequency Frequenz Voltage Spannung AMDPMVoltOffsetForm Voltage Spannung WARNING: Operating range not available. Use with caution! WARNUNG: Außerhalb der Spezifikation. Mit besonderer Vorsicht verwenden! OFFSET OFFSET About Control your hardware with ease using application profiles Hardware einfach über Anwendungsprofile steuern by von Links Links Project Projekt Issue tracker Issue-Tracker Wiki Wiki FAQ FAQ CPUFreqForm Frequency governor Governor für Taktfrequenz Energy Performance Preference Präferenz für Energieeffizienz CPUFreqModeForm Performance scaling Leistungsskalierung CPUFreqQMLItem performance Max. Leistung powersave Energiesparen schedutil Scheduler ondemand Ondemand conservative Konservativ default Standard balance_performance Leistung ausgleichen balance_power Energie ausgleichen power Energie ControlModeQMLItem AMD_FAN_AUTO Automatisch AMD_FAN_CURVE Kurve AMD_FAN_FIXED Fester Wert AMD_PM_DYNAMIC_FREQ Dynamisch AMD_PM_FIXED_FREQ Fester Wert AMD_PM_ADVANCED Erweitert AMD_PM_AUTO Automatisch AMD_PM_FIXED Fester Wert AMD_PM_POWERSTATE Benutzerdefiniert CPU_CPUFREQ Benutzerdefiniert NOOP Nicht gesteuert AMD_OD_FAN_AUTO Automatisch AMD_OD_FAN_CURVE Kurve FVControl STATE STATUS Auto Auto Frequency Frequenz Voltage Spannung FreqStateControl MINIMUM MINIMUM MAXIMUM MAXIMUM STATE STATUS NoopForm Warning! Warnung! The component will not be controlled Der Betrieb des Geräts wird nicht gesteuert ProfileButton Disable Deaktivieren Enable Aktivieren Edit... Bearbeiten... Clone... Klonen... Export to... Exportieren nach... Remove Entfernen ProfileInfoDialog Name: Name: Profile name Profilname Activation: Aktivierung: Automatic Automatisch Manual Manuell Executable: Ausführbare Datei: Executable name Name der ausführbaren Datei Select an executable file Ausführbare Datei auswählen Icon: Symbol: Select an icon Symbol auswählen Images Bilder Customize icon Symbol ändern ProfileManagerUI _global_ Globales Profil Profiles Disabled Deaktiviert Profile properties Profileigenschaften New profile properties Eigenschaften des neuen Profils Export profile to... Profil exportieren nach... CoreCtrl profile CoreCtrl Profil Cannot export profile. Check the permissions of the destination file and directory. Profil konnte nicht exportiert werden. Prüfen Sie, ob Sie Schreibrechte für Zieldatei und -verzeichnis haben. Error Fehler Warning Warnung This action is permantent. Do you really want to remove %1? Diese Aktion kann nicht zurückgenommen werden. Soll %1 wirklich entfernt werden? Unapplied settings will be lost. Do you want to apply them now? Nicht gespeicherte Änderungen gehen verloren. Sollen sie jetzt gespeichert werden? Unsaved settings will be lost. Nicht gespeicherte Einstellungen gehen verloren. Do you want to load the default settings? Sollen die Standard-Einstellungen geladen werden? Current settings will be discarded. Die aktuellen Einstellungen werden verworfen. Do you want to load the saved settings? Sollen die gespeicherten Einstellungen geladen werden? Manage profiles for your applications... Anwendungsprofile verwalten... Save Speichern Apply Anwenden Restore Wiederherstellen Load from... Laden... Load settings from... Einstellungen laden... Cannot load profile. Invalid or corrupted file. Das Profil kann nicht geladen werden. Ungültige oder fehlerhafte Datei. Reset Zurücksetzen SensorGraph n/a n/a: "not applicable" vs "not available" n/a AMD_ACTIVITY Aktivität AMD_FAN_SPEED_PERC Lüfter AMD_FAN_SPEED_RPM Lüfter AMD_GPU_FREQ GPU AMD_GPU_TEMP Temperatur AMD_GPU_VOLT Spannung AMD_GPU_JUNCTION_TEMP Temperatur (Hotspot) AMD_MEM_FREQ Speicher AMD_GPU_MEMORY_TEMP Temperatur (Speicher) AMD_MEM_USAGE Speicherauslastung AMD_POWER Leistung CPU_FREQ_PACK CPU CPU_USAGE Verwendung CPU_CORE_TEMP Temperatur SettingsDialog Settings Einstellungen General Allgemein Workarounds "Workarounds" passt nicht; hier können nur Sensoren (de)aktiviert werden. Anpassungen SettingsGeneral Show system tray icon Symbol in Systemleiste anzeigen Start minimized on system tray Beim Start in Systemleiste minimieren Save window geometry Fenstergeometrie speichern SettingsWorkarounds Sensors Sensoren Disabled sensors won't be updated from hardware Die Werte deaktivierter Hardware-Sensoren werden nicht angezeigt Device Gerät SysTray Hide Verstecken Show Zeigen Manual profiles Manuelle Profile Quit Beenden System Information and application settings... Infos und Anwendungseinstellungen... Settings Einstellungen Copy all Alles kopieren SystemInfoUI kernelv Kernel-Version mesav Mesa-Version vkapiv Vulkan-API-Version glcorev OpenGL-Version (Core) glcompv OpenGL-Version (Compat) vendorid Anbieter-ID deviceid Geräte-ID svendorid Subsystem-Anbieter-ID sdeviceid Subsystem-ID vendor Anbieter device Gerät sdevice Geräte-Modell pcislot PCI-Slot driver Treiber revision Revision memory Speicher gputype GPU-Typ biosv BIOS-Version cpufamily CPU-Familie model Modell modname Modell-Name stepping Stepping ucodev Microcode-Version l3cache L3-Cache exeunits Ausführungseinheiten cores Kerne flags Flags bugs Bugs bogomips BogoMips arch Architektur opmode Betriebsmodi byteorder Byte-Reihenfolge virt Virtualisierung l1dcache L1-Cache (Daten) l1icache L1-Cache (Instruktionen) l2cache L2-Cache uniqueid Eindeutige ID main Profiles Profile System System corectrl-v1.4.2/src/translations/lang_en_EN.ts000066400000000000000000001134631467225065400214110ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Low mid Mid high High AMD::PMFreqRangeQMLItem SCLK GPU MCLK Memory AMD::PMFreqVoltQMLItem SCLK GPU MCLK Memory AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D Fullscreen POWER_SAVING Power saving VIDEO Video VR Virtual reality COMPUTE Compute AMD::PMPowerStateQMLItem battery Battery balanced Balanced performance Performance AMDFanCurveForm Temperature Temperature PWM PWM Fan start Fan start AMDFanFixedForm Fan start Fan start AMDFanModeForm Ventilation Ventilation AMDOdFanCurveForm Temperature Temperature Speed Speed AMDPMFixedFreqForm GPU GPU Memory Memory AMDPMFreqModeForm Frequency Frequency AMDPMFreqOdForm GPU GPU Memory Memory AMDPMPerfModeForm Performance mode Performance mode AMDPMPowerCapForm Power limit Power limit AMDPMPowerProfileForm Power profile Power profile AMDPMPowerStateModeForm Power management mode Power management mode AMDPMVoltCurveForm Frequency Frequency Voltage Voltage AMDPMVoltOffsetForm Voltage Voltage WARNING: Operating range not available. Use with caution! WARNING: Operating range not available. Use with caution! OFFSET OFFSET About Control your hardware with ease using application profiles Control your hardware with ease using application profiles by by Links Links Project Project Issue tracker Issue tracker Wiki Wiki FAQ FAQ CPUFreqForm Frequency governor Frequency governor Energy Performance Preference Energy Performance Preference CPUFreqModeForm Performance scaling Performance scaling CPUFreqQMLItem performance Performance powersave Powersave schedutil CPU utilization ondemand Ondemand conservative Conservative default Default balance_performance Balance performance balance_power Balance power power Power ControlModeQMLItem AMD_PM_AUTO Automatic AMD_PM_FIXED Fixed AMD_FAN_AUTO Automatic AMD_FAN_FIXED Fixed AMD_FAN_CURVE Curve AMD_PM_ADVANCED Advanced AMD_PM_FIXED_FREQ Fixed AMD_PM_DYNAMIC_FREQ Dynamic CPU_CPUFREQ Custom AMD_PM_POWERSTATE Custom NOOP Do not control AMD_OD_FAN_AUTO Automatic AMD_OD_FAN_CURVE Curve FVControl STATE STATE Auto Auto Frequency Frequency Voltage Voltage FreqStateControl MINIMUM MINIMUM MAXIMUM MAXIMUM STATE STATE NoopForm Warning! Warning! The component will not be controlled The component will not be controlled ProfileButton Disable Disable Enable Enable Edit... Edit... Clone... Clone... Export to... Export to... Remove Remove ProfileInfoDialog Name: Name: Profile name Profile name Activation: Activation: Automatic Automatic Manual Manual Executable: Executable: Executable name Executable name Select an executable file Select an executable file Icon: Icon: Select an icon Select an icon Images Images Customize icon Customize icon ProfileManagerUI _global_ Global Profile Profiles Disabled Disabled Profile properties Profile properties New profile properties New profile properties Error Error Warning Warning Unapplied settings will be lost. Do you want to apply them now? Unapplied settings will be lost. Do you want to apply them now? Manage profiles for your applications... Manage profiles for your applications... Load from... Load from... Load settings from... Load settings from... Cannot load profile. Invalid or corrupted file. Cannot load profile. Invalid or corrupted file. Unsaved settings will be lost. Unsaved settings will be lost. This action is permantent. Do you really want to remove %1? This action is permantent. Do you really want to remove %1? Do you want to load the default settings? Do you want to load the default settings? Current settings will be discarded. Current settings will be discarded. Do you want to load the saved settings? Do you want to load the saved settings? Save Save Apply Apply Restore Restore Export profile to... Export profile to... CoreCtrl profile CoreCtrl profile Cannot export profile. Check the permissions of the destination file and directory. Cannot export profile. Check the permissions of the destination file and directory. Reset Reset SensorGraph AMD_MEM_FREQ Memory AMD_GPU_FREQ GPU AMD_GPU_TEMP Temperature AMD_POWER Power AMD_ACTIVITY Activity AMD_MEM_USAGE Used memory AMD_FAN_SPEED_PERC Fan AMD_FAN_SPEED_RPM Fan CPU_FREQ_PACK CPU n/a n/a AMD_GPU_VOLT Voltage AMD_GPU_JUNCTION_TEMP Temperature (junction) AMD_GPU_MEMORY_TEMP Temperature (memory) CPU_USAGE Usage CPU_CORE_TEMP Temperature SettingsDialog Settings Settings General General Workarounds Workarounds SettingsGeneral Show system tray icon Show system tray icon Start minimized on system tray Start minimized on system tray Save window geometry Save window geometry SettingsWorkarounds Sensors Sensors Disabled sensors won't be updated from hardware Disabled sensors won't be updated from hardware Device Device SysTray Hide Hide Show Show Manual profiles Manual profiles Quit Quit System Information and application settings... Information and application settings... Settings Settings Copy all Copy all SystemInfoUI kernelv Kernel version mesav Mesa version vkapiv Vulkan API version glcorev OpenGL version (core) glcompv OpenGL version (compat) vendorid Vendor ID deviceid Device ID svendorid Vendor model ID sdeviceid Device model ID vendor Vendor device Device sdevice Device model pcislot PCI Slot driver Driver revision Revision memory Memory gputype GPU Type biosv BIOS version cpufamily CPU Family model Model modname Model Name stepping Stepping ucodev Microcode version l3cache L3 cache cores Cores flags Flags bugs Bugs bogomips Bogomips arch Architecture opmode Operation modes byteorder Byte order virt Virtualization l1dcache L1 cache (data) l1icache L1 cache (instructions) l2cache L2 cache uniqueid Unique ID exeunits Execution units main Profiles Profiles System System corectrl-v1.4.2/src/translations/lang_es_ES.ts000066400000000000000000001145721467225065400214250ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Bajo mid Medio high Alto AMD::PMFreqRangeQMLItem SCLK GPU MCLK Memoria AMD::PMFreqVoltQMLItem SCLK GPU MCLK Memoria AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D a pantalla completa POWER_SAVING Ahorro de energía VIDEO Vídeo VR Realidad virtual COMPUTE Computación AMD::PMPowerStateQMLItem battery Batería balanced Balanceado performance Rendimiento AMDFanCurveForm Temperature Temperatura PWM PWM Fan start Inicio de ventilador AMDFanFixedForm Fan start Inicio de ventilador AMDFanModeForm Ventilation Ventilación AMDOdFanCurveForm Temperature Temperatura Speed Velocidad AMDPMFixedFreqForm GPU GPU Memory Memoria AMDPMFreqModeForm Frequency Frecuencia AMDPMFreqOdForm GPU GPU Memory Memoria AMDPMPerfModeForm Performance mode Modo de rendimiento AMDPMPowerCapForm Power limit Límite de energía AMDPMPowerProfileForm Power profile Perfil de energía AMDPMPowerStateModeForm Power management mode Modo de gestión de energía AMDPMVoltCurveForm Frequency Frecuencia Voltage Voltaje AMDPMVoltOffsetForm Voltage Voltaje WARNING: Operating range not available. Use with caution! ADVERTENCIA: Rango de operación no disponible. ¡Úselo con precaución! OFFSET COMPENSACIÓN About Control your hardware with ease using application profiles Controla tu hardware con facilidad usando perfiles de aplicaciones by por Links Enlaces Project Proyecto Issue tracker Seguimiento de problemas Wiki Wiki FAQ Preguntas frecuentes CPUFreqForm Frequency governor Gobernador de frequencia Energy Performance Preference Preferencia de rendimiento energético CPUFreqModeForm Performance scaling Escalado de rendimiento CPUFreqQMLItem performance Rendimiento powersave Ahorro de energía schedutil Utilización de la CPU ondemand Bajo demanda conservative Conservador default Por defecto balance_performance Equilibrar rendimiento balance_power Equilibrar energía power Energía ControlModeQMLItem AMD_PM_AUTO Automático AMD_PM_FIXED Fijo AMD_FAN_AUTO Automática AMD_FAN_FIXED Fija AMD_FAN_CURVE Curva AMD_PM_ADVANCED Avanzado AMD_PM_FIXED_FREQ Fija AMD_PM_DYNAMIC_FREQ Dinámica CPU_CPUFREQ Personalizado AMD_PM_POWERSTATE Personalizado NOOP No controlar AMD_OD_FAN_AUTO Automática AMD_OD_FAN_CURVE Curva FVControl STATE ESTADO Auto Auto Frequency Frecuencia Voltage Voltaje FreqStateControl MINIMUM MÍNIMA MAXIMUM MÁXIMA STATE ESTADO NoopForm Warning! ¡Advertencia! The component will not be controlled El componente no será controlado ProfileButton Disable Deshabilitar Enable Habilitar Edit... Editar... Clone... Duplicar... Export to... Exportar a... Remove Eliminar ProfileInfoDialog Name: Nombre: Profile name Nombre del perfil Activation: Activación: Automatic Automática Manual Manual Executable: Ejecutable: Executable name Nombre del ejecutable Select an executable file Seleciona un fichero ejecutable Icon: Icono: Select an icon Selecciona un icono Images Imágenes Customize icon Personalizar icono ProfileManagerUI _global_ Perfil Global Profiles Disabled Deshabilitado Profile properties Propiedades del perfil New profile properties Propiedades del nuevo perfil Error Error Warning Atención This action is permantent. Do you really want to remove %1? Esta acción es permanente. ¿Seguro que quieres eliminar %1? Unapplied settings will be lost. Do you want to apply them now? Los ajustes sin aplicar se perderán. ¿Quieres aplicarlos ahora? Manage profiles for your applications... Gestiona perfiles para tus aplicaciones... Load from... Cargar desde... Load settings from... Cargar ajustes desde... Cannot load profile. Invalid or corrupted file. No se puede cargar el perfil. Archivo erróneo o corrompido. Unsaved settings will be lost. Los ajustes sin guardar se perderán. Do you want to load the default settings? ¿Quieres cargar los ajustes por defecto? Current settings will be discarded. Los ajustes actuales serán descartados. Do you want to load the saved settings? ¿Quieres cargar los ajustes guardados? Save Guardar Apply Aplicar Restore Restaurar Export profile to... Exportar perfil a... CoreCtrl profile Perfil de CoreCtrl Cannot export profile. Check the permissions of the destination file and directory. El perfil no se puede exportar. Comprueba los permisos del fichero y el directorio de destino. Reset Reinicializar SensorGraph AMD_MEM_FREQ Memoria AMD_GPU_FREQ GPU AMD_GPU_TEMP Temperatura AMD_POWER Consumo AMD_ACTIVITY Actividad AMD_MEM_USAGE Memoria usada AMD_FAN_SPEED_PERC Ventilador AMD_FAN_SPEED_RPM Ventilador CPU_FREQ_PACK CPU n/a n/a AMD_GPU_VOLT Voltaje AMD_GPU_JUNCTION_TEMP Temperatura (unión) AMD_GPU_MEMORY_TEMP Temperatura (memoria) CPU_USAGE Uso CPU_CORE_TEMP Temperatura SettingsDialog Settings Ajustes General General Workarounds Rodeos SettingsGeneral Show system tray icon Mostrar icono en la bandeja del sistema Start minimized on system tray Iniciar minimizado en la bandeja del sistema Save window geometry Guardar geometría de la ventana SettingsWorkarounds Sensors Sensores Disabled sensors won't be updated from hardware Los sensores deshabilitados no se actualizarán desde el hardware Device Dispositivo SysTray Hide Ocultar Show Mostrar Manual profiles Perfiles manuales Quit Salir System Information and application settings... Información y ajustes de la aplicación... Settings Ajustes Copy all Copiar todo SystemInfoUI kernelv Versión de núcleo mesav Versión de Mesa vkapiv Versión de API de Vulkan glcorev Versión de OpenGL (core) glcompv Versión de OpenGL (compat) vendorid ID de proveedor deviceid ID de dispositivo svendorid ID de modelo del proveedor sdeviceid ID de modelo vendor Proveedor device Dispositivo sdevice Modelo de dispositivo pcislot Slot PCI driver Controlador revision Revisión memory Memoria gputype Tipo de GPU biosv Versión de BIOS cpufamily Familia de CPU model Modelo modname Nombre del modelo stepping Revisión ucodev Versión de microcódigo l3cache Caché L3 cores Núcleos flags Indicadores bugs Bugs bogomips Bogomips arch Arquitectura opmode Modo de operación byteorder Orden de bytes virt Virtualización l1dcache Caché L1 (datos) l1icache Caché L1 (instrucciones) l2cache Caché L2 uniqueid Identificador único exeunits Unidades de ejecución main Profiles Perfiles System Sistema corectrl-v1.4.2/src/translations/lang_fr_FR.ts000066400000000000000000001151731467225065400214230ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Bas mid Moyen high Elevé AMD::PMFreqRangeQMLItem SCLK GPU MCLK Mémoire AMD::PMFreqVoltQMLItem SCLK GPU MCLK Mémoire AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D Plein écran POWER_SAVING Économie d'énergie VIDEO Vidéo VR Réalité Virtuelle COMPUTE Calcul AMD::PMPowerStateQMLItem battery Batterie balanced Équilibré performance Performance AMDFanCurveForm Temperature Température PWM PWM Fan start Démarrage du ventilateur AMDFanFixedForm Fan start Démarrage du ventilateur AMDFanModeForm Ventilation Ventilation AMDOdFanCurveForm Temperature Température Speed Vitesse AMDPMFixedFreqForm GPU GPU Memory Mémoire AMDPMFreqModeForm Frequency Fréquence AMDPMFreqOdForm GPU GPU Memory Mémoire AMDPMPerfModeForm Performance mode Mode Performance AMDPMPowerCapForm Power limit Limite de puissance AMDPMPowerProfileForm Power profile Profil de puissance AMDPMPowerStateModeForm Power management mode Mode de gestion d'énergie AMDPMVoltCurveForm Frequency Fréquence Voltage Tension AMDPMVoltOffsetForm Voltage Tension WARNING: Operating range not available. Use with caution! AVERTISSEMENT : Plage de fonctionnement non disponible. Utiliser avec précaution! OFFSET COMPENSATION About Control your hardware with ease using application profiles Contrôlez aisément votre matériel à l'aide de profils applicatifs by par Links Liens Project Projet Issue tracker Tickets de support Wiki Wiki FAQ FAQ CPUFreqForm Frequency governor Gouverneur de fréquence Energy Performance Preference Préférence pour la performance énergétique CPUFreqModeForm Performance scaling Echelle de performance CPUFreqQMLItem performance Performance powersave Économies d'énergie schedutil En fonction de l'utilisation du CPU ondemand À la demande conservative Conservateur default Par défaut balance_performance Équilibrer la performance balance_power Equilibrer l'énergie power Énergie ControlModeQMLItem AMD_PM_AUTO Automatique AMD_PM_FIXED Fixe AMD_FAN_AUTO Automatique AMD_FAN_FIXED Fixe AMD_FAN_CURVE Courbe AMD_PM_ADVANCED Avancé AMD_PM_FIXED_FREQ Fixe AMD_PM_DYNAMIC_FREQ Dynamique CPU_CPUFREQ Personnalisé AMD_PM_POWERSTATE Personnalisé NOOP Ne pas contrôler AMD_OD_FAN_AUTO Automatique AMD_OD_FAN_CURVE Courbe FVControl STATE ÉTAT Auto Auto Frequency Fréquence Voltage Voltage FreqStateControl MINIMUM MINIMUM MAXIMUM MAXIMUM STATE ÉTAT NoopForm Warning! Avertissement! The component will not be controlled Le composant ne sera pas contrôlé ProfileButton Disable Désactiver Enable Activer Edit... Éditer... Clone... Cloner... Export to... Exporter vers... Remove Effacer ProfileInfoDialog Name: Nom : Profile name Nom du profil Activation: Activation : Automatic Automatique Manual Manuel Executable: Exécutable : Executable name Nom de l'exécutable Select an executable file Sélectionnez un fichier exécutable Icon: Icône : Select an icon Sélectionnez une icône Images Images Customize icon Personnaliser l'icône ProfileManagerUI _global_ Profil Global Profiles Disabled Désactivé Profile properties Propriétés du profil New profile properties Propriétés du nouveau profil Error Erreur Warning Avertissement This action is permantent. Do you really want to remove %1? Cette action est définitive. Voulez-vous vraiment effacer %1? Unapplied settings will be lost. Do you want to apply them now? Les paramètres non-appliqués seront perdus. Voulez-vous les appliquer dès maintenant ? Manage profiles for your applications... Gérez les profils pour vos applications... Load from... Charger depuis... Load settings from... Charger les paramètres depuis... Cannot load profile. Invalid or corrupted file. Impossible de charger le profil. Fichier invalide ou corrompu. Unsaved settings will be lost. Les paramètres non-appliqués seront perdus. Do you want to load the default settings? Voulez-vous charger les paramètres par défaut ? Current settings will be discarded. Les paramètres actuels seront annulés. Do you want to load the saved settings? Voulez-vous charger les paramètres enregistrés ? Save Enregistrer Apply Appliquer Restore Restaurer Export profile to... Exporter le profil vers... CoreCtrl profile Profil de CoreCtrl Cannot export profile. Check the permissions of the destination file and directory. Impossible d'exporter le profil. Vérifiez les droits sur les fichier et répertoire de destination. Reset Réinitialiser SensorGraph AMD_MEM_FREQ Mémoire AMD_GPU_FREQ GPU AMD_GPU_TEMP Température AMD_POWER Puissance AMD_ACTIVITY Activité AMD_MEM_USAGE Mémoire utilisée AMD_FAN_SPEED_PERC Ventilateur (%) AMD_FAN_SPEED_RPM Ventilateur (RPM) CPU_FREQ_PACK CPU n/a n/a AMD_GPU_VOLT Tension AMD_GPU_JUNCTION_TEMP Température (jonction) AMD_GPU_MEMORY_TEMP Température (mémoire) CPU_USAGE Usage CPU_CORE_TEMP Température SettingsDialog Settings Paramètres General Général Workarounds Contournements SettingsGeneral Show system tray icon Afficher l'icône dans la zone de notification Start minimized on system tray Démarrer minimisé dans la zone de notification Save window geometry Sauvegarder la géométrie de la fenêtre SettingsWorkarounds Sensors Capteurs Disabled sensors won't be updated from hardware Les valeurs des capteurs désactivés ne seront pas mises à jour Device Périphérique SysTray Hide Cacher Show Montrer Manual profiles Profils manuels Quit Quitter System Information and application settings... Informations et paramètres de l'application... Settings Paramètres Copy all Tout copier SystemInfoUI kernelv Version du kernel mesav Version de Mesa vkapiv Version de l'API Vulkan glcorev Version d'OpenGL (core) glcompv Version d'OpenGL (compat) vendorid ID Vendeur deviceid ID Périphérique svendorid ID Vendeur sous-système sdeviceid ID sous-système vendor Vendeur device Périphérique sdevice Modèle périphérique pcislot Emplacement PCI driver Pilote revision Révision memory Mémoire gputype Type GPU biosv Version du BIOS cpufamily Famille CPU model Modèle modname Nom du modèle stepping Stepping ucodev Version du Microcode l3cache cache L3 cores Cœurs flags Drapeaux bugs Bugs bogomips Bogomips arch Architecture opmode Modes d'opération byteorder Ordre des octets virt Virtualisation l1dcache Cache L1 (données) l1icache Cache L1 (instructions) l2cache Cache L2 uniqueid Identifiant unique exeunits Unités d'exécution main Profiles Profils System Système corectrl-v1.4.2/src/translations/lang_nl_NL.ts000066400000000000000000001143571467225065400214320ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Laag mid Gemiddeld high Hoog AMD::PMFreqRangeQMLItem SCLK SCLK MCLK MCLK AMD::PMFreqVoltQMLItem SCLK SCLK MCLK MCLK AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D + Schermvullend POWER_SAVING Energiebesparing VIDEO Video VR VR COMPUTE Berekeningen AMD::PMPowerStateQMLItem battery Accu balanced Balans performance Prestaties AMDFanCurveForm Temperature Temperatuur PWM PWM Fan start Ventilator begint bij AMDFanFixedForm Fan start Ventilator begint bij AMDFanModeForm Ventilation Ventilatie AMDOdFanCurveForm Temperature Temperatuur Speed Snelheid AMDPMFixedFreqForm GPU Gpu Memory Geheugen AMDPMFreqModeForm Frequency Frequentie AMDPMFreqOdForm GPU Gpu Memory Geheugen AMDPMPerfModeForm Performance mode Prestatiemodus AMDPMPowerCapForm Power limit Energiebeperking AMDPMPowerProfileForm Power profile Energieprofiel AMDPMPowerStateModeForm Power management mode Energiebeheermodus AMDPMVoltCurveForm Frequency Frequentie Voltage Voltage AMDPMVoltOffsetForm Voltage Voltage WARNING: Operating range not available. Use with caution! WAARSCHUWING: het gekozen bereik is niet beschikbaar. Wees voorzichtig! OFFSET Verschuiving About Control your hardware with ease using application profiles Bedien uw hardware op basis van programmaprofielen by door Links Links Project Project Issue tracker Probleemtracker Wiki Wiki FAQ Veelgestelde vragen CPUFreqForm Frequency governor Frequentiegovernor Energy Performance Preference Energie-efficiëntie voorkeur CPUFreqModeForm Performance scaling Prestatieverhoudingen CPUFreqQMLItem performance performance powersave powersave schedutil Schedutil ondemand ondemand conservative conservative default Standaard balance_performance Prestaties balanceren balance_power Energie balanceren power Energie ControlModeQMLItem AMD_FAN_AUTO Automatische ventilatie AMD_FAN_CURVE Ventilatiecurve AMD_FAN_FIXED Vaste ventilatorsnelheid AMD_PM_DYNAMIC_FREQ Dynamische frequentie AMD_PM_FIXED_FREQ Vaste frequentie AMD_PM_ADVANCED Geavanceerd AMD_PM_AUTO Automatisch AMD_PM_FIXED Vast AMD_PM_POWERSTATE Energiestatus CPU_CPUFREQ Cpu-frequentie NOOP Noop AMD_OD_FAN_AUTO Automatische ventilatie AMD_OD_FAN_CURVE Ventilatiecurve FVControl STATE STATUS Auto Automatisch Frequency Frequentie Voltage Voltage FreqStateControl MINIMUM MINIMUM MAXIMUM MAXIMUM STATE STATUS NoopForm Warning! Waarschuwing! The component will not be controlled Dit onderdeel wordt niet bediend ProfileButton Disable Uitschakelen Enable Inschakelen Edit... Bewerken… Clone... Klonen… Export to... Exporteren naar… Remove Verwijderen ProfileInfoDialog Name: Naam: Profile name Profielnaam Activation: Activering: Automatic Automatisch Manual Handmatig Executable: Uitvoerbaar bestand: Executable name Uitvoerbaar bestand Select an executable file Kies een uitvoerbaar bestand Icon: Pictogram: Select an icon Kies een pictogram Images Afbeeldingen Customize icon Pictogram aanpassen ProfileManagerUI _global_ Algemeen Profiles Disabled Uitgeschakeld Profile properties Profieleigenschappen New profile properties Nieuwe profieleigenschappen Export profile to... Profiel exporteren naar… CoreCtrl profile CoreCtrl-profiel Cannot export profile. Check the permissions of the destination file and directory. Het profiel kan niet worden geëxporteerd. Controleer de rechten van de bestemming. Error Foutmelding Warning Waarschuwing This action is permantent. Do you really want to remove %1? Deze actie kan niet ongedaan worden gemaakt. Weet u zeker dat u %1 wilt verwijderen? Unapplied settings will be lost. Do you want to apply them now? Niet-toegepaste instellingen worden gewist. Wilt u ze nu toepassen? Unsaved settings will be lost. Niet-toegepaste instellingen worden gewist. Do you want to load the default settings? Wilt u de standaardwaarden herstellen? Current settings will be discarded. De huidige instellingen worden hierdoor overschreven. Do you want to load the saved settings? Wilt u de opgeslagen instellingen laden? Manage profiles for your applications... Beheer uw programmaprofielen… Save Opslaan Apply Toepassen Restore Herstellen Load from... Laden uit… Load settings from... Instellingen laden uit… Cannot load profile. Invalid or corrupted file. Het profiel kan niet worden geladen. Het bestand is mogelijk ongeldig of beschadigd. Reset Standaardwaarden SensorGraph n/a n/b AMD_ACTIVITY Activiteit AMD_FAN_SPEED_PERC Ventilatorsnelheid (in procenten) AMD_FAN_SPEED_RPM Ventilatorsnelheid (in TPM) AMD_GPU_FREQ Gpu-frequentie AMD_GPU_TEMP Gpu-temperatuur AMD_GPU_VOLT Gpu-voltage AMD_GPU_JUNCTION_TEMP Gpu-scheidingstemperatuur AMD_MEM_FREQ Geheugenfrequentie AMD_GPU_MEMORY_TEMP Tijdelijk gpu-geheugen AMD_MEM_USAGE Geheugengebruik AMD_POWER Energie CPU_FREQ_PACK Frequentiereeks CPU_USAGE Gebruik CPU_CORE_TEMP Temperatuur SettingsDialog Settings Instellingen General Algemeen Workarounds Tussenoplossingen SettingsGeneral Show system tray icon Systeemvakpictogram tonen Start minimized on system tray Geminimaliseerd opstarten Save window geometry Venstergeometrie opslaan SettingsWorkarounds Sensors Sensoren Disabled sensors won't be updated from hardware Uitgeschakelde sensoren worden niet bijgewerkt door de hardware Device Apparaat SysTray Hide Verbergen Show Tonen Manual profiles Handmatige profielen Quit Afsluiten System Information and application settings... Informatie en programma-instellingen… Settings Instellingen Copy all Alles kopiëren SystemInfoUI kernelv kernelv. mesav mesav. vkapiv vkapiv. glcorev glcorev. glcompv glcompv. vendorid fabrikantid deviceid apparaatid svendorid sapparaatid sdeviceid sapparaatid vendor fabrikant device apparaat sdevice sapparaat pcislot pcislot driver stuurprogramma revision revisie memory geheugen gputype gputype biosv biosv. cpufamily cpufamilie model model modname modelnaam stepping stappen ucodev ucodev. l3cache l3cache exeunits uitvoereenheden cores kernen flags opties bugs bugs bogomips bogomips arch arch. opmode opmodus byteorder bytevolgorde virt virt. l1dcache l1dcache l1icache l1icache l2cache l2cache uniqueid Unieke ID main Profiles Profielen System Systeem corectrl-v1.4.2/src/translations/lang_ru_RU.ts000066400000000000000000001217701467225065400214610ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Низкий mid Средний high Высокий AMD::PMFreqRangeQMLItem SCLK GPU MCLK Память AMD::PMFreqVoltQMLItem SCLK GPU MCLK Память AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN Полный 3D-экран POWER_SAVING Энергосбережение VIDEO Видео VR Виртуальная реальность COMPUTE Вычисления AMD::PMPowerStateQMLItem battery Батарея balanced Сбалансированный performance Производительность AMDFanCurveForm Temperature Температура PWM ШИМ Fan start Запуск вентилятора AMDFanFixedForm Fan start Запуск вентилятора AMDFanModeForm Ventilation Вентиляция AMDOdFanCurveForm Temperature Температура Speed Скорость AMDPMFixedFreqForm GPU GPU Memory Память AMDPMFreqModeForm Frequency Частота AMDPMFreqOdForm GPU GPU Memory Память AMDPMPerfModeForm Performance mode Режим производительности AMDPMPowerCapForm Power limit Ограничение мощности AMDPMPowerProfileForm Power profile Профиль мощности AMDPMPowerStateModeForm Power management mode Режим управления питанием AMDPMVoltCurveForm Frequency Частота Voltage Напряжение AMDPMVoltOffsetForm Voltage Напряжение WARNING: Operating range not available. Use with caution! ВНИМАНИЕ: Рабочий диапазон недоступен. Используйте с осторожностью! OFFSET СМЕЩЕНИЕ About Control your hardware with ease using application profiles Управляйте своим оборудованием с легкостью, используя профили приложений by от Links Ссылки Project Проект Issue tracker Issue tracker Wiki Вики FAQ FAQ CPUFreqForm Frequency governor Частотный регулятор Energy Performance Preference Предпочтение энергоэффективности CPUFreqModeForm Performance scaling Масштабирование производительности CPUFreqQMLItem performance Производительность powersave Экономия энергии schedutil Использование CPU ondemand По требованию conservative Консервативный default По умолчанию balance_performance Сбалансированная производительность balance_power Балансировка энергии power Энергия ControlModeQMLItem AMD_PM_AUTO Автоматический AMD_PM_FIXED Фиксированный AMD_FAN_AUTO Автоматический AMD_FAN_FIXED Фиксированный AMD_FAN_CURVE Кривая AMD_PM_ADVANCED Расширенный AMD_PM_FIXED_FREQ Фиксированный AMD_PM_DYNAMIC_FREQ Динамический CPU_CPUFREQ Пользовательский AMD_PM_POWERSTATE Пользовательский NOOP Не контролировать AMD_OD_FAN_AUTO Автоматический AMD_OD_FAN_CURVE Кривая FVControl STATE СОСТОЯНИЕ Auto Авто Frequency Частота Voltage Напряжение FreqStateControl MINIMUM минимум MAXIMUM максимум STATE СОСТОЯНИЕ NoopForm Warning! Внимание! The component will not be controlled Компонент не будет управляться ProfileButton Disable Выключить Enable Включить Edit... Редактировать... Clone... Клонировать... Export to... Экспортировать в... Remove Удалить ProfileInfoDialog Name: Имя: Profile name Имя профиля Activation: Активация: Automatic Автоматический Manual Руководство Executable: Исполняемый файл: Executable name Имя исполняемого файла Select an executable file Выбрать исполняемый файл Icon: Иконка: Select an icon Выбрать иконку Images Изображения Customize icon Настроить значок ProfileManagerUI _global_ Глобальный профиль Profiles Disabled Выключены Profile properties Свойства профиля New profile properties Новые свойства профиля Error Ошибка Warning Предупреждение This action is permantent. Do you really want to remove %1? Это действие необратимо. Вы действительно хотите удалить %1? Unapplied settings will be lost. Do you want to apply them now? Неприменённые настройки будут потеряны. Хотите применить их сейчас? Manage profiles for your applications... Управление профилями для ваших приложений... Load from... Загрузить из... Load settings from... Загрузить настройки из... Cannot load profile. Invalid or corrupted file. Невозможно загрузить профиль. Некорректный или поврежденный файл. Unsaved settings will be lost. Несохраненные настройки будут потеряны. Do you want to load the default settings? Вы хотите загрузить настройки по умолчанию? Current settings will be discarded. Текущие настройки будут сброшены. Do you want to load the saved settings? Хотите загрузить сохранённые настройки? Save Сохранить Apply Применить Restore Восстановить Export profile to... Экспортировать профиль в... CoreCtrl profile Профиль CoreCtrl Cannot export profile. Check the permissions of the destination file and directory. Невозможно экспортировать профиль. Проверьте права доступа к файлу назначения и каталогу. Reset Сбросить SensorGraph AMD_MEM_FREQ Память AMD_GPU_FREQ GPU AMD_GPU_TEMP Температура AMD_POWER Мощность AMD_ACTIVITY Активность AMD_MEM_USAGE Использование памяти AMD_FAN_SPEED_PERC I hope "_PERC" refers to the percentage of fan speed. If it doesn't, remove the percent sign. Вентилятор (%) AMD_FAN_SPEED_RPM Вентилятор (об/мин) CPU_FREQ_PACK CPU n/a н/д AMD_GPU_VOLT Напряжение AMD_GPU_JUNCTION_TEMP Температура (перехода) AMD_GPU_MEMORY_TEMP Температура (память) CPU_USAGE Использование CPU_CORE_TEMP Температура SettingsDialog Settings Настройки General Общие Workarounds Обходные пути SettingsGeneral Show system tray icon Показывать значок в системном лотке Start minimized on system tray Запускать в свёрнутом виде в системном лотке Save window geometry Сохранить геометрию окна SettingsWorkarounds Sensors Датчики Disabled sensors won't be updated from hardware Выключенные датчики не будут получать обновления от оборудования Device Устройство SysTray Hide Скрывать Show Показать Manual profiles Ручные профили Quit Завершить System Information and application settings... Информация и настройки приложений.... Settings Настройки Copy all Копировать всё SystemInfoUI kernelv Версия ядра mesav Версия Mesa vkapiv Версия Vulkan API glcorev Версия OpenGL (core) glcompv Версия OpenGL (compat) vendorid ID поставщика deviceid ID устройства svendorid ID модели поставщика sdeviceid ID модели устройства vendor Поставщик device Устройство sdevice Модель устройства pcislot PCI слот driver Драйвер revision Ревизия memory Память gputype Тип GPU biosv Версия BIOS cpufamily Семейство CPU model Модель modname Название модели stepping Stepping ucodev Версия микрокода l3cache Кэш L3 cores Ядра flags Флаги bugs Ошибки bogomips Bogomips arch Архитектура opmode Режимы работы byteorder Порядок байтов virt Виртуализация l1dcache Кэш L1 (данные) l1icache Кэш L1 (инструкции) l2cache Кэш L2 uniqueid Уникальный идентификатор exeunits Исполнительные единицы main Profiles Профили System Система corectrl-v1.4.2/src/translations/lang_sv_SE.ts000066400000000000000000001137231467225065400214430ustar00rootroot00000000000000 AMD::PMFixedQMLItem low Låg mid Medium high Hög AMD::PMFreqRangeQMLItem SCLK GPU MCLK Minne AMD::PMFreqVoltQMLItem SCLK GPU MCLK Minne AMD::PMPowerProfileQMLItem 3D_FULL_SCREEN 3D Helskärm POWER_SAVING Energispar VIDEO Video VR Virtual reality COMPUTE Beräkning AMD::PMPowerStateQMLItem battery Batteri balanced Balanserad performance Prestanda AMDFanCurveForm Temperature Temperatur PWM PWM Fan start Fläkt start AMDFanFixedForm Fan start Fläkt start AMDFanModeForm Ventilation Ventilation AMDOdFanCurveForm Temperature Temperatur Speed Hastighet AMDPMFixedFreqForm GPU GPU Memory Minne AMDPMFreqModeForm Frequency Frekvens AMDPMFreqOdForm GPU GPU Memory Minne AMDPMPerfModeForm Performance mode Prestandaläge AMDPMPowerCapForm Power limit Max effekt AMDPMPowerProfileForm Power profile Energiprofil AMDPMPowerStateModeForm Power management mode Effekt AMDPMVoltCurveForm Frequency Frekvens Voltage Voltantal AMDPMVoltOffsetForm Voltage Voltantal WARNING: Operating range not available. Use with caution! VARNING: Giltig skala är okänd. Använd försiktigt!! OFFSET FÖRSKJUTNING About Control your hardware with ease using application profiles Hantera din hårdvara enkelt med hjälp av programprofiler by av Links Länkar Project Projekt Issue tracker Ärendesystem Wiki Wiki FAQ FAQ CPUFreqForm Frequency governor Frequency governor Energy Performance Preference Energieffektivitet preferens CPUFreqModeForm Performance scaling Prestanda scalingskalning CPUFreqQMLItem performance Prestanda powersave Energispar schedutil CPU användande ondemand Vid behov conservative Konservativ default Standard balance_performance Balansera prestanda balance_power Balansera energi power Energi ControlModeQMLItem AMD_PM_AUTO Automatisk AMD_PM_FIXED Fast AMD_FAN_AUTO Automatisk AMD_FAN_FIXED Fast AMD_FAN_CURVE Kurva AMD_PM_ADVANCED Avancerad AMD_PM_FIXED_FREQ Fast AMD_PM_DYNAMIC_FREQ Dynamisk CPU_CPUFREQ Anpassad AMD_PM_POWERSTATE Anpassad NOOP Kontrollera inte AMD_OD_FAN_AUTO Automatisk AMD_OD_FAN_CURVE Kurva FVControl STATE LÄGE Auto Auto Frequency Frekvens Voltage Volt FreqStateControl MINIMUM MINIMUM MAXIMUM MAXIMUM STATE LÄGE NoopForm Warning! Varning! The component will not be controlled Komponentent kommer inte kontrolleras ProfileButton Disable Stäng av Enable Sätt på Edit... Editera... Clone... Klona... Export to... Exportera till... Remove Ta bort ProfileInfoDialog Name: Namn: Profile name Profilnamn Activation: Aktivering: Automatic Automatisk Manual Manuell Executable: Programfil: Executable name Namn på exekeverbara filen Select an executable file Välj en exekeverbar fil Icon: Ikon: Select an icon Välj en ikon Images Bilder Customize icon Ändra ikon ProfileManagerUI _global_ Globala Profiler Profiles Disabled Deaktiverad Profile properties Profilegenskaper New profile properties Ny profils egenskaper Error Fel Warning Varning Unapplied settings will be lost. Do you want to apply them now? Ickeapplicerade inställningar kommer förloras.. Vill du applicera dem nu? Manage profiles for your applications... Hantera profiler för dina applikationer... Load from... Ladda från... Load settings from... Ladda inställningar från... Cannot load profile. Invalid or corrupted file. Kan inte ladda profil. Felaktig eller korrumperad fil. Unsaved settings will be lost. Soparade ändringar kommer förloras.. This action is permantent. Do you really want to remove %1? Det går inte återställa. Vill du verkligen radera %1? Do you want to load the default settings? Vill du ladda defaultinställningarna? Current settings will be discarded. Aktiva inställnigar kommer slängas.. Do you want to load the saved settings? Vill du ladda de sparade inställningarna? Save Spara Apply Applicera Restore Återställ Export profile to... Exporta profil till... CoreCtrl profile CoreCtrl-profil Cannot export profile. Check the permissions of the destination file and directory. Kan inte exporta profil. Kontrollera rättigheter i destinationskatalogen och filen. Reset Återställ SensorGraph AMD_MEM_FREQ Minne AMD_GPU_FREQ GPU AMD_GPU_TEMP Temperatur AMD_POWER Effekt AMD_ACTIVITY Aktivitet AMD_MEM_USAGE Använt minne AMD_FAN_SPEED_PERC Fläkt AMD_FAN_SPEED_RPM Fläkt CPU_FREQ_PACK CPU n/a n/a AMD_GPU_VOLT Spänning AMD_GPU_JUNCTION_TEMP Temperatur (knutpunkt) AMD_GPU_MEMORY_TEMP Temperatur (minne) CPU_USAGE Resursanvändning CPU_CORE_TEMP Temperatur SettingsDialog Settings Inställningar General Generellt Workarounds Workarounds SettingsGeneral Show system tray icon Visa statusbarikon Start minimized on system tray Starta minimerat på statusbaren Save window geometry Spara fönsterstorlek SettingsWorkarounds Sensors Sensorer Disabled sensors won't be updated from hardware Inaktiverade sensorer kommer inte uppdateras från hårdvaran Device Enhet SysTray Hide Göm Show Visa Manual profiles Manuella profiler Quit Quit System Information and application settings... Information och programinställningar... Settings Inställningar Copy all Kopiera alla SystemInfoUI kernelv Kernelversion mesav Mesaversion vkapiv Vulkan API-version glcorev OpenGLversion (core) glcompv OpenGLversion (compat) vendorid Leverantörsid deviceid Enhetsid svendorid Leverantörsmodellsid sdeviceid Enhetsmodelid vendor Leverantör device Enhet sdevice Enhetsmodell pcislot PCI Slot driver Drivrutin revision Revision memory Minne gputype GPU-Typ biosv BIOS-version cpufamily CPU-Familj model Modell modname Modellnamn stepping Stepping ucodev Microcode-version l3cache L3 cache cores Kärnor flags Flaggor bugs Buggar bogomips Bogomips arch Arkitectur opmode Operationslägen byteorder Byteordning virt Viritualisering l1dcache L1 cache (data) l1icache L1 cache (instruktioner) l2cache L2 cache uniqueid Unikt ID exeunits Exekeveringsenheter main Profiles Profiler System System corectrl-v1.4.2/tests/000077500000000000000000000000001467225065400146765ustar00rootroot00000000000000corectrl-v1.4.2/tests/CMakeLists.txt000066400000000000000000000023631467225065400174420ustar00rootroot00000000000000find_package(Catch2 3.0 REQUIRED) find_package(trompeloeil 40 REQUIRED) # Compile definitions list(APPEND TESTS_COMPILE_DEFINITIONS ${3RDPARTY_DEFINITIONS} CATCH_CONFIG_FAST_COMPILE SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE ) # include directories for all tests list(APPEND TESTS_INCLUDE_DIRECTORIES ${3RDPARTY_INCLUDE_DIRECTORIES} ${PROJECT_SOURCE_DIR}/src ) # catch main add_library(catch_main OBJECT "src/main.cpp") target_include_directories(catch_main PRIVATE ${TESTS_INCLUDE_DIRECTORIES}) target_compile_definitions(catch_main PRIVATE ${TESTS_COMPILE_DEFINITIONS}) target_link_libraries(catch_main PRIVATE spdlog::spdlog Catch2::Catch2 trompeloeil::trompeloeil ${ATOMIC_LIB} ) # test_* files file(GLOB test_files "src/test_*.cpp") # generate test_all executable add_executable(test_all $ ${test_files} ${3RDPARTY_SRC}) target_include_directories(test_all PRIVATE ${TESTS_INCLUDE_DIRECTORIES}) target_compile_definitions(test_all PRIVATE ${TESTS_COMPILE_DEFINITIONS}) target_link_libraries(test_all PRIVATE corectrl_lib Qt5::Core spdlog::spdlog $<$:units::units> Catch2::Catch2 trompeloeil::trompeloeil ${ATOMIC_LIB} ) include(CTest) include(Catch) catch_discover_tests(test_all)corectrl-v1.4.2/tests/src/000077500000000000000000000000001467225065400154655ustar00rootroot00000000000000corectrl-v1.4.2/tests/src/common/000077500000000000000000000000001467225065400167555ustar00rootroot00000000000000corectrl-v1.4.2/tests/src/common/commandqueuestub.h000066400000000000000000000014321467225065400225070ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/icommandqueue.h" #include #include class CommandQueueStub final : public ICommandQueue { public: void pack(bool) override { } std::optional packWritesTo(std::string const &) override { return std::nullopt; } void add(std::pair &&cmd) override { commands_.emplace_back(std::move(cmd)); } QByteArray toRawData() override { return QByteArray(); } std::vector> const &commands() { return commands_; } void clear() { commands_.clear(); } private: std::vector> commands_; }; corectrl-v1.4.2/tests/src/common/controlmock.h000066400000000000000000000015451467225065400214650ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/icontrol.h" #include #include class ControlMock : public IControl { public: MAKE_MOCK0(init, void(), override); MAKE_MOCK1(preInit, void(ICommandQueue &), override); MAKE_MOCK1(postInit, void(ICommandQueue &), override); MAKE_CONST_MOCK0(active, bool(), override); MAKE_MOCK1(activate, void(bool), override); MAKE_MOCK0(cleanOnce, void(), override); MAKE_MOCK1(clean, void(ICommandQueue &), override); MAKE_MOCK1(sync, void(ICommandQueue &), override); MAKE_CONST_MOCK0(ID, std::string const &(), override); MAKE_MOCK1(importWith, void(Importable::Importer &), override); MAKE_CONST_MOCK1(exportWith, void(Exportable::Exporter &), override); }; corectrl-v1.4.2/tests/src/common/hwidtranslatorstub.h000066400000000000000000000010431467225065400230670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/info/ihwidtranslator.h" class HWIDTranslatorStub : public IHWIDTranslator { public: std::string vendor(std::string const &) const { return ""; } std::string device(std::string const &, std::string const &) const { return ""; } std::string subdevice(std::string const &, std::string const &, std::string const &, std::string const &) const { return ""; } }; corectrl-v1.4.2/tests/src/common/ppdpmhandlermock.h000066400000000000000000000022461467225065400224620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/controls/amd/pm/handlers/ippdpmhandler.h" #include #include extern template struct trompeloeil::reporter; namespace Tests::AMD { class PpDpmHandlerMock : public ::AMD::IPpDpmHandler { public: PpDpmHandlerMock( std::vector> states = {}) : states_(std::move(states)) { } std::vector> const & states() const override { return states_; } MAKE_CONST_MOCK0(active, std::vector const &(), override); MAKE_MOCK1(activate, void(std::vector const &), override); MAKE_MOCK0(saveState, void(), override); MAKE_MOCK1(restoreState, void(ICommandQueue &), override); MAKE_MOCK1(reset, void(ICommandQueue &), override); MAKE_MOCK1(sync, void(ICommandQueue &), override); private: std::vector> const states_; }; } // namespace Tests::AMD corectrl-v1.4.2/tests/src/common/sensormock.h000066400000000000000000000006761467225065400213220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/components/sensors/isensor.h" #include #include class SensorMock : public ISensor { public: MAKE_MOCK0(update, void(), override); MAKE_CONST_MOCK0(ID, std::string const &(), override); MAKE_CONST_MOCK1(exportWith, void(Exportable::Exporter &), override); }; corectrl-v1.4.2/tests/src/common/stringdatasourcestub.h000066400000000000000000000012141467225065400234030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" class StringDataSourceStub : public IDataSource { public: StringDataSourceStub(std::string_view source = "", std::string_view data = "", bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(std::string &data) override { data = data_; return success_; } std::string const source_; std::string const data_; bool success_; }; corectrl-v1.4.2/tests/src/common/stringpathdatasourcestub.h000066400000000000000000000014011467225065400242560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include class StringPathDataSourceStub : public IDataSource { public: StringPathDataSourceStub(std::string_view path = "", std::string_view data = "", bool success = true) noexcept : source_(path) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(std::string &data, std::filesystem::path const &) override { data = data_; return success_; } std::string const source_; std::string const data_; bool success_; }; corectrl-v1.4.2/tests/src/common/uintdatasourcestub.h000066400000000000000000000012701467225065400230560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" class UIntDataSourceStub : public IDataSource { public: UIntDataSourceStub(std::string_view source = "", unsigned int data = 0, bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(unsigned int &data) override { data = data_; return success_; } void data(unsigned int data) { data_ = data; } std::string const source_; unsigned int data_; bool success_; }; corectrl-v1.4.2/tests/src/common/vectorstringdatasourcestub.h000066400000000000000000000013761467225065400246370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #pragma once #include "core/idatasource.h" #include class VectorStringDataSourceStub : public IDataSource> { public: VectorStringDataSourceStub(std::string_view source = "", std::vector data = {""}, bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(std::vector &data) override { data = data_; return success_; } std::string const source_; std::vector const data_; bool success_; }; corectrl-v1.4.2/tests/src/main.cpp000066400000000000000000000007241467225065400171200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include #include void setupLogger() { auto logger = spdlog::create("null_logger"); spdlog::set_default_logger(logger); } int main(int argc, char *argv[]) { setupLogger(); return Catch::Session().run(argc, argv); } corectrl-v1.4.2/tests/src/test_amdfanauto.cpp000066400000000000000000000040421467225065400213470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/uintdatasourcestub.h" #include "core/components/controls/amd/fan/auto/fanauto.h" namespace Tests::AMD::FanAuto { class FanAutoTestAdapter : public ::AMD::FanAuto { public: using ::AMD::FanAuto::FanAuto; using ::AMD::FanAuto::cleanControl; using ::AMD::FanAuto::syncControl; }; TEST_CASE("AMD FanAuto tests", "[GPU][AMD][Fan][FanAuto]") { CommandQueueStub ctlCmds; SECTION("Has FanAuto ID") { FanAutoTestAdapter ts(std::make_unique()); REQUIRE(ts.ID() == ::AMD::FanAuto::ItemID); } SECTION("Is active by default") { FanAutoTestAdapter ts(std::make_unique()); REQUIRE(ts.active()); } SECTION("Does not generate pre-init control commands") { FanAutoTestAdapter ts(std::make_unique()); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { FanAutoTestAdapter ts(std::make_unique()); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate clean control commands") { FanAutoTestAdapter ts(std::make_unique()); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { FanAutoTestAdapter ts(std::make_unique("path", 2)); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { FanAutoTestAdapter ts(std::make_unique("path", 123)); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == "path"); REQUIRE(value == "2"); // 2 == automatic } } } // namespace Tests::AMD::FanAuto corectrl-v1.4.2/tests/src/test_amdfancurve.cpp000066400000000000000000000542731467225065400215360ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/uintdatasourcestub.h" #include "core/components/controls/amd/fan/curve/fancurve.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::FanCurve { class FanCurveTestAdapter : public ::AMD::FanCurve { public: using ::AMD::FanCurve::FanCurve; using ::AMD::FanCurve::cleanControl; using ::AMD::FanCurve::curve; using ::AMD::FanCurve::evaluatePwm; using ::AMD::FanCurve::evaluateTemp; using ::AMD::FanCurve::exportControl; using ::AMD::FanCurve::fanStartValue; using ::AMD::FanCurve::fanStop; using ::AMD::FanCurve::hysteresis; using ::AMD::FanCurve::importControl; using ::AMD::FanCurve::lerpFromPwm; using ::AMD::FanCurve::lerpFromTemp; using ::AMD::FanCurve::syncControl; }; class FanCurveImporterStub : public ::AMD::FanCurve::Importer { public: FanCurveImporterStub(std::vector<::AMD::FanCurve::Point> const &curve) : curve_(curve) , fanStartValue_(0) , fanStop_(false) { } std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } std::vector<::AMD::FanCurve::Point> const &provideFanCurvePoints() const override { return curve_; } bool provideFanCurveFanStop() const override { return fanStop_; } units::concentration::percent_t provideFanCurveFanStartValue() const override { return fanStartValue_; } void fanStop(bool enabled) { fanStop_ = enabled; } void fanStartValue(units::concentration::percent_t value) { fanStartValue_ = value; } private: std::vector<::AMD::FanCurve::Point> const curve_; units::concentration::percent_t fanStartValue_; bool fanStop_; }; class FanCurveExporterMock : public ::AMD::FanCurve::Exporter { public: MAKE_MOCK1(takeFanCurvePoints, void(std::vector<::AMD::FanCurve::Point> const &), override); MAKE_MOCK1(takeFanCurveFanStop, void(bool), override); MAKE_MOCK1(takeFanCurveFanStartValue, void(units::concentration::percent_t), override); MAKE_MOCK2(takeFanCurveTemperatureRange, void(units::temperature::celsius_t, units::temperature::celsius_t), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; class IntDataSourceStub : public IDataSource { public: IntDataSourceStub(std::string_view source = "", int data = 0, bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(int &data) override { data = data_; return success_; } void data(int data) { data_ = data; } std::string const source_; int data_; bool success_; }; TEST_CASE("AMD FanCurve tests", "[GPU][AMD][Fan][FanCurve]") { CommandQueueStub ctlCmds; SECTION("Pwm curve evaluation") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(100)); REQUIRE(ts.lerpFromPwm(units::concentration::percent_t(50), p1, p2) == 50); // out of line input REQUIRE(ts.lerpFromPwm(units::concentration::percent_t(-50), p1, p2) == 0); REQUIRE(ts.lerpFromPwm(units::concentration::percent_t(150), p1, p2) == 100); std::vector> curve; curve.push_back(p1); curve.push_back(p2); ts.curve(curve); REQUIRE(ts.evaluatePwm(units::concentration::percent_t(50)) == 50); // out of curve pwm REQUIRE(ts.evaluatePwm(units::concentration::percent_t(-50)) == 0); REQUIRE(ts.evaluatePwm(units::concentration::percent_t(150)) == 100); } SECTION("Temperature curve evaluation") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(100)); REQUIRE(ts.lerpFromTemp(units::temperature::celsius_t(50), p1, p2) == 128); // out of line input REQUIRE(ts.lerpFromTemp(units::temperature::celsius_t(-50), p1, p2) == 0); REQUIRE(ts.lerpFromTemp(units::temperature::celsius_t(150), p1, p2) == 255); std::vector> curve; curve.push_back(p1); curve.push_back(p2); ts.curve(curve); REQUIRE(ts.evaluateTemp(units::temperature::celsius_t(50)) == 128); // out of curve temperatures REQUIRE(ts.evaluateTemp(units::temperature::celsius_t(-50)) == 0); REQUIRE(ts.evaluateTemp(units::temperature::celsius_t(150)) == 255); } SECTION("Has FanCurve ID") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); REQUIRE(ts.ID() == ::AMD::FanCurve::ItemID); } SECTION("Is not active by default") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); REQUIRE_FALSE(ts.active()); } SECTION("Has a default curve") { auto tempRange = std::make_pair(units::temperature::celsius_t(0), units::temperature::celsius_t(50)); FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), tempRange.first, tempRange.second); REQUIRE(ts.curve().size() > 2); SECTION("Default curve points are normalized into temperature range") { REQUIRE_FALSE(std::any_of(ts.curve().cbegin(), ts.curve().cend(), [&](auto const &point) { return point.first < tempRange.first || point.first > tempRange.second; })); } } SECTION("Computed pwm1 value is clampled in [0, 255] range") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(100)); REQUIRE(ts.lerpFromTemp(units::temperature::celsius_t(-50), p1, p2) == 0); REQUIRE(ts.lerpFromTemp(units::temperature::celsius_t(50), p1, p2) == 128); REQUIRE(ts.lerpFromTemp(units::temperature::celsius_t(150), p1, p2) == 255); } SECTION("Has fan stop disabled by default") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); REQUIRE_FALSE(ts.fanStop()); } SECTION("Has hysteresis > 0") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); REQUIRE(ts.hysteresis() > 0); } SECTION("Has fan start value == 54 (21%) by default") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); REQUIRE(ts.fanStartValue() == 54); } SECTION("Clamp its fan start value in [0, 255] range") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.fanStartValue(300); REQUIRE(ts.fanStartValue() == 255); } SECTION("Does not generate pre-init control commands") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Imports its state") { auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(200), // out of range units::concentration::percent_t(200)); // out of range std::vector> curve; curve.push_back(p1); curve.push_back(p2); FanCurveImporterStub i(curve); i.fanStartValue(50); i.fanStop(true); FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.importControl(i); auto normalizedCurve = curve; auto &lastPoint = normalizedCurve.back(); lastPoint.first = units::temperature::celsius_t(100); lastPoint.second = units::concentration::percent_t(100); REQUIRE_FALSE(ts.curve().empty()); REQUIRE(ts.curve() == normalizedCurve); REQUIRE(ts.fanStartValue() == 128); REQUIRE(ts.fanStop()); } SECTION("Export its state") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(100)); std::vector> curve; curve.push_back(p1); curve.push_back(p2); ts.curve(curve); ts.fanStop(true); ts.fanStartValue(128); trompeloeil::sequence seq; FanCurveExporterMock e; REQUIRE_CALL(e, takeFanCurveTemperatureRange(trompeloeil::_, trompeloeil::_)) .WITH(_1 == units::temperature::celsius_t(0)) .WITH(_2 == units::temperature::celsius_t(100)) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takeFanCurvePoints(trompeloeil::_)) .LR_WITH(_1 == curve) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takeFanCurveFanStop(true)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takeFanCurveFanStartValue(trompeloeil::_)) .WITH(_1 == units::concentration::percent_t(50)) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Does not generate clean control commands") { FanCurveTestAdapter ts(std::make_unique(), std::make_unique(), std::make_unique(), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when...") { SECTION("is synced") { FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 128), std::make_unique("temp1_input", 50), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(100)); std::vector> curve; curve.push_back(p1); curve.push_back(p2); ts.curve(curve); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } } SECTION("Does generate sync control commands when...") { auto p1 = std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(0)); auto p2 = std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(100)); std::vector> curve; curve.push_back(p1); curve.push_back(p2); SECTION("pwm1_enabled is out of sync") { FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 0), std::make_unique("pwm1", 128), std::make_unique("temp1_input", 50), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == "pwm1_enabled"); REQUIRE(cmd0Value == "1"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == "pwm1"); REQUIRE(cmd1Value == "128"); } SECTION("pwm1_enabled and pwm1 are out of sync") { FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 0), std::make_unique("pwm1", 12), std::make_unique("temp1_input", 50), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == "pwm1_enabled"); REQUIRE(cmd0Value == "1"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == "pwm1"); REQUIRE(cmd1Value == "128"); } SECTION("fan stop is disabled and pwm1 is out of sync") { FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 12), std::make_unique("temp1_input", 50), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm1"); REQUIRE(cmdValue == "128"); } SECTION("fan stop is enabled and...") { SECTION("temperature is >= fan start temperature and pwm1 is out of sync") { auto tempDataSourcePtr = std::make_unique( "temp1_input", 0); auto &tempDataSource = *tempDataSourcePtr; FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 40), std::move(tempDataSourcePtr), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.fanStop(true); ts.fanStartValue(128); // 50% -> start temperature = 50 degrees C tempDataSource.data(50); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm1"); REQUIRE(cmdValue == "128"); } SECTION("temperature is fanStartTemp - hyst and pwm1 > 0 but out of sync") { auto tempDataSourcePtr = std::make_unique( "temp1_input", 0); auto &tempDataSource = *tempDataSourcePtr; FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 154), std::move(tempDataSourcePtr), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.fanStop(true); ts.fanStartValue(128); // 50% -> start temperature = 50 degrees C // temperature equals to fan start - hysteresis tempDataSource.data(50 - ts.hysteresis()); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm1"); REQUIRE(cmdValue == "128"); // value of fan start temperature } SECTION("temperature is in (fanStartTemp - hyst, fanStartTemp) range " "and pwm1 > 0 but out of sync") { auto tempDataSourcePtr = std::make_unique( "temp1_input", 0); auto &tempDataSource = *tempDataSourcePtr; FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 154), std::move(tempDataSourcePtr), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.fanStop(true); ts.fanStartValue(128); // 50% -> start temperature = 50 degrees C // temperature in (fan start - hysteresis, fan start) range tempDataSource.data(49); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm1"); REQUIRE(cmdValue == "128"); // value of fan start temperature } SECTION("temperature is < fanStartTemp - hyst and pwm1 > 0") { auto tempDataSourcePtr = std::make_unique( "temp1_input", 0); auto &tempDataSource = *tempDataSourcePtr; FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 128), std::move(tempDataSourcePtr), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.fanStop(true); ts.fanStartValue(128); // 50% -> start temperature = 50 degrees C // temperature lower than fan start - hysteresis tempDataSource.data(50 - ts.hysteresis() - 1); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm1"); REQUIRE(cmdValue == "0"); // turns off fan } SECTION("fan stop was enabled and then disabled") { FanCurveTestAdapter ts( std::make_unique("pwm1_enabled", 1), std::make_unique("pwm1", 0), std::make_unique("temp1_input", 50), units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ts.curve(curve); ts.fanStop(true); ts.syncControl(ctlCmds); ctlCmds = {}; ts.fanStop(false); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm1"); REQUIRE(cmdValue != "0"); } } } } } // namespace Tests::AMD::FanCurve corectrl-v1.4.2/tests/src/test_amdfanfixed.cpp000066400000000000000000000203671467225065400215060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/uintdatasourcestub.h" #include "core/components/controls/amd/fan/fixed/fanfixed.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::FanFixed { class FanFixedTestAdapter : public ::AMD::FanFixed { public: using ::AMD::FanFixed::FanFixed; using ::AMD::FanFixed::cleanControl; using ::AMD::FanFixed::exportControl; using ::AMD::FanFixed::fanStartValue; using ::AMD::FanFixed::fanStop; using ::AMD::FanFixed::importControl; using ::AMD::FanFixed::syncControl; using ::AMD::FanFixed::value; }; class FanFixedImporterStub : public ::AMD::FanFixed::Importer { public: FanFixedImporterStub() : value_(0) , fanStartValue_(0) , fanStop_(false) { } std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } units::concentration::percent_t provideFanFixedValue() const override { return value_; } bool provideFanFixedFanStop() const override { return fanStop_; } units::concentration::percent_t provideFanFixedFanStartValue() const override { return fanStartValue_; } void value(units::concentration::percent_t value) { value_ = value; } void fanStop(bool enabled) { fanStop_ = enabled; } void fanStartValue(units::concentration::percent_t value) { fanStartValue_ = value; } private: units::concentration::percent_t value_; units::concentration::percent_t fanStartValue_; bool fanStop_; }; class FanFixedExporterMock : public ::AMD::FanFixed::Exporter { public: MAKE_MOCK1(takeFanFixedValue, void(units::concentration::percent_t), override); MAKE_MOCK1(takeFanFixedFanStop, void(bool), override); MAKE_MOCK1(takeFanFixedFanStartValue, void(units::concentration::percent_t), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD FanFixed tests", "[GPU][AMD][Fan][FanFixed]") { CommandQueueStub ctlCmds; SECTION("Has FanFixed ID") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE(ts.ID() == ::AMD::FanFixed::ItemID); } SECTION("Is not active by default") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE_FALSE(ts.active()); } SECTION("Has value == 64 (25%) by default") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE(ts.value() == 64); } SECTION("Clamp its value in [0, 255] range") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); ts.value(300); REQUIRE(ts.value() == 255); } SECTION("Has fan stop disabled by default") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE_FALSE(ts.fanStop()); } SECTION("Has fan start value == 54 (21%) by default") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE(ts.fanStartValue() == 54); } SECTION("Clamp its fan start value in [0, 255] range") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); ts.fanStartValue(300); REQUIRE(ts.fanStartValue() == 255); } SECTION("Does not generate pre-init control commands") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Imports its state") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); FanFixedImporterStub i; i.value(100); i.fanStartValue(50); i.fanStop(true); ts.importWith(i); REQUIRE(ts.value() == 255); REQUIRE(ts.fanStartValue() == 128); REQUIRE(ts.fanStop()); } SECTION("Export its state") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); ts.value(128); ts.fanStop(true); ts.fanStartValue(128); units::concentration::percent_t percentValue(50); FanFixedExporterMock e; REQUIRE_CALL(e, takeFanFixedValue(trompeloeil::_)).LR_WITH(_1 == percentValue); REQUIRE_CALL(e, takeFanFixedFanStop(true)); REQUIRE_CALL(e, takeFanFixedFanStartValue(trompeloeil::_)) .LR_WITH(_1 == percentValue); ts.exportControl(e); } SECTION("Does not generate clean control commands") { FanFixedTestAdapter ts(std::make_unique(), std::make_unique()); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { FanFixedTestAdapter ts(std::make_unique("pwm_enabled", 1), std::make_unique("pwm", 128)); ts.value(128); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when...") { SECTION("pwm_enabled is out of sync") { FanFixedTestAdapter ts( std::make_unique("pwm_enabled", 0), std::make_unique("pwm", 128)); ts.value(128); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == "pwm_enabled"); REQUIRE(cmd0Value == "1"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == "pwm"); REQUIRE(cmd1Value == "128"); } SECTION("pwm is out of sync") { FanFixedTestAdapter ts( std::make_unique("pwm_enabled", 1), std::make_unique("pwm", 0)); ts.value(128); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm"); REQUIRE(cmdValue == "128"); } SECTION("pwm_enabled and pwm are out of sync") { FanFixedTestAdapter ts( std::make_unique("pwm_enabled", 0), std::make_unique("pwm", 0)); ts.value(128); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == "pwm_enabled"); REQUIRE(cmd0Value == "1"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == "pwm"); REQUIRE(cmd1Value == "128"); } } SECTION("Synced hw value uses fan start value when enabled") { FanFixedTestAdapter ts(std::make_unique("pwm_enabled", 1), std::make_unique("pwm", 20)); ts.value(20); ts.fanStartValue(30); ts.fanStop(false); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); ts.fanStop(true); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pwm"); REQUIRE(cmdValue == "0"); } } } // namespace Tests::AMD::FanFixed corectrl-v1.4.2/tests/src/test_amdfanmode.cpp000066400000000000000000000011641467225065400213250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/controls/amd/fan/fanmode.h" namespace Tests::AMD::FanMode { TEST_CASE("AMD FanMode tests", "[GPU][AMD][Fan][FanMode]") { std::vector> controlMocks; SECTION("Has FanMode ID") { ::AMD::FanMode ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::FanMode::ItemID); } SECTION("Is active by default") { ::AMD::FanMode ts(std::move(controlMocks)); REQUIRE(ts.active()); } } } // namespace Tests::AMD::FanMode corectrl-v1.4.2/tests/src/test_amdgpuinfopm.cpp000066400000000000000000000035131467225065400217200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/stringpathdatasourcestub.h" #include "core/info/amd/gpuinfopm.h" namespace Tests::AMD::GPUInfoPM { TEST_CASE("GPUInfoPM tests", "[AMD][Info][GPUInfo][GPUInfoPM]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); std::vector>> dataSources; SECTION("Provides Legacy capability") { dataSources.emplace_back(std::make_shared( "power_method", "dynpm", true)); dataSources.emplace_back(std::make_shared( "power_method", "profile", true)); ::AMD::GPUInfoPM ts(std::move(dataSources)); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 2); REQUIRE(output.front() == ::AMD::GPUInfoPM::Legacy); REQUIRE(output.back() == ::AMD::GPUInfoPM::Legacy); } SECTION("Provides Radeon capability") { dataSources.emplace_back(std::make_shared( "power_method", "dpm", true)); ::AMD::GPUInfoPM ts(std::move(dataSources)); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 1); REQUIRE(output.front() == ::AMD::GPUInfoPM::Radeon); } SECTION("Provides Amdgpu capability") { dataSources.emplace_back(std::make_shared( "power_dpm_force_performance_level", "some_value", true)); ::AMD::GPUInfoPM ts(std::move(dataSources)); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 1); REQUIRE(output.front() == ::AMD::GPUInfoPM::Amdgpu); } } } // namespace Tests::AMD::GPUInfoPM corectrl-v1.4.2/tests/src/test_amdgpuinfopmoverdrive.cpp000066400000000000000000000074711467225065400236550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/idatasource.h" #include "core/info/amd/gpuinfopmoverdrive.h" namespace Tests::AMD::GPUInfoPMOverdrive { class VectorStringPathDataSourceStub : public IDataSource, std::filesystem::path const> { public: VectorStringPathDataSourceStub(std::string_view source = "", std::vector data = {""}, bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(std::vector &data, std::filesystem::path const &) override { data = data_; return success_; } std::string const source_; std::vector const data_; bool success_; }; TEST_CASE("GPUInfoPMOverdrive tests", "[AMD][Info][GPUInfo][GPUInfoPMOverdrive]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); SECTION("Provides voltage curve capability") { // clang-format off std::vector ppOdClkVoltageData{"OD_VDDC_CURVE:", "0: 700Mhz 800mV",}; // clang-format on ::AMD::GPUInfoPMOverdrive ts(std::make_unique( "pp_od_clk_voltage", std::move(ppOdClkVoltageData))); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 1); REQUIRE(output.front() == ::AMD::GPUInfoPMOverdrive::VoltCurve); } SECTION("Does not provide voltage curve capability when the curve points " "have missing coordinates") { // clang-format off std::vector ppOdClkVoltageData{"OD_VDDC_CURVE:", "0: 800mV"}; // clang-format on ::AMD::GPUInfoPMOverdrive ts(std::make_unique( "pp_od_clk_voltage", std::move(ppOdClkVoltageData))); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.empty()); } SECTION("Provides clock + voltage capability") { // clang-format off std::vector ppOdClkVoltageData{"OD_SCLK:", "0: 300MHz 800mV"}; // clang-format on ::AMD::GPUInfoPMOverdrive ts(std::make_unique( "pp_od_clk_voltage", std::move(ppOdClkVoltageData))); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 1); REQUIRE(output.front() == ::AMD::GPUInfoPMOverdrive::ClkVolt); } SECTION("Provides clock capability") { // clang-format off std::vector ppOdClkVoltageData{"OD_SCLK:", "0: 300MHz"}; // clang-format on ::AMD::GPUInfoPMOverdrive ts(std::make_unique( "pp_od_clk_voltage", std::move(ppOdClkVoltageData))); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 1); REQUIRE(output.front() == ::AMD::GPUInfoPMOverdrive::Clk); } SECTION("Provides voltage offset capability") { // clang-format off std::vector ppOdClkVoltageData{"OD_VDDGFX_OFFSET:", "0mV"}; // clang-format on ::AMD::GPUInfoPMOverdrive ts(std::make_unique( "pp_od_clk_voltage", std::move(ppOdClkVoltageData))); auto output = ts.provideCapabilities(vendor, gpuIndex, path); REQUIRE(output.size() == 1); REQUIRE(output.front() == ::AMD::GPUInfoPMOverdrive::VoltOffset); } } } // namespace Tests::AMD::GPUInfoPMOverdrive corectrl-v1.4.2/tests/src/test_amdgpuinfouniqueid.cpp000066400000000000000000000017711467225065400231330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2022 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "common/stringpathdatasourcestub.h" #include "core/info/amd/gpuinfouniqueid.h" namespace Tests::AMD::GPUInfoUniqueID { TEST_CASE("GPUInfoUniqueID tests", "[AMD][Info][GPUInfo][GPUInfoUniqueID]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorStub hwIDTranslator; SECTION("Provides the type given by its DataSource") { ::AMD::GPUInfoUniqueID ts(std::make_unique( "unique_id", "some_unique_id")); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto type = std::make_pair(std::string(::IGPUInfo::Keys::uniqueID), std::string("SOME_UNIQUE_ID")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(type)); } } } // namespace Tests::AMD::GPUInfoUniqueID corectrl-v1.4.2/tests/src/test_amdgpuinfovbios.cpp000066400000000000000000000017371467225065400224340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "common/stringpathdatasourcestub.h" #include "core/info/amd/gpuinfovbios.h" namespace Tests::AMD::GPUInfoVbios { TEST_CASE("GPUInfoVbios tests", "[AMD][Info][GPUInfo][GPUInfoVbios]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorStub hwIDTranslator; SECTION("Provides the type given by its DataSource") { ::AMD::GPUInfoVbios ts( std::make_unique("vbios_version", "VERSION")); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto type = std::make_pair(std::string(::AMD::GPUInfoVbios::version), std::string("VERSION")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(type)); } } } // namespace Tests::AMD::GPUInfoVbios corectrl-v1.4.2/tests/src/test_amdodfanauto.cpp000066400000000000000000000045171467225065400217010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2023 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/fan/overdrive/auto/odfanauto.h" namespace Tests::AMD::OdFanAuto { class OdFanAutoTestAdapter : public ::AMD::OdFanAuto { public: using ::AMD::OdFanAuto::OdFanAuto; using ::AMD::OdFanAuto::cleanControl; using ::AMD::OdFanAuto::syncControl; }; TEST_CASE("AMD OdFanAuto tests", "[GPU][AMD][Fan][Overdrive][OdFanAuto]") { CommandQueueStub ctlCmds; OdFanAutoTestAdapter ts(std::make_unique("path")); SECTION("Has OdFanAuto ID") { REQUIRE(ts.ID() == ::AMD::OdFanAuto::ItemID); } SECTION("Is active by default") { REQUIRE(ts.active()); } SECTION("Does not generate pre-init control commands") { ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate clean control commands") { ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands the first time is sync") { ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[path0, value0] = ctlCmds.commands().at(0); REQUIRE(path0 == "path"); REQUIRE(value0 == "r"); auto &[path1, value1] = ctlCmds.commands().at(1); REQUIRE(path1 == "path"); REQUIRE(value1 == "c"); } SECTION("Does not generate sync control commands when is already active") { ts.syncControl(ctlCmds); ctlCmds.clear(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is reactivated") { ts.syncControl(ctlCmds); ts.activate(false); ts.clean(ctlCmds); ts.activate(true); ctlCmds.clear(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[path0, value0] = ctlCmds.commands().at(0); REQUIRE(path0 == "path"); REQUIRE(value0 == "r"); auto &[path1, value1] = ctlCmds.commands().at(1); REQUIRE(path1 == "path"); REQUIRE(value1 == "c"); } } } // namespace Tests::AMD::OdFanAuto corectrl-v1.4.2/tests/src/test_amdodfancurve.cpp000066400000000000000000000471731467225065400220620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/fan/overdrive/curve/odfancurve.h" extern template struct trompeloeil::reporter; #include namespace Tests::AMD::OdFanCurve { class OdFanCurveTestAdapter : public ::AMD::OdFanCurve { public: // clang-format off using ::AMD::OdFanCurve::OdFanCurve; using ::AMD::OdFanCurve::exportControl; using ::AMD::OdFanCurve::importControl; using ::AMD::OdFanCurve::cleanControl; using ::AMD::OdFanCurve::syncControl; using ::AMD::OdFanCurve::defaultCurve; using ::AMD::OdFanCurve::fanCurve; using ::AMD::OdFanCurve::controlPoints; using ::AMD::OdFanCurve::tempRange; using ::AMD::OdFanCurve::speedRange; using ::AMD::OdFanCurve::isZeroCurve; using ::AMD::OdFanCurve::setPointCoordinatesFrom; using ::AMD::OdFanCurve::controlPointCmd; using ::AMD::OdFanCurve::toCurvePoints; // clang-format on }; class FanCurveImporterStub : public ::AMD::OdFanCurve::Importer { public: FanCurveImporterStub(std::vector<::AMD::OdFanCurve::CurvePoint> const &curve) : curve_(curve) { } std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } std::vector<::AMD::OdFanCurve::CurvePoint> const &provideFanCurve() const override { return curve_; } private: std::vector<::AMD::OdFanCurve::CurvePoint> const curve_; }; class FanCurveExporterMock : public ::AMD::OdFanCurve::Exporter { public: MAKE_MOCK1(takeFanCurve, void(std::vector<::AMD::OdFanCurve::CurvePoint> const &), override); MAKE_MOCK2(takeFanCurveRange, void(::AMD::OdFanCurve::TempRange, ::AMD::OdFanCurve::SpeedRange), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD OdFanCurve tests", "[GPU][AMD][Fan][Overdrive][OdFanCurve]") { CommandQueueStub ctlCmds; // clang-format off std::vector regularInput{ "OD_FAN_CURVE:", "0: 10C 10%", "1: 45C 20%", "2: 50C 50%", "3: 75C 70%", "4: 100C 100%", "OD_RANGE:", "FAN_CURVE(hotspot temp): 10C 100C", "FAN_CURVE(fan speed): 10% 100%" }; std::vector zeroCurveInput{ "OD_FAN_CURVE:", "0: 0C 0%", "1: 0C 0%", "2: 0C 0%", "3: 0C 0%", "4: 0C 0%", "OD_RANGE:", "FAN_CURVE(hotspot temp): 10C 100C", "FAN_CURVE(fan speed): 10% 100%" }; // clang-format on SECTION("toCurvePoints") { // clang-format off std::vector> controlCurve { {0, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {1, units::temperature::celsius_t(1), units::concentration::percent_t(1)}, {2, units::temperature::celsius_t(2), units::concentration::percent_t(2)}, {3, units::temperature::celsius_t(3), units::concentration::percent_t(3)}, {4, units::temperature::celsius_t(4), units::concentration::percent_t(4)} }; std::vector> curvePoints { {units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {units::temperature::celsius_t(1), units::concentration::percent_t(1)}, {units::temperature::celsius_t(2), units::concentration::percent_t(2)}, {units::temperature::celsius_t(3), units::concentration::percent_t(3)}, {units::temperature::celsius_t(4), units::concentration::percent_t(4)} }; // clang-format on OdFanCurveTestAdapter ts(std::make_unique()); auto output = ts.toCurvePoints(controlCurve); REQUIRE_THAT(output, Catch::Matchers::Equals(curvePoints)); } SECTION("setPointCoordinatesFrom") { // clang-format off std::vector> curve { {0, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {1, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {2, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {3, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {4, units::temperature::celsius_t(0), units::concentration::percent_t(0)} }; std::vector> values { {units::temperature::celsius_t(-10), units::concentration::percent_t(-10)}, {units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {units::temperature::celsius_t(1), units::concentration::percent_t(1)}, {units::temperature::celsius_t(20), units::concentration::percent_t(20)}, {units::temperature::celsius_t(300), units::concentration::percent_t(300)} }; std::vector> targetCurve { {0, units::temperature::celsius_t(-10), units::concentration::percent_t(-10)}, {1, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {2, units::temperature::celsius_t(1), units::concentration::percent_t(1)}, {3, units::temperature::celsius_t(20), units::concentration::percent_t(20)}, {4, units::temperature::celsius_t(300), units::concentration::percent_t(300)} }; // clang-format on OdFanCurveTestAdapter ts(std::make_unique()); ts.setPointCoordinatesFrom(curve, values); REQUIRE_THAT(curve, Catch::Matchers::Equals(targetCurve)); } SECTION("isZeroCurve") { // clang-format off std::vector> zeroCurve { {0, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {1, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {2, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {3, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {4, units::temperature::celsius_t(0), units::concentration::percent_t(0)} }; std::vector> nonZeroCurve { {0, units::temperature::celsius_t(0), units::concentration::percent_t(0)}, {1, units::temperature::celsius_t(1), units::concentration::percent_t(1)}, {2, units::temperature::celsius_t(2), units::concentration::percent_t(2)}, {3, units::temperature::celsius_t(3), units::concentration::percent_t(3)}, {4, units::temperature::celsius_t(4), units::concentration::percent_t(4)} }; // clang-format on OdFanCurveTestAdapter ts(std::make_unique()); REQUIRE(ts.isZeroCurve(zeroCurve)); REQUIRE_FALSE(ts.isZeroCurve(nonZeroCurve)); } SECTION("controlPointCmd") { auto point = std::make_tuple(0, units::temperature::celsius_t(-100), units::concentration::percent_t(100)); OdFanCurveTestAdapter ts(std::make_unique()); auto output = ts.controlPointCmd(point); REQUIRE(output == "0 -100 100"); } SECTION("Has OdFanCurve ID") { OdFanCurveTestAdapter ts(std::make_unique()); REQUIRE(ts.ID() == ::AMD::OdFanCurve::ItemID); } SECTION("Is not active by default") { OdFanCurveTestAdapter ts(std::make_unique()); REQUIRE_FALSE(ts.active()); } SECTION("Generate pre-init control commands") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == "fan_curve"); REQUIRE(cmd0Value == "r"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == "fan_curve"); REQUIRE(cmd1Value == "c"); } SECTION("Does not generate post-init control commands with a pre-init zero " "point curve") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", zeroCurveInput)); ts.preInit(ctlCmds); ts.init(); ctlCmds.clear(); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generate post-init control commands with a pre-init non-zero points " "curve restoring the pre-init curve state") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.preInit(ctlCmds); ts.init(); ctlCmds.clear(); ts.postInit(ctlCmds); auto const &cmds = ctlCmds.commands(); REQUIRE(cmds.size() == 6); REQUIRE(cmds[0].first == "fan_curve"); REQUIRE(cmds[0].second == "0 10 10"); REQUIRE(cmds[1].first == "fan_curve"); REQUIRE(cmds[1].second == "1 45 20"); REQUIRE(cmds[2].first == "fan_curve"); REQUIRE(cmds[2].second == "2 50 50"); REQUIRE(cmds[3].first == "fan_curve"); REQUIRE(cmds[3].second == "3 75 70"); REQUIRE(cmds[4].first == "fan_curve"); REQUIRE(cmds[4].second == "4 100 100"); REQUIRE(cmds[5].second == "c"); } SECTION("Initializes...") { SECTION("Both temperature and speed ranges") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); REQUIRE(ts.tempRange() == std::make_pair(units::temperature::celsius_t(10), units::temperature::celsius_t(100))); REQUIRE(ts.speedRange() == std::make_pair(units::concentration::percent_t(10), units::concentration::percent_t(100))); } SECTION("Control curve with the custom default curve when the GPU has " "default zero point curve") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", zeroCurveInput)); ts.init(); auto defaultCurvePoints = ts.defaultCurve(); auto controlPoints = ts.controlPoints(); REQUIRE(controlPoints.size() == 5); auto const &[_i0, t0, s0] = controlPoints[0]; REQUIRE(t0 == defaultCurvePoints[0].first); REQUIRE(s0 == defaultCurvePoints[0].second); auto const &[_i1, t1, s1] = controlPoints[1]; REQUIRE(t1 == defaultCurvePoints[1].first); REQUIRE(s1 == defaultCurvePoints[1].second); auto const &[_i2, t2, s2] = controlPoints[2]; REQUIRE(t2 == defaultCurvePoints[2].first); REQUIRE(s2 == defaultCurvePoints[2].second); auto const &[_i3, t3, s3] = controlPoints[3]; REQUIRE(t3 == defaultCurvePoints[3].first); REQUIRE(s3 == defaultCurvePoints[3].second); auto const &[_i4, t4, s4] = controlPoints[4]; REQUIRE(t4 == defaultCurvePoints[4].first); REQUIRE(s4 == defaultCurvePoints[4].second); } SECTION("Control curve with the device default curve when the GPU has " "default non-zero point curve") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); auto controlPoints = ts.controlPoints(); REQUIRE(controlPoints.size() == 5); auto const &[_i0, t0, s0] = controlPoints[0]; REQUIRE(t0 == units::temperature::celsius_t(10)); REQUIRE(s0 == units::concentration::percent_t(10)); auto const &[_i1, t1, s1] = controlPoints[1]; REQUIRE(t1 == units::temperature::celsius_t(45)); REQUIRE(s1 == units::concentration::percent_t(20)); auto const &[_i2, t2, s2] = controlPoints[2]; REQUIRE(t2 == units::temperature::celsius_t(50)); REQUIRE(s2 == units::concentration::percent_t(50)); auto const &[_i3, t3, s3] = controlPoints[3]; REQUIRE(t3 == units::temperature::celsius_t(75)); REQUIRE(s3 == units::concentration::percent_t(70)); auto const &[_i4, t4, s4] = controlPoints[4]; REQUIRE(t4 == units::temperature::celsius_t(100)); REQUIRE(s4 == units::concentration::percent_t(100)); } SECTION("Control curve with normalized curve point coordinates") { // clang-format off std::vector input{ "OD_FAN_CURVE:", "0: 0C 0%", // out of range "1: 45C 20%", "2: 50C 50%", "3: 75C 70%", "4: 200C 200%", // out of range "OD_RANGE:", "FAN_CURVE(hotspot temp): 10C 100C", "FAN_CURVE(fan speed): 10% 100%" }; // clang-format on OdFanCurveTestAdapter ts( std::make_unique("fan_curve", input)); ts.init(); auto const &tempRange = ts.tempRange(); auto const &speedRange = ts.speedRange(); auto const &points = ts.controlPoints(); REQUIRE_FALSE( std::any_of(points.cbegin(), points.cend(), [&](auto const &point) { return std::get<1>(point) < tempRange.first || std::get<1>(point) > tempRange.second || std::get<2>(point) < speedRange.first || std::get<2>(point) > speedRange.second; })); } } SECTION("Imports its state") { // clang-format off std::vector> curve { {units::temperature::celsius_t(10), units::concentration::percent_t(15)}, {units::temperature::celsius_t(20), units::concentration::percent_t(25)}, {units::temperature::celsius_t(30), units::concentration::percent_t(35)}, {units::temperature::celsius_t(40), units::concentration::percent_t(45)}, {units::temperature::celsius_t(50), units::concentration::percent_t(55)}, }; // clang-format on FanCurveImporterStub i(curve); OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); ts.importControl(i); auto controlPoints = ts.controlPoints(); REQUIRE(controlPoints.size() == 5); auto const &[_i0, t0, s0] = controlPoints[0]; REQUIRE(t0 == units::temperature::celsius_t(10)); REQUIRE(s0 == units::concentration::percent_t(15)); auto const &[_i1, t1, s1] = controlPoints[1]; REQUIRE(t1 == units::temperature::celsius_t(20)); REQUIRE(s1 == units::concentration::percent_t(25)); auto const &[_i2, t2, s2] = controlPoints[2]; REQUIRE(t2 == units::temperature::celsius_t(30)); REQUIRE(s2 == units::concentration::percent_t(35)); auto const &[_i3, t3, s3] = controlPoints[3]; REQUIRE(t3 == units::temperature::celsius_t(40)); REQUIRE(s3 == units::concentration::percent_t(45)); auto const &[_i4, t4, s4] = controlPoints[4]; REQUIRE(t4 == units::temperature::celsius_t(50)); REQUIRE(s4 == units::concentration::percent_t(55)); } SECTION("Export its state") { // clang-format off std::vector> curve { {units::temperature::celsius_t(10), units::concentration::percent_t(10)}, {units::temperature::celsius_t(45), units::concentration::percent_t(20)}, {units::temperature::celsius_t(50), units::concentration::percent_t(50)}, {units::temperature::celsius_t(75), units::concentration::percent_t(70)}, {units::temperature::celsius_t(100), units::concentration::percent_t(100)}, }; // clang-format on OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); trompeloeil::sequence seq; FanCurveExporterMock e; REQUIRE_CALL(e, takeFanCurveRange(trompeloeil::_, trompeloeil::_)) .WITH(_1 == std::make_pair(units::temperature::celsius_t(10), units::temperature::celsius_t(100))) .WITH(_2 == std::make_pair(units::concentration::percent_t(10), units::concentration::percent_t(100))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takeFanCurve(trompeloeil::_)) .LR_WITH(_1 == curve) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Generate clean control commands") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.cleanControl(ctlCmds); auto const &cmds = ctlCmds.commands(); REQUIRE(cmds.size() == 2); auto const &[cmd0Path, cmd0Value] = cmds[0]; REQUIRE(cmd0Path == "fan_curve"); REQUIRE(cmd0Value == "r"); auto const &[cmd1Path, cmd1Value] = cmds[1]; REQUIRE(cmd1Path == "fan_curve"); REQUIRE(cmd1Value == "c"); } SECTION("Does not generate sync control commands when is synced") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); ts.syncControl(ctlCmds); ctlCmds.clear(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when...") { SECTION("curve is in sync but the operation mode must be set to manual") { OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); ts.syncControl(ctlCmds); auto const &cmds = ctlCmds.commands(); REQUIRE(cmds.size() == 2); auto const &[cmd0Path, cmd0Value] = cmds[0]; REQUIRE(cmd0Path == "fan_curve"); REQUIRE(cmd0Value == "r"); auto const &[cmd1Path, cmd1Value] = cmds[1]; REQUIRE(cmd1Path == "fan_curve"); REQUIRE(cmd1Value == "c"); } SECTION("curve is out of sync") { // clang-format off std::vector> curve { {units::temperature::celsius_t(15), units::concentration::percent_t(15)}, {units::temperature::celsius_t(20), units::concentration::percent_t(20)}, {units::temperature::celsius_t(30), units::concentration::percent_t(30)}, {units::temperature::celsius_t(40), units::concentration::percent_t(40)}, {units::temperature::celsius_t(50), units::concentration::percent_t(50)} }; // clang-format on OdFanCurveTestAdapter ts(std::make_unique( "fan_curve", regularInput)); ts.init(); ts.fanCurve(curve); ts.syncControl(ctlCmds); auto const &cmds = ctlCmds.commands(); REQUIRE(cmds.size() == 6); REQUIRE(cmds[0].first == "fan_curve"); REQUIRE(cmds[0].second == "0 15 15"); REQUIRE(cmds[1].first == "fan_curve"); REQUIRE(cmds[1].second == "1 20 20"); REQUIRE(cmds[2].first == "fan_curve"); REQUIRE(cmds[2].second == "2 30 30"); REQUIRE(cmds[3].first == "fan_curve"); REQUIRE(cmds[3].second == "3 40 40"); REQUIRE(cmds[4].first == "fan_curve"); REQUIRE(cmds[4].second == "4 50 50"); REQUIRE(cmds[5].second == "c"); } } } } // namespace Tests::AMD::OdFanCurve corectrl-v1.4.2/tests/src/test_amdpmadvanced.cpp000066400000000000000000000012401467225065400220110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/controls/amd/pm/advanced/pmadvanced.h" namespace Tests::AMD::PMAdvanced { TEST_CASE("AMD PMAdvanced tests", "[GPU][AMD][PM][PMAdvanced]") { std::vector> controlMocks; SECTION("Has PMAdvanced ID") { ::AMD::PMAdvanced ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::PMAdvanced::ItemID); } SECTION("Is not active by default") { ::AMD::PMAdvanced ts(std::move(controlMocks)); REQUIRE_FALSE(ts.active()); } } } // namespace Tests::AMD::PMAdvanced corectrl-v1.4.2/tests/src/test_amdpmauto.cpp000066400000000000000000000021541467225065400212210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "core/components/controls/amd/pm/auto/pmauto.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMAuto { class PMAutoTestAdapter : public ::AMD::PMAuto { public: MAKE_MOCK1(cleanControl, void(ICommandQueue &), override); MAKE_MOCK1(syncControl, void(ICommandQueue &), override); }; TEST_CASE("AMD PMAuto tests", "[GPU][AMD][PM][PMAuto]") { PMAutoTestAdapter ts; SECTION("Has PMAuto ID") { REQUIRE(ts.ID() == ::AMD::PMAuto::ItemID); } SECTION("Is active by default") { REQUIRE(ts.active()); } SECTION("Does not generate pre-init control commands") { CommandQueueStub cmds; ts.preInit(cmds); REQUIRE(cmds.commands().empty()); } SECTION("Does not generate post-init control commands") { CommandQueueStub cmds; ts.postInit(cmds); REQUIRE(cmds.commands().empty()); } } } // namespace Tests::AMD::PMAuto corectrl-v1.4.2/tests/src/test_amdpmautolegacy.cpp000066400000000000000000000051761467225065400224150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/auto/pmautolegacy.h" namespace Tests::AMD::PMAutoLegacy { class PMAutoLegacyTestAdapter : public ::AMD::PMAutoLegacy { public: using ::AMD::PMAutoLegacy::PMAutoLegacy; using ::AMD::PMAutoLegacy::cleanControl; using ::AMD::PMAutoLegacy::syncControl; }; TEST_CASE("AMD PMAutoLegacy tests", "[GPU][AMD][PM][PMAuto][Legacy]") { std::string const powerMethodPath{"power_method"}; std::string const powerProfilePath{"power_profile"}; CommandQueueStub ctlCmds; SECTION("Does not generate clean control commands") { PMAutoLegacyTestAdapter ts(std::make_unique(), std::make_unique()); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { PMAutoLegacyTestAdapter ts( std::make_unique(powerMethodPath, "profile"), std::make_unique(powerProfilePath, "auto")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when...") { SECTION("power_method is out of sync") { PMAutoLegacyTestAdapter ts( std::make_unique(powerMethodPath, "_other_"), std::make_unique(powerProfilePath, "auto")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == powerMethodPath); REQUIRE(cmd0Value == "profile"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == powerProfilePath); REQUIRE(cmd1Value == "auto"); } SECTION("power_profile is out of sync") { PMAutoLegacyTestAdapter ts( std::make_unique(powerMethodPath, "profile"), std::make_unique(powerProfilePath, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == powerMethodPath); REQUIRE(cmd0Value == "profile"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == powerProfilePath); REQUIRE(cmd1Value == "auto"); } } } } // namespace Tests::AMD::PMAutoLegacy corectrl-v1.4.2/tests/src/test_amdpmautor600.cpp000066400000000000000000000030131467225065400216240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/auto/pmautor600.h" namespace Tests::AMD::PMAutoR600 { class PMAutoR600TestAdapter : public ::AMD::PMAutoR600 { public: using ::AMD::PMAutoR600::PMAutoR600; using ::AMD::PMAutoR600::cleanControl; using ::AMD::PMAutoR600::syncControl; }; TEST_CASE("AMD PMAutoR600 tests", "[GPU][AMD][PM][PMAuto][R600]") { std::string const perfLevelPath{"power_dpm_force_performance_level"}; CommandQueueStub ctlCmds; SECTION("Does not generate clean control commands") { PMAutoR600TestAdapter ts(std::make_unique()); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { PMAutoR600TestAdapter ts( std::make_unique(perfLevelPath, "auto")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { PMAutoR600TestAdapter ts( std::make_unique(perfLevelPath, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == perfLevelPath); REQUIRE(value == "auto"); } } } // namespace Tests::AMD::PMAutoR600 corectrl-v1.4.2/tests/src/test_amdpmdynamicfreq.cpp000066400000000000000000000044351467225065400225570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/dynamicfreq/pmdynamicfreq.h" namespace Tests::AMD::PMDynamicFreq { class PMDynamicFreqTestAdapter : public ::AMD::PMDynamicFreq { public: using ::AMD::PMDynamicFreq::PMDynamicFreq; using ::AMD::PMDynamicFreq::cleanControl; using ::AMD::PMDynamicFreq::syncControl; }; TEST_CASE("AMD PMDynamicFreq tests", "[GPU][AMD][PM][PMAdvanced][PMDynamicFreq]") { std::string const path{"power_dpm_force_performance_level"}; CommandQueueStub ctlCmds; SECTION("Has PMDynamicFreq ID") { PMDynamicFreqTestAdapter ts(std::make_unique()); REQUIRE(ts.ID() == ::AMD::PMDynamicFreq::ItemID); } SECTION("Is not active by default") { PMDynamicFreqTestAdapter ts(std::make_unique()); REQUIRE_FALSE(ts.active()); } SECTION("Does not generate pre-init control commands") { PMDynamicFreqTestAdapter ts(std::make_unique()); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { PMDynamicFreqTestAdapter ts(std::make_unique()); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate clean control commands") { PMDynamicFreqTestAdapter ts(std::make_unique()); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { PMDynamicFreqTestAdapter ts( std::make_unique(path, "auto")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { PMDynamicFreqTestAdapter ts( std::make_unique(path, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == path); REQUIRE(value == "auto"); } } } // namespace Tests::AMD::PMDynamicFreq corectrl-v1.4.2/tests/src/test_amdpmfixed.cpp000066400000000000000000000057121467225065400213530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "core/components/controls/amd/pm/fixed/pmfixed.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMFixed { class PMFixedTestAdapter : public ::AMD::PMFixed { public: using ::AMD::PMFixed::PMFixed; using ::AMD::PMFixed::exportControl; using ::AMD::PMFixed::importControl; using ::AMD::PMFixed::mode; MAKE_MOCK1(cleanControl, void(ICommandQueue &), override); MAKE_MOCK1(syncControl, void(ICommandQueue &), override); MAKE_CONST_MOCK0(modes, std::vector const &(), override); }; class PMFixedImporterStub : public ::AMD::PMFixed::Importer { public: PMFixedImporterStub(std::string mode) : mode_(std::move(mode)) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &providePMFixedMode() const override { return mode_; } private: std::string mode_; }; class PMFixedExporterMock : public ::AMD::PMFixed::Exporter { public: MAKE_MOCK1(takePMFixedMode, void(std::string const &), override); MAKE_MOCK1(takePMFixedModes, void(std::vector const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMFixed tests", "[GPU][AMD][PM][PMFixed]") { std::vector const modes{"_mode_0_", "_mode_1_"}; PMFixedTestAdapter ts("_mode_0_"); ALLOW_CALL(ts, modes()).LR_RETURN(modes); SECTION("Has PMFixed ID") { REQUIRE(ts.ID() == ::AMD::PMFixed::ItemID); } SECTION("Is not active by default") { REQUIRE_FALSE(ts.active()); } SECTION("mode only sets known modes") { REQUIRE_CALL(ts, modes()).LR_RETURN(modes); ts.mode("_mode_1_"); REQUIRE(ts.mode() == "_mode_1_"); ts.mode("unkown"); REQUIRE(ts.mode() == "_mode_1_"); } SECTION("Does not generate pre-init control commands") { CommandQueueStub cmds; ts.preInit(cmds); REQUIRE(cmds.commands().empty()); } SECTION("Does not generate post-init control commands") { CommandQueueStub cmds; ts.postInit(cmds); REQUIRE(cmds.commands().empty()); } SECTION("Imports its mode") { PMFixedImporterStub i("_mode_1_"); ts.importControl(i); REQUIRE(ts.mode() == "_mode_1_"); } SECTION("Export its mode and available modes") { trompeloeil::sequence seq; PMFixedExporterMock e; REQUIRE_CALL(e, takePMFixedModes(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFixedMode(trompeloeil::eq("_mode_0_"))).IN_SEQUENCE(seq); ts.exportControl(e); } } } // namespace Tests::AMD::PMFixed corectrl-v1.4.2/tests/src/test_amdpmfixedfreq.cpp000066400000000000000000000154041467225065400222300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/ppdpmhandlermock.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/fixedfreq/pmfixedfreq.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMFixedFreq { class PMFixedFreqTestAdapter : public ::AMD::PMFixedFreq { public: using ::AMD::PMFixedFreq::PMFixedFreq; using PMFixedFreq::cleanControl; using PMFixedFreq::exportControl; using PMFixedFreq::importControl; using PMFixedFreq::syncControl; }; class PMFixedFreqImporterStub : public ::AMD::PMFixedFreq::Importer { public: PMFixedFreqImporterStub(unsigned int sclkIndex, unsigned int mclkIndex) : sclkIndex_(sclkIndex) , mclkIndex_(mclkIndex) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } unsigned int providePMFixedFreqSclkIndex() const override { return sclkIndex_; } unsigned int providePMFixedFreqMclkIndex() const override { return mclkIndex_; } private: unsigned int sclkIndex_; unsigned int mclkIndex_; }; class PMFixedFreqExporterMock : public ::AMD::PMFixedFreq::Exporter { public: MAKE_MOCK1(takePMFixedFreqSclkIndex, void(unsigned int), override); MAKE_MOCK1(takePMFixedFreqMclkIndex, void(unsigned int), override); MAKE_MOCK1( takePMFixedFreqSclkStates, void(std::vector> const &), override); MAKE_MOCK1( takePMFixedFreqMclkStates, void(std::vector> const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMFixedFreq tests", "[GPU][AMD][PM][PMAdvanced][PMFixedFreq]") { CommandQueueStub ctlCmds; std::vector> states{ {0, units::frequency::megahertz_t(300)}, {1, units::frequency::megahertz_t(2000)}}; auto ppDpmSclkMock = std::make_unique(states); auto ppDpmMclkMock = std::make_unique(states); std::vector activeStates{0}; SECTION("Has PMFixedFreq ID") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); REQUIRE(ts.ID() == ::AMD::PMFixedFreq::ItemID); } SECTION("Is active by default") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); REQUIRE(ts.active()); } SECTION("Has first state selected by default") { REQUIRE_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); REQUIRE_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); } SECTION("Does not generate pre-init control commands") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Import its state") { REQUIRE_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); REQUIRE_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); auto &ppDpmSclkMockRef = *ppDpmSclkMock; auto &ppDpmMclkMockRef = *ppDpmMclkMock; PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); std::vector sclkState{0}; std::vector mclkState{1}; REQUIRE_CALL(ppDpmSclkMockRef, activate(trompeloeil::_)).WITH(_1 == sclkState); REQUIRE_CALL(ppDpmMclkMockRef, activate(trompeloeil::_)).WITH(_1 == mclkState); PMFixedFreqImporterStub i(0, 1); ts.importControl(i); } SECTION("Export its state and available states") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); REQUIRE_CALL(*ppDpmSclkMock, active()).LR_RETURN(activeStates); REQUIRE_CALL(*ppDpmMclkMock, active()).LR_RETURN(activeStates); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); trompeloeil::sequence seq; PMFixedFreqExporterMock e; REQUIRE_CALL(e, takePMFixedFreqSclkStates(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFixedFreqSclkIndex(trompeloeil::eq(0u))).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFixedFreqMclkStates(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFixedFreqMclkIndex(trompeloeil::eq(0u))).IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Resets ppDpmHandlers on clean") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); REQUIRE_CALL(*ppDpmSclkMock, reset(trompeloeil::_)); REQUIRE_CALL(*ppDpmMclkMock, reset(trompeloeil::_)); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Sync ppDpmHandlers on sync") { ALLOW_CALL(*ppDpmSclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); ALLOW_CALL(*ppDpmMclkMock, activate(trompeloeil::_)).WITH(_1 == activeStates); REQUIRE_CALL(*ppDpmSclkMock, sync(trompeloeil::_)); REQUIRE_CALL(*ppDpmMclkMock, sync(trompeloeil::_)); PMFixedFreqTestAdapter ts(std::move(ppDpmSclkMock), std::move(ppDpmMclkMock)); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } } } // namespace Tests::AMD::PMFixedFreq corectrl-v1.4.2/tests/src/test_amdpmfixedlegacy.cpp000066400000000000000000000100041467225065400225260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/fixed/pmfixedlegacy.h" namespace Tests::AMD::PMFixedLegacy { class PMFixedLegacyTestAdapter : public ::AMD::PMFixedLegacy { public: using ::AMD::PMFixedLegacy::PMFixedLegacy; using ::AMD::PMFixedLegacy::cleanControl; using ::AMD::PMFixedLegacy::mode; using ::AMD::PMFixedLegacy::modes; using ::AMD::PMFixedLegacy::syncControl; }; TEST_CASE("AMD PMFixedLegacy tests", "[GPU][AMD][PM][PMFixed][Legacy]") { std::string const powerMethodPath{"power_method"}; std::string const powerProfilePath{"power_profile"}; CommandQueueStub ctlCmds; SECTION("Has 'low' mode selected by default") { PMFixedLegacyTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE(ts.mode() == "low"); } SECTION("Has [low, mid, high] modes") { std::vector const powerProfiles{"low", "mid", "high"}; PMFixedLegacyTestAdapter ts(std::make_unique(), std::make_unique()); REQUIRE(ts.modes() == powerProfiles); } SECTION("Does generate clean control commands") { PMFixedLegacyTestAdapter ts( std::make_unique(powerMethodPath, "profile"), std::make_unique(powerProfilePath, "low")); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == powerMethodPath); REQUIRE(cmd0Value == "profile"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == powerProfilePath); REQUIRE(cmd1Value == "auto"); } SECTION("Does not generate sync control commands when is synced") { PMFixedLegacyTestAdapter ts( std::make_unique(powerMethodPath, "profile"), std::make_unique(powerProfilePath, "low")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when...") { SECTION("power_method is out of sync") { PMFixedLegacyTestAdapter ts( std::make_unique(powerMethodPath, "_other_"), std::make_unique(powerProfilePath, "low")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == powerMethodPath); REQUIRE(cmd0Value == "profile"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == powerProfilePath); REQUIRE(cmd1Value == "low"); } SECTION("power_profile is out of sync") { PMFixedLegacyTestAdapter ts( std::make_unique(powerMethodPath, "profile"), std::make_unique(powerProfilePath, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == powerProfilePath); REQUIRE(cmdValue == "low"); } } SECTION("power_method and power_profile are out of sync") { PMFixedLegacyTestAdapter ts( std::make_unique(powerMethodPath, "_other_"), std::make_unique(powerProfilePath, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 2); auto &[cmd0Path, cmd0Value] = ctlCmds.commands().front(); REQUIRE(cmd0Path == powerMethodPath); REQUIRE(cmd0Value == "profile"); auto &[cmd1Path, cmd1Value] = ctlCmds.commands().back(); REQUIRE(cmd1Path == powerProfilePath); REQUIRE(cmd1Value == "low"); } } } // namespace Tests::AMD::PMFixedLegacy corectrl-v1.4.2/tests/src/test_amdpmfixedr600.cpp000066400000000000000000000041631467225065400217620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/fixed/pmfixedr600.h" namespace Tests::AMD::PMFixedR600 { class PMFixedR600TestAdapter : public ::AMD::PMFixedR600 { public: using ::AMD::PMFixedR600::PMFixedR600; using ::AMD::PMFixedR600::cleanControl; using ::AMD::PMFixedR600::mode; using ::AMD::PMFixedR600::modes; using ::AMD::PMFixedR600::syncControl; }; TEST_CASE("AMD PMFixedR600 tests", "[GPU][AMD][PM][PMFixed][R600]") { std::string const perfLevelPath{"power_dpm_force_performance_level"}; CommandQueueStub ctlCmds; SECTION("Has 'low' mode selected by default") { PMFixedR600TestAdapter ts(std::make_unique()); REQUIRE(ts.mode() == "low"); } SECTION("Has [low, high] modes") { std::vector const perfLevels{"low", "high"}; PMFixedR600TestAdapter ts(std::make_unique()); REQUIRE(ts.modes() == perfLevels); } SECTION("Does generate clean control commands") { PMFixedR600TestAdapter ts( std::make_unique(perfLevelPath, "low")); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == perfLevelPath); REQUIRE(value == "auto"); } SECTION("Does not generate sync control commands when is synced") { PMFixedR600TestAdapter ts( std::make_unique(perfLevelPath, "low")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { PMFixedR600TestAdapter ts( std::make_unique(perfLevelPath, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == perfLevelPath); REQUIRE(value == "low"); } } } // namespace Tests::AMD::PMFixedR600 corectrl-v1.4.2/tests/src/test_amdpmfreqmode.cpp000066400000000000000000000012531467225065400220520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/controls/amd/pm/advanced/freqmode/pmfreqmode.h" namespace Tests::AMD::PMFreqMode { TEST_CASE("AMD PMFreqMode tests", "[GPU][AMD][PM][PMAdvanced][PMFreqMode]") { std::vector> controlMocks; SECTION("Has PMFreqMode ID") { ::AMD::PMFreqMode ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::PMFreqMode::ItemID); } SECTION("Is active by default") { ::AMD::PMFreqMode ts(std::move(controlMocks)); REQUIRE(ts.active()); } } } // namespace Tests::AMD::PMFreqMode corectrl-v1.4.2/tests/src/test_amdpmfreqod.cpp000066400000000000000000000177601467225065400215420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/uintdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/overclock/freqod/pmfreqod.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMFreqOd { class PMFreqOdTestAdapter : public ::AMD::PMFreqOd { public: using ::AMD::PMFreqOd::PMFreqOd; using PMFreqOd::baseMclk; using PMFreqOd::baseSclk; using PMFreqOd::cleanControl; using PMFreqOd::exportControl; using PMFreqOd::importControl; using PMFreqOd::mclkOd; using PMFreqOd::sclkOd; using PMFreqOd::syncControl; }; class PMFreqOdImporterStub : public ::AMD::PMFreqOd::Importer { public: PMFreqOdImporterStub(unsigned int sclkOd, unsigned int mclkOd) : sclkOd_(sclkOd) , mclkOd_(mclkOd) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } unsigned int providePMFreqOdSclkOd() const override { return sclkOd_; } unsigned int providePMFreqOdMclkOd() const override { return mclkOd_; } private: unsigned int sclkOd_; unsigned int mclkOd_; }; class PMFreqOdExporterMock : public ::AMD::PMFreqOd::Exporter { public: MAKE_MOCK1(takePMFreqOdSclkOd, void(unsigned int), override); MAKE_MOCK1(takePMFreqOdMclkOd, void(unsigned int), override); MAKE_MOCK1(takePMFreqOdBaseSclk, void(units::frequency::megahertz_t), override); MAKE_MOCK1(takePMFreqOdBaseMclk, void(units::frequency::megahertz_t), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMFreqOd tests", "[GPU][AMD][PM][PMAdvanced][PMOverclock][PMFreqOd]") { CommandQueueStub ctlCmds; std::vector> const states{ std::make_pair(0u, units::frequency::megahertz_t(300)), std::make_pair(1u, units::frequency::megahertz_t(2000))}; SECTION("Has PMFreqOd ID") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); REQUIRE(ts.ID() == ::AMD::PMFreqOd::ItemID); } SECTION("Is active by default") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); REQUIRE(ts.active()); } SECTION("Has 0 as sclk & mclk od values by default") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); REQUIRE(ts.sclkOd() == 0); REQUIRE(ts.mclkOd() == 0); } SECTION("Initializes base sclk from sclk states on construction") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.init(); REQUIRE(ts.baseSclk() == units::frequency::megahertz_t(2000)); } SECTION("Initializes base mclk from mclk states on construction") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.init(); REQUIRE(ts.baseMclk() == units::frequency::megahertz_t(2000)); } SECTION("Clamps sclkOd in [0, 20] range") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.sclkOd(21); REQUIRE(ts.sclkOd() == 20); } SECTION("Clamps mclkOd in [0, 20] range") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.mclkOd(21); REQUIRE(ts.mclkOd() == 20); } SECTION("Does not generate pre-init control commands") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Import its state") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.init(); PMFreqOdImporterStub i(2, 3); ts.importControl(i); REQUIRE(ts.sclkOd() == 2); REQUIRE(ts.mclkOd() == 3); } SECTION("Export its state and available states") { PMFreqOdTestAdapter ts(std::make_unique(), std::make_unique(), states, states); ts.init(); trompeloeil::sequence seq; PMFreqOdExporterMock e; REQUIRE_CALL(e, takePMFreqOdBaseSclk( trompeloeil::eq(units::frequency::megahertz_t(2000)))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqOdBaseMclk( trompeloeil::eq(units::frequency::megahertz_t(2000)))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqOdSclkOd(trompeloeil::eq(0u))).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqOdMclkOd(trompeloeil::eq(0u))).IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Generate clean control commands unconditionally") { PMFreqOdTestAdapter ts( std::make_unique("pp_sclk_od", 0), std::make_unique("pp_mclk_od", 0), states, states); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.front(); REQUIRE(cmd0Path == "pp_sclk_od"); REQUIRE(cmd0Value == "0"); auto &[cmd1Path, cmd1Value] = commands.back(); REQUIRE(cmd1Path == "pp_mclk_od"); REQUIRE(cmd1Value == "0"); } SECTION("Does not generate sync control commands when is synced") { PMFreqOdTestAdapter ts( std::make_unique("pp_sclk_od", 1), std::make_unique("pp_mclk_od", 2), states, states); ts.init(); ts.sclkOd(1); ts.mclkOd(2); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when...") { SECTION("pp_sclk_od is out of sync") { PMFreqOdTestAdapter ts( std::make_unique("pp_sclk_od", 0), std::make_unique("pp_mclk_od", 0), states, states); ts.init(); ts.sclkOd(1); ts.mclkOd(0); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pp_sclk_od"); REQUIRE(cmdValue == "1"); } SECTION("pp_mclk_od is out of sync") { PMFreqOdTestAdapter ts( std::make_unique("pp_sclk_od", 0), std::make_unique("pp_mclk_od", 0), states, states); ts.init(); ts.sclkOd(0); ts.mclkOd(1); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pp_mclk_od"); REQUIRE(cmdValue == "1"); } } } } // namespace Tests::AMD::PMFreqOd corectrl-v1.4.2/tests/src/test_amdpmfreqrange.cpp000066400000000000000000000264251467225065400222320ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/overdrive/freqrange/pmfreqrange.h" #include extern template struct trompeloeil::reporter; namespace Tests::AMD::PMFreqRange { class PMFreqRangeTestAdapter : public ::AMD::PMFreqRange { public: using ::AMD::PMFreqRange::PMFreqRange; using ::AMD::PMFreqRange::cleanControl; using ::AMD::PMFreqRange::controlCmdId; using ::AMD::PMFreqRange::controlName; using ::AMD::PMFreqRange::exportControl; using ::AMD::PMFreqRange::importControl; using ::AMD::PMFreqRange::state; using ::AMD::PMFreqRange::stateRange; using ::AMD::PMFreqRange::states; using ::AMD::PMFreqRange::syncControl; }; class PMFreqRangeImporterStub final : public ::AMD::PMFreqRange::Importer { public: PMFreqRangeImporterStub( std::vector> const &states) : states_(states) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } units::frequency::megahertz_t providePMFreqRangeState(unsigned int index) const override { auto stateIt = std::find_if( states_.cbegin(), states_.cend(), [=](auto const &state) { return state.first == index; }); return stateIt->second; } private: std::vector> const states_; }; class PMFreqRangeExporterMock : public ::AMD::PMFreqRange::Exporter { public: MAKE_MOCK1(takePMFreqRangeControlName, void(std::string const &), override); MAKE_MOCK2(takePMFreqRangeStateRange, void(units::frequency::megahertz_t, units::frequency::megahertz_t), override); MAKE_MOCK1( takePMFreqRangeStates, void(std::vector> const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMFreqRange tests", "[GPU][AMD][PM][PMAdvanced][PMOverdrive][PMFreqRange]") { // clang-format off std::vector ppOdClkVoltageData { "OD_SCLK:", "0: 200MHz", "1: 1000MHz", "OD_RANGE:", "SCLK: 200MHz 2000MHz"}; // clang-format on CommandQueueStub ctlCmds; SECTION("Has PMFreqRange ID") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique()); REQUIRE(ts.ID() == ::AMD::PMFreqRange::ItemID); } SECTION("Is active by default") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique()); REQUIRE(ts.active()); } SECTION("Has overdrive control name") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique()); REQUIRE(ts.controlName() == "SCLK"); } SECTION("Has overdrive control command id") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique()); REQUIRE(ts.controlCmdId() == "s"); } SECTION("Does not generate pre-init control commands") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.preInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Generates post-init control commands") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "s 0 200"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "s 1 1000"); } SECTION( "Does not generate post-init control commands for disabled bound states") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), ::AMD::PMFreqRange::DisabledBound{1}); ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "s 0 200"); } SECTION("Initializes states and range from pp_od_clk_voltage data source") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); auto states = ts.states(); REQUIRE(states.size() == 2); auto &[s0Index, s0Freq] = states.at(0); REQUIRE(s0Index == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(200)); auto &[s1Index, s1Freq] = states.at(1); REQUIRE(s1Index == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(1000)); auto &[min, max] = ts.stateRange(); REQUIRE(min == units::frequency::megahertz_t(200)); REQUIRE(max == units::frequency::megahertz_t(2000)); } SECTION("Initializes states and range from pp_od_clk_voltage data source, " "skipping disabled bound states") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), ::AMD::PMFreqRange::DisabledBound{1}); ts.init(); auto states = ts.states(); REQUIRE(states.size() == 1); auto &[s0Index, s0Freq] = states.at(0); REQUIRE(s0Index == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(200)); auto &[min, max] = ts.stateRange(); REQUIRE(min == units::frequency::megahertz_t(200)); REQUIRE(max == units::frequency::megahertz_t(2000)); } SECTION("Clamps state frequency value in range") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); // min ts.state(0, units::frequency::megahertz_t(0)); // max ts.state(1, units::frequency::megahertz_t(10000)); auto states = ts.states(); REQUIRE(states.size() == 2); // min auto &[s0Index, s0Freq] = states.at(0); REQUIRE(s0Index == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(200)); // max auto &[s1Index, s1Freq] = states.at(1); REQUIRE(s1Index == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(2000)); } SECTION("Imports its state") { std::vector gpuActiveStates{0, 1}; std::vector memActiveStates{1}; PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); std::vector> states; states.emplace_back(0, units::frequency::megahertz_t(201)); states.emplace_back(1, units::frequency::megahertz_t(1001)); PMFreqRangeImporterStub i(states); ts.importControl(i); REQUIRE(ts.states() == states); } SECTION("Exports its state") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); std::vector> states; states.emplace_back(0, units::frequency::megahertz_t(200)); states.emplace_back(1, units::frequency::megahertz_t(1000)); trompeloeil::sequence seq; PMFreqRangeExporterMock e; REQUIRE_CALL(e, takePMFreqRangeControlName(trompeloeil::_)) .LR_WITH(_1 == "SCLK") .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqRangeStateRange( trompeloeil::eq(units::frequency::megahertz_t(200)), trompeloeil::eq(units::frequency::megahertz_t(2000)))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqRangeStates(trompeloeil::_)) .LR_WITH(_1 == states) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Does not generate clean control commands") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Does not generate sync control commands when is synced") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates sync control commands when is out of sync") { PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.state(0, units::frequency::megahertz_t(201)); ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "s 0 201"); } SECTION("Generated sync control commands ignores disabled bound state") { // clang-format off std::vector ppOdClkVoltageData { "OD_SCLK:", "0: 10MHz", // Bogus state that will be disabled "1: 1000MHz", "OD_RANGE:", "SCLK: 200MHz 2000MHz"}; // clang-format on PMFreqRangeTestAdapter ts("SCLK", "s", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), ::AMD::PMFreqRange::DisabledBound{0}); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } } } // namespace Tests::AMD::PMFreqRange corectrl-v1.4.2/tests/src/test_amdpmfreqvolt.cpp000066400000000000000000000344101467225065400221130ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/ppdpmhandlermock.h" #include "common/stringdatasourcestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/overdrive/freqvolt/pmfreqvolt.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMFreqVolt { class PMFreqVoltTestAdapter : public ::AMD::PMFreqVolt { public: using ::AMD::PMFreqVolt::PMFreqVolt; using ::AMD::PMFreqVolt::cleanControl; using ::AMD::PMFreqVolt::controlCmdId; using ::AMD::PMFreqVolt::controlName; using ::AMD::PMFreqVolt::exportControl; using ::AMD::PMFreqVolt::freqRange; using ::AMD::PMFreqVolt::importControl; using ::AMD::PMFreqVolt::state; using ::AMD::PMFreqVolt::states; using ::AMD::PMFreqVolt::syncControl; using ::AMD::PMFreqVolt::voltMode; using ::AMD::PMFreqVolt::voltModes; using ::AMD::PMFreqVolt::voltRange; }; class PMFreqVoltImporterStub final : public ::AMD::PMFreqVolt::Importer { public: PMFreqVoltImporterStub( std::string const &voltMode, std::vector> const &states, std::vector const &activeStates) : voltMode_(voltMode) , states_(states) , activeStates_(activeStates) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &providePMFreqVoltVoltMode() const override { return voltMode_; } std::pair providePMFreqVoltState(unsigned int index) const override { auto stateIt = std::find_if( states_.cbegin(), states_.cend(), [=](auto const &state) { return std::get<0>(state) == index; }); return {std::get<1>(*stateIt), std::get<2>(*stateIt)}; } std::vector providePMFreqVoltActiveStates() const override { return activeStates_; } private: std::string const voltMode_; std::vector> const states_; std::vector const activeStates_; }; class PMFreqVoltExporterMock : public ::AMD::PMFreqVolt::Exporter { public: MAKE_MOCK1(takePMFreqVoltControlName, void(std::string const &), override); MAKE_MOCK1(takePMFreqVoltVoltModes, void(std::vector const &), override); MAKE_MOCK1(takePMFreqVoltVoltMode, void(std::string const &), override); MAKE_MOCK2(takePMFreqVoltVoltRange, void(units::voltage::millivolt_t, units::voltage::millivolt_t), override); MAKE_MOCK2(takePMFreqVoltFreqRange, void(units::frequency::megahertz_t, units::frequency::megahertz_t), override); MAKE_MOCK1(takePMFreqVoltStates, void(std::vector> const &), override); MAKE_MOCK1(takePMFreqVoltActiveStates, void(std::vector const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMFreqVolt tests", "[GPU][AMD][PM][PMAdvanced][PMOverdrive][PMFreqVolt]") { std::vector> states{ {0, units::frequency::megahertz_t(300)}, {1, units::frequency::megahertz_t(2000)}}; auto ppDpmMock = std::make_unique(states); // clang-format off std::vector ppOdClkVoltageData { "OD_MCLK:", "0: 300MHz 800mV", "1: 3000MHz 900mV", "OD_RANGE:", "MCLK: 300MHz 3000MHz", "VDDC: 800mV 900mV" }; // clang-format on CommandQueueStub ctlCmds; SECTION("Has PMFreqVolt ID") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique(), std::move(ppDpmMock)); REQUIRE(ts.ID() == ::AMD::PMFreqVolt::ItemID); } SECTION("Is active by default") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique(), std::move(ppDpmMock)); REQUIRE(ts.active()); } SECTION("Has overdrive control name") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique(), std::move(ppDpmMock)); REQUIRE(ts.controlName() == "MCLK"); } SECTION("Has overdrive control command id") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique(), std::move(ppDpmMock)); REQUIRE(ts.controlCmdId() == "m"); } SECTION("Has 'auto' volt mode by default") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique(), std::move(ppDpmMock)); REQUIRE(ts.voltMode() == "auto"); } SECTION( "Resets dpm handler on pre-init but does not generates control commands") { REQUIRE_CALL(*ppDpmMock, saveState()); REQUIRE_CALL(*ppDpmMock, reset(trompeloeil::_)); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.preInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Generates post-init control commands") { REQUIRE_CALL(*ppDpmMock, saveState()); REQUIRE_CALL(*ppDpmMock, reset(trompeloeil::_)); REQUIRE_CALL(*ppDpmMock, restoreState(trompeloeil::_)); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "m 0 300 800"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "m 1 3000 900"); } SECTION("Initializes states and range from pp_od_clk_voltage data source") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); auto states = ts.states(); REQUIRE(states.size() == 2); auto &[s0Index, s0Freq, s0Volt] = states.at(0); REQUIRE(s0Index == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(300)); REQUIRE(s0Volt == units::voltage::millivolt_t(800)); auto &[s1Index, s1Freq, s1Volt] = states.at(1); REQUIRE(s1Index == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(3000)); REQUIRE(s1Volt == units::voltage::millivolt_t(900)); auto &[freqMin, freqMax] = ts.freqRange(); REQUIRE(freqMin == units::frequency::megahertz_t(300)); REQUIRE(freqMax == units::frequency::megahertz_t(3000)); auto &[voltMin, voltMax] = ts.voltRange(); REQUIRE(voltMin == units::voltage::millivolt_t(800)); REQUIRE(voltMax == units::voltage::millivolt_t(900)); } SECTION("Clamps state frequency and voltage values in range") { PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); // min ts.state(0, units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); // max ts.state(1, units::frequency::megahertz_t(10000), units::voltage::millivolt_t(10000)); auto states = ts.states(); REQUIRE(states.size() == 2); // min auto &[s0Index, s0Freq, s0Volt] = states.at(0); REQUIRE(s0Index == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(300)); REQUIRE(s0Volt == units::voltage::millivolt_t(800)); // max auto &[s1Index, s1Freq, s1Volt] = states.at(1); REQUIRE(s1Index == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(3000)); REQUIRE(s1Volt == units::voltage::millivolt_t(900)); } SECTION("Imports its state") { std::vector activeStates{0}; REQUIRE_CALL(*ppDpmMock, activate(trompeloeil::_)).LR_WITH(_1 == activeStates); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); std::vector> states; states.emplace_back(0, units::frequency::megahertz_t(301), units::voltage::millivolt_t(801)); states.emplace_back(1, units::frequency::megahertz_t(2000), units::voltage::millivolt_t(800)); PMFreqVoltImporterStub i("manual", states, activeStates); ts.importControl(i); REQUIRE(ts.voltMode() == "manual"); REQUIRE(ts.states() == states); } SECTION("Exports its state") { std::vector activeStates{0, 1}; ALLOW_CALL(*ppDpmMock, active()).LR_RETURN(activeStates); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); std::vector modes{"auto", "manual"}; std::vector> states; states.emplace_back(0, units::frequency::megahertz_t(300), units::voltage::millivolt_t(800)); states.emplace_back(1, units::frequency::megahertz_t(3000), units::voltage::millivolt_t(900)); trompeloeil::sequence seq; PMFreqVoltExporterMock e; REQUIRE_CALL(e, takePMFreqVoltControlName("MCLK")).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqVoltVoltModes(trompeloeil::_)) .LR_WITH(_1 == modes) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqVoltVoltMode("auto")).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqVoltFreqRange( trompeloeil::eq(units::frequency::megahertz_t(300)), trompeloeil::eq(units::frequency::megahertz_t(3000)))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqVoltVoltRange( trompeloeil::eq(units::voltage::millivolt_t(800)), trompeloeil::eq(units::voltage::millivolt_t(900)))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqVoltStates(trompeloeil::_)) .LR_WITH(_1 == states) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMFreqVoltActiveStates(trompeloeil::_)) .LR_WITH(_1 == activeStates) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Resets dpm handler but does not generates clean control commands") { REQUIRE_CALL(*ppDpmMock, reset(trompeloeil::_)); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Does not generate sync control commands when is synced") { REQUIRE_CALL(*ppDpmMock, sync(trompeloeil::_)); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates sync control commands when...") { SECTION("states are out of sync...") { REQUIRE_CALL(*ppDpmMock, sync(trompeloeil::_)); PMFreqVoltTestAdapter ts("MCLK", "m", std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(ppDpmMock)); ts.init(); SECTION("and volt mode is 'auto'") { ts.voltMode("auto"); ts.state(0, units::frequency::megahertz_t(301), units::voltage::millivolt_t(801)); // not used in the command ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "m 0 301 800"); } SECTION("and volt mode is 'manual'") { ts.voltMode("manual"); ts.state(0, units::frequency::megahertz_t(301), units::voltage::millivolt_t(801)); ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "m 0 301 801"); } } } } } // namespace Tests::AMD::PMFreqVolt corectrl-v1.4.2/tests/src/test_amdpmoverclock.cpp000066400000000000000000000012651467225065400222420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/controls/amd/pm/advanced/overclock/pmoverclock.h" namespace Tests::AMD::PMOverclock { TEST_CASE("AMD PMOverclock tests", "[GPU][AMD][PM][PMAdvanced][PMOverclock]") { std::vector> controlMocks; SECTION("Has PMOverclock ID") { ::AMD::PMOverclock ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::PMOverclock::ItemID); } SECTION("Is active by default") { ::AMD::PMOverclock ts(std::move(controlMocks)); REQUIRE(ts.active()); } } } // namespace Tests::AMD::PMOverclock corectrl-v1.4.2/tests/src/test_amdpmperfmode.cpp000066400000000000000000000012151467225065400220470ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/controls/amd/pm/pmperfmode.h" namespace Tests::AMD::PMPerfMode { TEST_CASE("AMD PMPerfMode tests", "[GPU][AMD][PM][PMPerfMode]") { std::vector> controlMocks; SECTION("Has PMPerfMode ID") { ::AMD::PMPerfMode ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::PMPerfMode::ItemID); } SECTION("Is active by default") { ::AMD::PMPerfMode ts(std::move(controlMocks)); REQUIRE(ts.active()); } } } // namespace Tests::AMD::PMPerfMode corectrl-v1.4.2/tests/src/test_amdpmpowercap.cpp000066400000000000000000000203231467225065400220670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "core/components/controls/amd/pm/advanced/powercap/pmpowercap.h" #include "core/idatasource.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMPowerCap { class ULongDataSourceStub : public IDataSource { public: ULongDataSourceStub(std::string_view source = "", unsigned long data = 0, bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(unsigned long &data) override { data = data_; return success_; } void data(unsigned long data) { data_ = data; } std::string const source_; unsigned long data_; bool success_; }; class PMPowerCapTestAdapter : public ::AMD::PMPowerCap { public: using ::AMD::PMPowerCap::PMPowerCap; using ::AMD::PMPowerCap::cleanControl; using ::AMD::PMPowerCap::exportControl; using ::AMD::PMPowerCap::importControl; using ::AMD::PMPowerCap::max; using ::AMD::PMPowerCap::min; using ::AMD::PMPowerCap::syncControl; using ::AMD::PMPowerCap::value; }; class PMPowerCapImporterStub : public ::AMD::PMPowerCap::Importer { public: PMPowerCapImporterStub(units::power::watt_t value) : value_(value) { } std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } units::power::watt_t providePMPowerCapValue() const override { return value_; } private: units::power::watt_t value_; }; class PMPowerCapExporterMock : public ::AMD::PMPowerCap::Exporter { public: MAKE_MOCK1(takePMPowerCapValue, void(units::power::watt_t), override); MAKE_MOCK2(takePMPowerCapRange, void(units::power::watt_t, units::power::watt_t), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMPowerCap tests", "[GPU][AMD][PM][PMPowerCap]") { CommandQueueStub ctlCmds; units::power::watt_t min(50); units::power::watt_t max(100); SECTION("Has PMPowerCap ID") { PMPowerCapTestAdapter ts(std::make_unique(), min, max); REQUIRE(ts.ID() == ::AMD::PMPowerCap::ItemID); } SECTION("Is active by default") { PMPowerCapTestAdapter ts(std::make_unique(), min, max); REQUIRE(ts.active()); } SECTION("Has 1 watt as minimum range value when 0 watt is supplied as the " "minimum value at construction") { // NOTE 0 watt is reserved for reseting the value PMPowerCapTestAdapter ts(std::make_unique(), units::power::watt_t(0), max); REQUIRE(ts.min() == units::power::watt_t(1)); } SECTION("Clamp its value in the [min, max] range") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 50000000), min, max); ts.value(units::power::watt_t(0)); REQUIRE(ts.value() == min); ts.value(units::power::watt_t(500)); REQUIRE(ts.value() == max); } SECTION("Generate pre-init control commands when default power cap is not " "available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 10000000), min, max); ts.preInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmdPath, cmdValue] = commands.at(0); REQUIRE(cmdPath == "power1_cap"); REQUIRE(cmdValue == "0"); } SECTION("Does not generate pre-init control commands when default power cap " "is available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 10000000), min, max, units::power::watt_t(75)); ts.preInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Generate post-init control commands when default power cap is not " "available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 10000000), min, max); ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmdPath, cmdValue] = commands.at(0); REQUIRE(cmdPath == "power1_cap"); REQUIRE(cmdValue == "10000000"); // restore pre-init value } SECTION("Does not generate post-init control commands when default power cap " "is available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 10000000), min, max, units::power::watt_t(75)); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Power cap has the value of the default power cap when the later is " "available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 50000000), min, max, units::power::watt_t(75)); REQUIRE(ts.value() == units::power::watt_t(75)); } SECTION("Initializes power cap value from power1_cap data source when " "default power cap is not available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 50000000), min, max); ts.init(); REQUIRE(ts.value() == units::power::watt_t(50)); } SECTION("Imports its state") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap"), min, max); PMPowerCapImporterStub i(units::power::watt_t(80)); ts.importWith(i); REQUIRE(ts.value() == units::power::watt_t(80)); } SECTION("Export its state") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap"), min, max); units::power::watt_t value(80); ts.value(value); trompeloeil::sequence seq; PMPowerCapExporterMock e; REQUIRE_CALL(e, takePMPowerCapRange(trompeloeil::_, trompeloeil::_)) .LR_WITH(_1 == min) .LR_WITH(_2 == max) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMPowerCapValue(trompeloeil::_)) .LR_WITH(_1 == value) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Generate clean control commands...") { SECTION( "To restore the default value when default power cap is not available") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap"), min, max); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmdPath, cmdValue] = commands.at(0); REQUIRE(cmdPath == "power1_cap"); REQUIRE(cmdValue == "0"); } SECTION( "Assigning the default power value when default power cap is available") { units::power::watt_t defaultValue(75); PMPowerCapTestAdapter ts( std::make_unique("power1_cap"), min, max, defaultValue); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmdPath, cmdValue] = commands.at(0); REQUIRE(cmdPath == "power1_cap"); REQUIRE(cmdValue == "75000000"); } } SECTION("Does not generate sync control commands when is synced") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 50000000), min, max); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { PMPowerCapTestAdapter ts( std::make_unique("power1_cap", 50000000), min, max); ts.init(); ts.value(units::power::watt_t(80)); ts.sync(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmdPath, cmdValue] = commands.at(0); REQUIRE(cmdPath == "power1_cap"); REQUIRE(cmdValue == "80000000"); } } } // namespace Tests::AMD::PMPowerCap corectrl-v1.4.2/tests/src/test_amdpmpowerprofile.cpp000066400000000000000000000217651467225065400227770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/powerprofile/pmpowerprofile.h" #include "core/idatasource.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMPowerProfile { class PMPowerProfileTestAdapter : public ::AMD::PMPowerProfile { public: using ::AMD::PMPowerProfile::PMPowerProfile; using PMPowerProfile::cleanControl; using PMPowerProfile::exportControl; using PMPowerProfile::importControl; using PMPowerProfile::mode; using PMPowerProfile::modes; using PMPowerProfile::syncControl; }; class PMPowerProfileImporterStub : public ::AMD::PMPowerProfile::Importer { public: PMPowerProfileImporterStub(std::string mode) : mode_(std::move(mode)) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &providePMPowerProfileMode() const override { return mode_; } private: std::string mode_; }; class PMPowerProfileExporterMock : public ::AMD::PMPowerProfile::Exporter { public: MAKE_MOCK1(takePMPowerProfileModes, void(std::vector const &), override); MAKE_MOCK1(takePMPowerProfileMode, void(std::string const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; class OptionalIntDataSourceStub : public IDataSource> { public: OptionalIntDataSourceStub(std::string_view source = "", std::optional data = std::nullopt, bool success = true) noexcept : source_(source) , data_(data) , success_(success) { } std::string source() const override { return source_; } bool read(std::optional &data) override { data = data_; return success_; } std::string const source_; std::optional const data_; bool success_; }; TEST_CASE("AMD PMPowerProfile tests", "[GPU][AMD][PM][PMAdvanced][PMPowerProfile]") { CommandQueueStub ctlCmds; std::vector> modes{ std::make_pair("3D_FULL_SCREEN", 0), std::make_pair("POWER_SAVING", 1)}; SECTION("Has PMPowerProfile ID") { PMPowerProfileTestAdapter ts(std::make_unique(), std::make_unique(), modes); REQUIRE(ts.ID() == ::AMD::PMPowerProfile::ItemID); } SECTION("Is active by default") { PMPowerProfileTestAdapter ts(std::make_unique(), std::make_unique(), modes); REQUIRE(ts.active()); } SECTION("Has first mode selected by default") { PMPowerProfileTestAdapter ts( std::make_unique(), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); REQUIRE(ts.mode() == "3D_FULL_SCREEN"); } SECTION("mode ignores unknown modes") { PMPowerProfileTestAdapter ts( std::make_unique(), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); ts.mode("UNKNOWN"); REQUIRE(ts.mode() == "3D_FULL_SCREEN"); } SECTION("Does not generate pre-init control commands") { PMPowerProfileTestAdapter ts(std::make_unique(), std::make_unique(), modes); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { PMPowerProfileTestAdapter ts(std::make_unique(), std::make_unique(), modes); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Import its mode") { PMPowerProfileTestAdapter ts( std::make_unique(), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); ts.init(); PMPowerProfileImporterStub i("POWER_SAVING"); ts.importControl(i); REQUIRE(ts.mode() == "POWER_SAVING"); } SECTION("Export its mode and available modes") { PMPowerProfileTestAdapter ts( std::make_unique(), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); ts.init(); trompeloeil::sequence seq; PMPowerProfileExporterMock e; REQUIRE_CALL(e, takePMPowerProfileModes(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMPowerProfileMode(trompeloeil::eq("3D_FULL_SCREEN"))) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Generate clean control commands...") { SECTION("Including performance level command when its value is not manual") { PMPowerProfileTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands[0]; REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); auto &[cmd1Path, cmd1Value] = commands[1]; REQUIRE(cmd1Path == "pp_power_profile_mode"); REQUIRE(cmd1Value == "0"); } SECTION("Excluding performance level command when its value is manual") { PMPowerProfileTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands[0]; REQUIRE(cmd0Path == "pp_power_profile_mode"); REQUIRE(cmd0Value == "0"); } } SECTION("Does not generate sync control commands when is synced") { PMPowerProfileTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_power_profile_mode", std::make_optional(1)), modes); ts.init(); ts.mode("POWER_SAVING"); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when...") { SECTION("power_dpm_force_performance_level is out of sync") { PMPowerProfileTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique("pp_power_profile_mode", std::make_optional(0)), modes); ts.init(); ts.mode("POWER_SAVING"); ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands[0]; REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); auto &[cmd1Path, cmd1Value] = commands[1]; REQUIRE(cmd1Path == "pp_power_profile_mode"); REQUIRE(cmd1Value == "1"); } SECTION("pp_power_profile_mode is out of sync") { PMPowerProfileTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_power_profile_mode", std::make_optional(1)), modes); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[cmdPath, cmdValue] = ctlCmds.commands().front(); REQUIRE(cmdPath == "pp_power_profile_mode"); REQUIRE(cmdValue == "0"); } } } } // namespace Tests::AMD::PMPowerProfile corectrl-v1.4.2/tests/src/test_amdpmpowerstate.cpp000066400000000000000000000115011467225065400224420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/amd/pm/powerstate/pmpowerstate.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMPowerState { class PMPowerStateTestAdapter : public ::AMD::PMPowerState { public: using ::AMD::PMPowerState::PMPowerState; using ::AMD::PMPowerState::cleanControl; using ::AMD::PMPowerState::exportControl; using ::AMD::PMPowerState::importControl; using ::AMD::PMPowerState::mode; using ::AMD::PMPowerState::modes; using ::AMD::PMPowerState::syncControl; }; class PMPowerStateImporterStub : public ::AMD::PMPowerState::Importer { public: PMPowerStateImporterStub(std::string_view mode) : mode_(mode) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &providePMPowerStateMode() const override { return mode_; } private: std::string mode_; }; class PMPowerStateExporterMock : public ::AMD::PMPowerState::Exporter { public: MAKE_MOCK1(takePMPowerStateMode, void(std::string const &), override); MAKE_MOCK1(takePMPowerStateModes, void(std::vector const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMPowerState tests", "[GPU][AMD][PM][PMPowerState]") { std::string const powerDpmStatePath{"power_dpm_state"}; CommandQueueStub ctlCmds; SECTION("Has PMPowerState ID") { PMPowerStateTestAdapter ts(std::make_unique()); REQUIRE(ts.ID() == ::AMD::PMPowerState::ItemID); } SECTION("Is active by default") { PMPowerStateTestAdapter ts(std::make_unique()); REQUIRE(ts.active()); } SECTION("Has 'balanced' mode selected by default") { PMPowerStateTestAdapter ts(std::make_unique()); REQUIRE(ts.mode() == "balanced"); } SECTION("Has [battery, balanced, performance] modes") { std::vector const modes{std::string("battery"), std::string("balanced"), std::string("performance")}; PMPowerStateTestAdapter ts(std::make_unique()); REQUIRE(ts.modes() == modes); } SECTION("mode only sets known modes") { PMPowerStateTestAdapter ts(std::make_unique()); ts.mode("performance"); REQUIRE(ts.mode() == "performance"); ts.mode("unkown"); REQUIRE(ts.mode() == "performance"); } SECTION("Does not generate pre-init control commands") { PMPowerStateTestAdapter ts(std::make_unique()); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { PMPowerStateTestAdapter ts(std::make_unique()); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Imports its mode") { PMPowerStateTestAdapter ts(std::make_unique()); PMPowerStateImporterStub i("performance"); ts.importControl(i); REQUIRE(ts.mode() == "performance"); } SECTION("Export its mode and available modes") { PMPowerStateTestAdapter ts(std::make_unique()); PMPowerStateExporterMock e; trompeloeil::sequence seq; REQUIRE_CALL(e, takePMPowerStateModes(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMPowerStateMode(trompeloeil::eq("balanced"))) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Does not generate clean control commands") { PMPowerStateTestAdapter ts(std::make_unique()); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { PMPowerStateTestAdapter ts( std::make_unique(powerDpmStatePath, "balanced")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { PMPowerStateTestAdapter ts( std::make_unique(powerDpmStatePath, "_other_")); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == powerDpmStatePath); REQUIRE(value == "balanced"); } } } // namespace Tests::AMD::PMPowerState corectrl-v1.4.2/tests/src/test_amdpmvoltcurve.cpp000066400000000000000000000313421467225065400223030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/overdrive/voltcurve/pmvoltcurve.h" extern template struct trompeloeil::reporter; namespace Tests::AMD::PMVoltCurve { class PMVoltCurveTestAdapter : public ::AMD::PMVoltCurve { public: using ::AMD::PMVoltCurve::PMVoltCurve; using ::AMD::PMVoltCurve::cleanControl; using ::AMD::PMVoltCurve::controlCmdId; using ::AMD::PMVoltCurve::exportControl; using ::AMD::PMVoltCurve::importControl; using ::AMD::PMVoltCurve::mode; using ::AMD::PMVoltCurve::modes; using ::AMD::PMVoltCurve::point; using ::AMD::PMVoltCurve::points; using ::AMD::PMVoltCurve::pointsRange; using ::AMD::PMVoltCurve::syncControl; }; class PMVoltCurveImporterStub final : public ::AMD::PMVoltCurve::Importer { public: PMVoltCurveImporterStub( std::string const &mode, std::vector> const points) : mode_(mode) , points_(points) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &providePMVoltCurveMode() const override { return mode_; } std::pair providePMVoltCurvePoint(unsigned int index) const override { return points_[index]; } private: std::string const mode_; std::vector> const points_; }; class PMVoltCurveExporterMock : public ::AMD::PMVoltCurve::Exporter { public: MAKE_MOCK1(takePMVoltCurveModes, void(std::vector const &), override); MAKE_MOCK1(takePMVoltCurveMode, void(std::string const &), override); MAKE_MOCK1( takePMVoltCurvePointsRange, void(std::vector, std::pair>> const &), override); MAKE_MOCK1(takePMVoltCurvePoints, void(std::vector> const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMVoltCurve tests", "[GPU][AMD][PM][PMAdvanced][PMOverdrive][PMVoltCurve]") { // clang-format off std::vector ppOdClkVoltageData { "OD_SCLK:", "0: 200MHz", "1: 1000MHz", "OD_MCLK:", "1: 1000MHz", "OD_VDDC_CURVE:", "0: 200MHz 800mV", "1: 1000MHz 850mV", "2: 2000MHz 900mV", "OD_RANGE:", "SCLK: 200MHz 2000MHz", "MCLK: 300MHz 3000MHz", "VDDC_CURVE_SCLK[0]: 200MHz 2000MHz", "VDDC_CURVE_VOLT[0]: 800mV 900mV", "VDDC_CURVE_SCLK[1]: 200MHz 2000MHz", "VDDC_CURVE_VOLT[1]: 800mV 900mV", "VDDC_CURVE_SCLK[2]: 200MHz 2000MHz", "VDDC_CURVE_VOLT[2]: 800mV 900mV" }; // clang-format on CommandQueueStub ctlCmds; SECTION("Has PMVoltCurve ID") { PMVoltCurveTestAdapter ts("vc", std::make_unique()); REQUIRE(ts.ID() == ::AMD::PMVoltCurve::ItemID); } SECTION("Is active by default") { PMVoltCurveTestAdapter ts("vc", std::make_unique()); REQUIRE(ts.active()); } SECTION("Has 'auto' mode by default") { PMVoltCurveTestAdapter ts("vc", std::make_unique()); REQUIRE(ts.mode() == "auto"); } SECTION("Has overdrive control command id") { PMVoltCurveTestAdapter ts("vc", std::make_unique()); REQUIRE(ts.controlCmdId() == "vc"); } SECTION("Does not generate pre-init control commands") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.preInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Generate post-init control commands") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 3); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "vc 0 200 800"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "vc 1 1000 850"); auto &[cmd2Path, cmd2Value] = commands.at(2); REQUIRE(cmd2Path == "pp_od_clk_voltage"); REQUIRE(cmd2Value == "vc 2 2000 900"); } SECTION("Initializes points and range from pp_od_clk_voltage data source") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); auto &pointsRange = ts.pointsRange(); REQUIRE(pointsRange.size() == 3); auto &[p0RangeFreq, p0RangeVolt] = pointsRange.at(0); REQUIRE(p0RangeFreq.first == units::frequency::megahertz_t(200)); REQUIRE(p0RangeFreq.second == units::frequency::megahertz_t(2000)); REQUIRE(p0RangeVolt.first == units::voltage::millivolt_t(800)); REQUIRE(p0RangeVolt.second == units::voltage::millivolt_t(900)); auto &[p1RangeFreq, p1RangeVolt] = pointsRange.at(1); REQUIRE(p1RangeFreq.first == units::frequency::megahertz_t(200)); REQUIRE(p1RangeFreq.second == units::frequency::megahertz_t(2000)); REQUIRE(p1RangeVolt.first == units::voltage::millivolt_t(800)); REQUIRE(p1RangeVolt.second == units::voltage::millivolt_t(900)); auto &[p2RangeFreq, p2RangeVolt] = pointsRange.at(2); REQUIRE(p2RangeFreq.first == units::frequency::megahertz_t(200)); REQUIRE(p2RangeFreq.second == units::frequency::megahertz_t(2000)); REQUIRE(p2RangeVolt.first == units::voltage::millivolt_t(800)); REQUIRE(p2RangeVolt.second == units::voltage::millivolt_t(900)); auto &points = ts.points(); auto &[p0Freq, p0Volt] = points.at(0); REQUIRE(p0Freq == units::frequency::megahertz_t(200)); REQUIRE(p0Volt == units::voltage::millivolt_t(800)); auto &[p1Freq, p1Volt] = points.at(1); REQUIRE(p1Freq == units::frequency::megahertz_t(1000)); REQUIRE(p1Volt == units::voltage::millivolt_t(850)); auto &[p2Freq, p2Volt] = points.at(2); REQUIRE(p2Freq == units::frequency::megahertz_t(2000)); REQUIRE(p2Volt == units::voltage::millivolt_t(900)); } SECTION("Clamps point values in range") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); // min ts.point(0, units::frequency::megahertz_t(0), units::voltage::millivolt_t(0)); // max ts.point(1, units::frequency::megahertz_t(10000), units::voltage::millivolt_t(10000)); auto curve = ts.points(); REQUIRE(curve.size() == 3); // min auto &[p0Freq, p0Volt] = curve.at(0); REQUIRE(p0Freq == units::frequency::megahertz_t(200)); REQUIRE(p0Volt == units::voltage::millivolt_t(800)); // max auto &[p1Freq, p1Volt] = curve.at(1); REQUIRE(p1Freq == units::frequency::megahertz_t(2000)); REQUIRE(p1Volt == units::voltage::millivolt_t(900)); } SECTION("Imports its state") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); std::vector> points; points.emplace_back(units::frequency::megahertz_t(201), units::voltage::millivolt_t(801)); points.emplace_back(units::frequency::megahertz_t(1001), units::voltage::millivolt_t(851)); points.emplace_back(units::frequency::megahertz_t(1000), units::voltage::millivolt_t(850)); PMVoltCurveImporterStub i("manual", points); ts.importControl(i); REQUIRE(ts.mode() == "manual"); REQUIRE(ts.points() == points); } SECTION("Exports its state") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); std::vector modes{"auto", "manual"}; std::vector, std::pair>> pointsRange; for (int i = 0; i < 3; ++i) pointsRange.emplace_back( std::make_pair(units::frequency::megahertz_t(200), units::frequency::megahertz_t(2000)), std::make_pair(units::voltage::millivolt_t(800), units::voltage::millivolt_t(900))); std::vector> points; points.emplace_back(units::frequency::megahertz_t(200), units::voltage::millivolt_t(800)); points.emplace_back(units::frequency::megahertz_t(1000), units::voltage::millivolt_t(850)); points.emplace_back(units::frequency::megahertz_t(2000), units::voltage::millivolt_t(900)); trompeloeil::sequence seq; PMVoltCurveExporterMock e; REQUIRE_CALL(e, takePMVoltCurveModes(trompeloeil::_)) .LR_WITH(_1 == modes) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMVoltCurveMode("auto")).IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMVoltCurvePointsRange(trompeloeil::_)) .LR_WITH(_1 == pointsRange) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMVoltCurvePoints(trompeloeil::_)) .LR_WITH(_1 == points) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Does not generate clean control commands") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Does not generate sync control commands when is synced") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates sync control commands when points are out of sync") { PMVoltCurveTestAdapter ts( "vc", std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.mode("manual"); ts.point(0, units::frequency::megahertz_t(201), units::voltage::millivolt_t(801)); ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "vc 0 201 801"); } } } // namespace Tests::AMD::PMVoltCurve corectrl-v1.4.2/tests/src/test_amdpmvoltoffset.cpp000066400000000000000000000137441467225065400224530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/overdrive/voltoffset/pmvoltoffset.h" #include extern template struct trompeloeil::reporter; namespace Tests::AMD::PMVoltOffset { class PMVoltOffsetTestAdapter : public ::AMD::PMVoltOffset { public: using ::AMD::PMVoltOffset::PMVoltOffset; using ::AMD::PMVoltOffset::cleanControl; using ::AMD::PMVoltOffset::exportControl; using ::AMD::PMVoltOffset::importControl; using ::AMD::PMVoltOffset::range; using ::AMD::PMVoltOffset::syncControl; using ::AMD::PMVoltOffset::value; }; class PMVoltOffsetImporterStub final : public ::AMD::PMVoltOffset::Importer { public: PMVoltOffsetImporterStub(units::voltage::millivolt_t const offset) : offset_(offset) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } units::voltage::millivolt_t providePMVoltOffsetValue() const override { return offset_; } private: units::voltage::millivolt_t const offset_; }; class PMVoltOffsetExporterMock : public ::AMD::PMVoltOffset::Exporter { public: MAKE_MOCK2(takePMVoltOffsetRange, void(units::voltage::millivolt_t, units::voltage::millivolt_t), override); MAKE_MOCK1(takePMVoltOffsetValue, void(units::voltage::millivolt_t), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD PMVoltOffset tests", "[GPU][AMD][PM][PMAdvanced][PMOverdrive][PMVoltOffset]") { // clang-format off std::vector ppOdClkVoltageData { "OD_VDDGFX_OFFSET:", "0mV"}; // clang-format on CommandQueueStub ctlCmds; SECTION("Has PMVoltOffset ID") { PMVoltOffsetTestAdapter ts(std::make_unique()); REQUIRE(ts.ID() == ::AMD::PMVoltOffset::ItemID); } SECTION("Is active by default") { PMVoltOffsetTestAdapter ts(std::make_unique()); REQUIRE(ts.active()); } SECTION("Does not generate pre-init control commands") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.preInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Generates post-init control commands") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "vo 0"); } SECTION("Initializes offset from pp_od_clk_voltage data source") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); auto offset = ts.value(); REQUIRE(offset == units::voltage::millivolt_t(0)); } SECTION("Clamps offset value in range") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); auto range = ts.range(); // min ts.value(units::voltage::millivolt_t(-1) + range.first); REQUIRE(ts.value() == range.first); // max ts.value(units::voltage::millivolt_t(1) + range.second); REQUIRE(ts.value() == range.second); } SECTION("Imports its state") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); auto offset = units::voltage::millivolt_t(-20); PMVoltOffsetImporterStub i(offset); ts.importControl(i); REQUIRE(ts.value() == offset); } SECTION("Exports its state") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); auto range = ts.range(); trompeloeil::sequence seq; PMVoltOffsetExporterMock e; REQUIRE_CALL(e, takePMVoltOffsetRange(trompeloeil::eq(range.first), trompeloeil::eq(range.second))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takePMVoltOffsetValue(units::voltage::millivolt_t(0))) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Does not generate clean control commands") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.empty()); } SECTION("Does not generate sync control commands when is synced") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates sync control commands when is out of sync") { PMVoltOffsetTestAdapter ts(std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData)); ts.init(); ts.value(units::voltage::millivolt_t(-20)); ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "vo -20"); } } } // namespace Tests::AMD::PMVoltOffset corectrl-v1.4.2/tests/src/test_amdppdpmhandler.cpp000066400000000000000000000140521467225065400223720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/handlers/ppdpmhandler.h" namespace Tests::AMD::PpDpmHandler { TEST_CASE("AMD PpDpmHandler tests", "[GPU][AMD][PM][DataSourceHandler][PpDpmHandler]") { CommandQueueStub ctlCmds; std::vector defaultActiveStates{0, 1}; std::vector ppDpmData{"0: 300Mhz *", "1: 2000Mhz"}; SECTION("Initializes states from data source on construction") { ::AMD::PpDpmHandler ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_dpm_sclk", ppDpmData)); auto states = ts.states(); REQUIRE(states.size() == 2); REQUIRE(states.front() == std::make_pair(0u, units::frequency::megahertz_t(300))); REQUIRE(states.back() == std::make_pair(1u, units::frequency::megahertz_t(2000))); SECTION("Has all states active by default") { REQUIRE(ts.active() == defaultActiveStates); } SECTION("Activate...") { SECTION("Works with known states") { ts.activate({1}); auto &activeStates = ts.active(); REQUIRE(activeStates.size() == 1); REQUIRE(activeStates.front() == 1); } SECTION("Ignores unknown states") { ts.activate({2, 3}); REQUIRE(ts.active() == defaultActiveStates); } SECTION("Cannot deactivate all states") { ts.activate({}); REQUIRE(ts.active() == defaultActiveStates); } } } SECTION("Saving and restoring data source state are not supported") { ::AMD::PpDpmHandler ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_dpm_sclk", ppDpmData)); ts.saveState(); ts.restoreState(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates reset control commands unconditionally...") { SECTION("Including performance level command when its value is not manual") { ::AMD::PpDpmHandler ts(std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique( "pp_dpm_sclk", ppDpmData)); ts.reset(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_dpm_sclk"); REQUIRE(cmd1Value == "0 1"); } SECTION("Excluding performance level command when its value is not manual") { ::AMD::PpDpmHandler ts(std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique( "pp_dpm_sclk", ppDpmData)); ts.reset(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_dpm_sclk"); REQUIRE(cmd0Value == "0 1"); } } SECTION("Does not generate sync control commands when is synced") { ::AMD::PpDpmHandler ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_dpm_sclk", ppDpmData)); // skip initial sync commands ts.sync(ctlCmds); ctlCmds.clear(); ts.sync(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates sync control commands when...") { SECTION("Performance level is not manual") { ::AMD::PpDpmHandler ts(std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique( "pp_dpm_sclk", ppDpmData)); ts.sync(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_dpm_sclk"); REQUIRE(cmd1Value == "0 1"); } SECTION("Active states were changed") { ::AMD::PpDpmHandler ts(std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique( "pp_dpm_sclk", ppDpmData)); ts.activate({0}); ts.sync(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_dpm_sclk"); REQUIRE(cmd0Value == "0"); } SECTION("Current index is not an active index") { ::AMD::PpDpmHandler ts(std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique( "pp_dpm_sclk", ppDpmData)); ts.activate({1}); ts.sync(ctlCmds); ctlCmds.clear(); ts.sync(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_dpm_sclk"); REQUIRE(cmd0Value == "1"); } } } } // namespace Tests::AMD::PpDpmHandler corectrl-v1.4.2/tests/src/test_amdutils.cpp000066400000000000000000001151701467225065400210570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/amdutils.h" #include namespace Tests::Utils::AMD { TEST_CASE("AMD utils tests", "[Utils][AMD]") { SECTION("parseDPMStates") { // clang-format off std::vector input{"0: 300Mhz *", "1: 2000Mhz"}; // clang-format on SECTION("Returns dpm states indices and frequencies") { auto states = ::Utils::AMD::parseDPMStates(input); REQUIRE(states.has_value()); REQUIRE(states.value().size() == 2); auto &[s0Index, s0Freq] = states.value().front(); REQUIRE(s0Index == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(300)); auto &[s1Index, s1Freq] = states.value().back(); REQUIRE(s1Index == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(2000)); } SECTION("Returns no dpm states for invalid input") { // clang-format off std::vector input{""}; // clang-format on auto states = ::Utils::AMD::parseDPMStates(input); REQUIRE_FALSE(states.has_value()); } } SECTION("parseDPMCurrentStateIndex") { // clang-format off std::vector input{"0: 300Mhz", "1: 2000Mhz *"}; // clang-format on SECTION("Returns index of current dpm state") { auto index = ::Utils::AMD::parseDPMCurrentStateIndex(input); REQUIRE(index.has_value()); REQUIRE(*index == 1); } SECTION("Returns nothing for invalid input") { // clang-format off std::vector input{""}; // clang-format on auto index = ::Utils::AMD::parseDPMCurrentStateIndex(input); REQUIRE_FALSE(index.has_value()); } } SECTION("parsePowerProfileModeModes") { SECTION("Returns power profile modes on smu7 asics") { // clang-format off std::vector input{ "NUM ...", " 0 BOOTUP_DEFAULT: ...", " 1 3D_FULL_SCREEN *: ...", " 2 POWER_SAVING: ...", "...", " 6 CUSTOM: ..."}; // clang-format on auto modes = ::Utils::AMD::parsePowerProfileModeModes(input); REQUIRE(modes.has_value()); REQUIRE_FALSE(modes->empty()); auto &[mode0, mode0Index] = modes->at(0); REQUIRE(mode0 == "3D_FULL_SCREEN"); REQUIRE(mode0Index == 1); auto &[mode1, mode1Index] = modes->at(1); REQUIRE(mode1 == "POWER_SAVING"); REQUIRE(mode1Index == 2); } SECTION("Returns power profile modes on vega10 asics") { // clang-format off std::vector input{ "NUM ...", " 0 3D_FULL_SCREEN*: ...", " 1 POWER_SAVING : ...", "...", " 5 CUSTOM : ..."}; // clang-format on auto modes = ::Utils::AMD::parsePowerProfileModeModes(input); REQUIRE(modes.has_value()); REQUIRE_FALSE(modes->empty()); auto &[mode0, mode0Index] = modes->at(0); REQUIRE(mode0 == "3D_FULL_SCREEN"); REQUIRE(mode0Index == 0); auto &[mode1, mode1Index] = modes->at(1); REQUIRE(mode1 == "POWER_SAVING"); REQUIRE(mode1Index == 1); } SECTION("Returns power profile modes on vega20 asics") { // clang-format off std::vector input{ "PROFILE_INDEX(NAME) ...", " 0 3D_FULL_SCREEN*: ...", " 1 POWER_SAVING : ...", "...", " 5 CUSTOM : ..."}; // clang-format on auto modes = ::Utils::AMD::parsePowerProfileModeModes(input); REQUIRE(modes.has_value()); REQUIRE_FALSE(modes->empty()); auto &[mode0, mode0Index] = modes->at(0); REQUIRE(mode0 == "3D_FULL_SCREEN"); REQUIRE(mode0Index == 0); auto &[mode1, mode1Index] = modes->at(1); REQUIRE(mode1 == "POWER_SAVING"); REQUIRE(mode1Index == 1); } SECTION("Returns power profile modes on sienna cichlid asics") { // clang-format off std::vector input{ "PROFILE_INDEX(NAME) ...", "...", " 1 3D_FULL_SCREEN*: ...", " 0( GFXCLK) ...", "...", " 2 POWER_SAVING : ...", " 0( GFXCLK) ...", "..."}; // clang-format on auto modes = ::Utils::AMD::parsePowerProfileModeModes(input); REQUIRE(modes.has_value()); REQUIRE_FALSE(modes->empty()); auto &[mode0, mode0Index] = modes->at(0); REQUIRE(mode0 == "3D_FULL_SCREEN"); REQUIRE(mode0Index == 1); auto &[mode1, mode1Index] = modes->at(1); REQUIRE(mode1 == "POWER_SAVING"); REQUIRE(mode1Index == 2); } SECTION("Returns power profile modes on asics without heuristics settings") { // clang-format off std::vector input{ " 0 3D_FULL_SCREEN ", " 3 VIDEO*", "...", " 6 CUSTOM "}; // clang-format on auto modes = ::Utils::AMD::parsePowerProfileModeModes(input); REQUIRE(modes.has_value()); REQUIRE_FALSE(modes->empty()); auto &[mode0, mode0Index] = modes->at(0); REQUIRE(mode0 == "3D_FULL_SCREEN"); REQUIRE(mode0Index == 0); auto &[mode1, mode1Index] = modes->at(1); REQUIRE(mode1 == "VIDEO"); REQUIRE(mode1Index == 3); } } SECTION("parsePowerProfileModeCurrentModeIndex") { SECTION("Returns index of current profile mode on smu7 asics") { // clang-format off std::vector input{ "NUM ...", " 0 BOOTUP_DEFAULT: ...", " 1 3D_FULL_SCREEN *: ...", " 2 POWER_SAVING: ...", "...", " 6 CUSTOM: ..."}; // clang-format on auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndex(input); REQUIRE(index.has_value()); REQUIRE(*index == 1); } SECTION("Returns index of current profile mode on vega10 asics") { // clang-format off std::vector input{ "NUM ...", " 0 3D_FULL_SCREEN : ...", " 1 POWER_SAVING*: ...", "...", " 5 CUSTOM : ..."}; // clang-format on auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndex(input); REQUIRE(index.has_value()); REQUIRE(*index == 1); } SECTION("Returns index of current profile mode on vega20 asics") { // clang-format off std::vector input{ "PROFILE_INDEX(NAME) ...", " 0 3D_FULL_SCREEN : ...", " 1 POWER_SAVING*: ...", "...", " 5 CUSTOM : ..."}; // clang-format on auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndex(input); REQUIRE(index.has_value()); REQUIRE(*index == 1); } SECTION("Returns index of current profile mode on sienna cichlid asics") { // clang-format off std::vector input{ "PROFILE_INDEX(NAME) ...", "...", " 1 3D_FULL_SCREEN*: ...", " 0( GFXCLK) ...", "...", " 2 POWER_SAVING : ...", " 0( GFXCLK) ...", "..."}; // clang-format on auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndex(input); REQUIRE(index.has_value()); REQUIRE(*index == 1); } SECTION("Returns index of current profile mode on asics without heuristics " "settings") { // clang-format off std::vector input{ " 0 3D_FULL_SCREEN ", " 3 VIDEO*", "...", " 6 CUSTOM "}; // clang-format on auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndex(input); REQUIRE(index.has_value()); REQUIRE(*index == 3); } SECTION("Returns nothing for invalid input") { auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndex({""}); REQUIRE_FALSE(index.has_value()); } } SECTION("parsePowerProfileModeModesColumnar") { SECTION("Returns power profile modes on asics with columnar data") { // clang-format off std::vector input{" 0 3D_FULL_SCREEN* 1 VIDEO 2 CUSTOM"}; // clang-format on auto modes = ::Utils::AMD::parsePowerProfileModeModesColumnar(input); REQUIRE(modes.has_value()); REQUIRE(modes->size() == 2); auto &[mode0, mode0Index] = modes->at(0); REQUIRE(mode0 == "3D_FULL_SCREEN"); REQUIRE(mode0Index == 0); auto &[mode1, mode1Index] = modes->at(1); REQUIRE(mode1 == "VIDEO"); REQUIRE(mode1Index == 1); } SECTION("Returns nothing for invalid input") { auto index = ::Utils::AMD::parsePowerProfileModeModesColumnar({""}); REQUIRE_FALSE(index.has_value()); } } SECTION("parsePowerProfileModeCurrentModeIndex") { SECTION( "Returns index of the active profile mode on asics with columnar data") { // clang-format off std::vector input{" 0 3D_FULL_SCREEN 1 VIDEO* 2 CUSTOM"}; // clang-format on auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndexColumnar(input); REQUIRE(index.has_value()); REQUIRE(*index == 1); } SECTION("Returns nothing for invalid input") { auto index = ::Utils::AMD::parsePowerProfileModeCurrentModeIndexColumnar({""}); REQUIRE_FALSE(index.has_value()); } } SECTION("parseOverdriveClksVolts") { // clang-format off std::vector input{"OD_MCLK:", "0: 300MHz 800mV", "1: 2000MHz 975mV", "OD_RANGE:"}; // clang-format on SECTION("Returns the available states for the control") { auto values = ::Utils::AMD::parseOverdriveClksVolts("MCLK", input); REQUIRE(values.has_value()); REQUIRE(values->size() == 2); auto &[s0Idx, s0Freq, s0Volt] = values->at(0); REQUIRE(s0Idx == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(300)); REQUIRE(s0Volt == units::voltage::millivolt_t(800)); auto &[s1Idx, s1Freq, s1Volt] = values->at(1); REQUIRE(s1Idx == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(2000)); REQUIRE(s1Volt == units::voltage::millivolt_t(975)); } SECTION("Returns nothing when there is no OD_controlName in input") { // clang-format off std::vector input{"OTHER:", "0: 300MHz 800mV", "1: 2000MHz 975mV", "OD_RANGE:"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveClksVolts("MCLK", input); REQUIRE_FALSE(empty.has_value()); } } SECTION("parseOverdriveClkRange") { // clang-format off std::vector input{"OD_RANGE:", "SCLK: 300MHz 2000MHz", "MCLK: 300MHz 2250MHz"}; // clang-format on SECTION("Returns minimum and maximum gpu frequency") { auto values = ::Utils::AMD::parseOverdriveClkRange("SCLK", input); REQUIRE(values.has_value()); REQUIRE(values->first == units::frequency::megahertz_t(300)); REQUIRE(values->second == units::frequency::megahertz_t(2000)); } SECTION("Returns minimum and maximum memory frequency") { auto values = ::Utils::AMD::parseOverdriveClkRange("MCLK", input); REQUIRE(values.has_value()); REQUIRE(values->first == units::frequency::megahertz_t(300)); REQUIRE(values->second == units::frequency::megahertz_t(2250)); } SECTION("Returns nothing when there is no OD_RANGE in input") { // clang-format off std::vector input{"OTHER:", "SCLK: 300MHz 2000MHz", "MCLK: 300MHz 2250MHz"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveClkRange("SLCK", input); REQUIRE_FALSE(empty.has_value()); } SECTION("Returns nothing for unknown controls names") { auto empty = ::Utils::AMD::parseOverdriveClkRange("OTHER", input); REQUIRE_FALSE(empty.has_value()); } } SECTION("parseOverdriveVoltRange") { // clang-format off std::vector input{"OD_RANGE:", "VDDC: 800mV 1175mV"}; // clang-format on SECTION("Returns minimum and maximum state voltage") { auto values = ::Utils::AMD::parseOverdriveVoltRange(input); REQUIRE(values.has_value()); REQUIRE(values->first == units::voltage::millivolt_t(800)); REQUIRE(values->second == units::voltage::millivolt_t(1175)); } SECTION("Returns nothing when there is no OD_RANGE in input") { // clang-format off std::vector input{"OTHER:", "VDDC: 800mV 1175mV"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveVoltRange(input); REQUIRE_FALSE(empty.has_value()); } } SECTION("parseOverdriveClks") { // clang-format off std::vector input{"OD_SCLK:", "0: 300MHz", "1: 2000MHz", "OD_MCLK:"}; // clang-format on SECTION("Returns available states for the control") { auto values = ::Utils::AMD::parseOverdriveClks("SCLK", input); REQUIRE(values.has_value()); REQUIRE(values->size() == 2); auto &[s0Idx, s0Freq] = values->at(0); REQUIRE(s0Idx == 0); REQUIRE(s0Freq == units::frequency::megahertz_t(300)); auto &[s1Idx, s1Freq] = values->at(1); REQUIRE(s1Idx == 1); REQUIRE(s1Freq == units::frequency::megahertz_t(2000)); } SECTION("Returns nothing when there is no OD_controlName in input") { // clang-format off std::vector input{"OTHER:", "0: 300MHz", "1: 2000MHz", "OD_MCLK:"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveClks("SCLK", input); REQUIRE_FALSE(empty.has_value()); } } SECTION("parseOverdriveVoltCurve") { // clang-format off std::vector input{"OD_VDDC_CURVE:", "0: 700Mhz 800mV", "2: 800Mhz @ 900mV", // navi "OD_RANGE:"}; // clang-format on SECTION("Returns the available voltage curve points") { auto values = ::Utils::AMD::parseOverdriveVoltCurve(input); REQUIRE(values.has_value()); REQUIRE(values->size() == 2); auto &[p0Freq, p0Volt] = values->at(0); REQUIRE(p0Freq == units::frequency::megahertz_t(700)); REQUIRE(p0Volt == units::voltage::millivolt_t(800)); auto &[p1Freq, p1Volt] = values->at(1); REQUIRE(p1Freq == units::frequency::megahertz_t(800)); REQUIRE(p1Volt == units::voltage::millivolt_t(900)); } SECTION("Returns nothing...") { SECTION("When there is no OD_VDDC_CURVE: in input") { // clang-format off std::vector input{"OTHER:", "0: 700Mhz 800mV", "2: 800Mhz 900mV", "OD_RANGE:"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveVoltCurve(input); REQUIRE_FALSE(empty.has_value()); } SECTION("When the voltage curve points have missing coordinates") { // clang-format off std::vector input{"OD_VDDC_CURVE:", "0: 800mV", "1: 800Mhz", "OD_RANGE:"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveVoltCurve(input); REQUIRE_FALSE(empty.has_value()); } } } SECTION("parseOverdriveVoltCurveRange") { // clang-format off std::vector input{"OD_RANGE:", "...", "VDDC_CURVE_SCLK[0]: 800Mhz 2000Mhz", "VDDC_CURVE_VOLT[0]: 700mV 1200mV", "VDDC_CURVE_SCLK[1]: 810Mhz 2100Mhz", "VDDC_CURVE_VOLT[1]: 800mV 1300mV"}; // clang-format on SECTION("Returns curve points") { auto values = ::Utils::AMD::parseOverdriveVoltCurveRange(input); REQUIRE(values.has_value()); REQUIRE(values->size() == 2); auto &[p0freq, p0volt] = values->at(0); auto &[p0fmin, p0fmax] = p0freq; REQUIRE(p0fmin == units::frequency::megahertz_t(800)); REQUIRE(p0fmax == units::frequency::megahertz_t(2000)); auto &[p0vmin, p0vmax] = p0volt; REQUIRE(p0vmin == units::voltage::millivolt_t(700)); REQUIRE(p0vmax == units::voltage::millivolt_t(1200)); auto &[p1freq, p1volt] = values->at(1); auto &[p1fmin, p1fmax] = p1freq; REQUIRE(p1fmin == units::frequency::megahertz_t(810)); REQUIRE(p1fmax == units::frequency::megahertz_t(2100)); auto &[p1vmin, p1vmax] = p1volt; REQUIRE(p1vmin == units::voltage::millivolt_t(800)); REQUIRE(p1vmax == units::voltage::millivolt_t(1300)); } SECTION("Returns nothing...") { SECTION("When input has no OD_RANGE") { std::vector input{"OTHER:"}; auto empty = ::Utils::AMD::parseOverdriveVoltRange(input); REQUIRE_FALSE(empty.has_value()); } SECTION("When input has no point's range") { std::vector input{"OD_RANGE:"}; auto empty = ::Utils::AMD::parseOverdriveVoltRange(input); REQUIRE_FALSE(empty.has_value()); } } SECTION("When input has missing data at least one point") { // clang-format off std::vector missingFreqInput{"OD_RANGE:", "...", "VDDC_CURVE_VOLT[0]: 700mV 1200mV"}; std::vector missingVoltInput{"OD_RANGE:", "...", "VDDC_CURVE_SCLK[0]: 800Mhz 2000Mhz"}; // clang-format on auto empty0 = ::Utils::AMD::parseOverdriveVoltRange(missingFreqInput); REQUIRE_FALSE(empty0.has_value()); auto empty1 = ::Utils::AMD::parseOverdriveVoltRange(missingVoltInput); REQUIRE_FALSE(empty1.has_value()); } } SECTION("parseOverdriveClkControls") { SECTION("Returns available CLK controls") { // clang-format off std::vector input{"OD_SCLK:", "...", "OD_MCLK:", "...",}; // clang-format on auto values = ::Utils::AMD::parseOverdriveClkControls(input); REQUIRE(values.has_value()); REQUIRE(values->size() == 2); REQUIRE(values->at(0) == "SCLK"); REQUIRE(values->at(1) == "MCLK"); } SECTION("Returns nothing when there is no available CLK controls") { std::vector input{"OTHER_DATA"}; auto empty = ::Utils::AMD::parseOverdriveClkControls(input); REQUIRE_FALSE(empty.has_value()); } } SECTION("parseOverdriveVoltOffset") { SECTION("Returns voltage offset") { // clang-format off std::vector input{"OD_VDDGFX_OFFSET:", "-10mV", "...",}; // clang-format on auto offset = ::Utils::AMD::parseOverdriveVoltOffset(input); REQUIRE(offset.has_value()); REQUIRE(*offset == units::voltage::millivolt_t(-10)); } SECTION("Returns nothing when there is no available voltage offset") { std::vector input{"OTHER_DATA"}; auto empty = ::Utils::AMD::parseOverdriveVoltOffset(input); REQUIRE_FALSE(empty.has_value()); } } SECTION("getOverdriveClkControlCmdId") { SECTION("Returns 's' command id for SCLK control") { auto cmdId = ::Utils::AMD::getOverdriveClkControlCmdId("SCLK"); REQUIRE(cmdId == "s"); } SECTION("Returns 'm' command id for MCLK control") { auto cmdId = ::Utils::AMD::getOverdriveClkControlCmdId("MCLK"); REQUIRE(cmdId == "m"); } } SECTION("ppOdClkVoltageHasKnownFreqVoltQuirks") { SECTION("Pre-Vega20 missing range section") { // clang-format off std::vector input{"OD_SCLK:", "0: 300MHz 800mV", "1: 608MHz 818mV"}; // clang-format on REQUIRE(::Utils::AMD::ppOdClkVoltageHasKnownFreqVoltQuirks("SCLK", input)); } SECTION("Good input has no quirks") { // clang-format off std::vector input{"OD_SCLK:", "0: 300MHz 800mV", "1: 608MHz 818mV", "OD_MCLK:", "0: 300MHz 800mV", "1: 2000MHz 975mV", "OD_RANGE:", "SCLK: 800MHz 2150MHz", "MCLK: 625MHz 950MHz", "VDDC: 800mV 1175mV"}; // clang-format on REQUIRE_FALSE( ::Utils::AMD::ppOdClkVoltageHasKnownFreqVoltQuirks("SCLK", input)); REQUIRE_FALSE( ::Utils::AMD::ppOdClkVoltageHasKnownFreqVoltQuirks("MCLK", input)); } } SECTION("ppOdClkVoltageHasKnownVoltCurveQuirks") { SECTION("Navi zero voltage curve points") { // clang-format off std::vector input{"OD_SCLK:", "0: 800Mhz", "1: 2100Mhz", "OD_MCLK:", "1: 875MHz", "OD_VDDC_CURVE:", "0: 700Mhz @ 0mV", "1: 800Mhz @ 0mV", "OD_RANGE:", "SCLK: 800Mhz 2150Mhz", "MCLK: 625Mhz 950Mhz", "VDDC_CURVE_SCLK[0]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[0]: 750mV 1200mV", "VDDC_CURVE_SCLK[1]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[1]: 750mV 1200mV", "VDDC_CURVE_SCLK[2]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[2]: 750mV 1200mV"}; // clang-format on REQUIRE(::Utils::AMD::ppOdClkVoltageHasKnownVoltCurveQuirks(input)); } SECTION("Good input has no quirks") { // Vega20 // clang-format off std::vector vega20Input{"OD_SCLK:", "0: 800Mhz", "1: 2100Mhz", "OD_MCLK:", "1: 875MHz", "OD_VDDC_CURVE:", "0: 700Mhz 800mV", "1: 800Mhz 900mV", "OD_RANGE:", "SCLK: 800Mhz 2150Mhz", "MCLK: 625Mhz 950Mhz", "VDDC_CURVE_SCLK[0]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[0]: 750mV 1200mV", "VDDC_CURVE_SCLK[1]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[1]: 750mV 1200mV", "VDDC_CURVE_SCLK[2]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[2]: 750mV 1200mV"}; // clang-format on REQUIRE_FALSE( ::Utils::AMD::ppOdClkVoltageHasKnownVoltCurveQuirks(vega20Input)); // Navi // clang-format off std::vector naviInput{"OD_SCLK:", "0: 800Mhz", "1: 2100Mhz", "OD_MCLK:", "1: 875MHz", "OD_VDDC_CURVE:", "0: 700Mhz @ 800mV", "1: 800Mhz @ 900mV", "OD_RANGE:", "SCLK: 800Mhz 2150Mhz", "MCLK: 625Mhz 950Mhz", "VDDC_CURVE_SCLK[0]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[0]: 750mV 1200mV", "VDDC_CURVE_SCLK[1]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[1]: 750mV 1200mV", "VDDC_CURVE_SCLK[2]: 800Mhz 2150Mhz", "VDDC_CURVE_VOLT[2]: 750mV 1200mV"}; // clang-format on REQUIRE_FALSE( ::Utils::AMD::ppOdClkVoltageHasKnownVoltCurveQuirks(naviInput)); } } SECTION("ppOdClkVoltageFreqRangeOutOfRangeState") { SECTION("Returns the out of range state indices") { // RX 6X00XT out of range minimum memory clock // clang-format off std::vector input{"OD_SCLK:", "0: 700Mhz", "1: 2629Mhz", "OD_MCLK:", "0: 97Mhz", "1: 1000MHz", "OD_VDDGFX_OFFSET:", "0mV", "OD_RANGE:", "SCLK: 500Mhz 3150Mhz", "MCLK: 674Mhz 1200Mhz"}; // clang-format on auto states = ::Utils::AMD::ppOdClkVoltageFreqRangeOutOfRangeStates( "MCLK", input); REQUIRE(states.has_value()); REQUIRE(states->size() == 1); REQUIRE(states->at(0) == 0); } SECTION("Returns nothing when there is no out of range states") { // clang-format off std::vector input{"OD_SCLK:", "0: 700Mhz", "1: 2629Mhz", "OD_MCLK:", "0: 674Mhz", "1: 1000MHz", "OD_VDDGFX_OFFSET:", "0mV", "OD_RANGE:", "SCLK: 500Mhz 3150Mhz", "MCLK: 674Mhz 1200Mhz"}; // clang-format on REQUIRE_FALSE( ::Utils::AMD::ppOdClkVoltageFreqRangeOutOfRangeStates("SCLK", input) .has_value()); REQUIRE_FALSE( ::Utils::AMD::ppOdClkVoltageFreqRangeOutOfRangeStates("MCLK", input) .has_value()); } } SECTION("parseOverdriveFanCurve") { // clang-format off std::vector input{"OD_FAN_CURVE:", "0: 0C 0%", "1: 45C 15%", // "2: 50C 30%", // "3: 55C 70%", // "4: 65C 100%", "OD_RANGE:"}; // clang-format on SECTION("Returns the available fan curve points") { auto values = ::Utils::AMD::parseOverdriveFanCurve(input); REQUIRE(values.has_value()); REQUIRE(values->size() == 2); auto [p0Index, p0Temp, p0Speed] = values->at(0); REQUIRE(p0Index == 0); REQUIRE(p0Temp == units::temperature::celsius_t(0)); REQUIRE(p0Speed == units::concentration::percent_t(0)); auto [p1Index, p1Temp, p1Speed] = values->at(1); REQUIRE(p1Index == 1); REQUIRE(p1Temp == units::temperature::celsius_t(45)); REQUIRE(p1Speed == units::concentration::percent_t(15)); } SECTION("Returns nothing...") { SECTION("When there is no OD_FAN_CURVE: in input") { // clang-format off std::vector input{"OTHER:", "0: 0C 0%", "1: 45C 15%", // "2: 50C 30%", // "3: 55C 70%", // "4: 65C 100%", "OD_RANGE:"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveFanCurve(input); REQUIRE_FALSE(empty.has_value()); } SECTION("When the fan curve points format is not valid") { // clang-format off std::vector input{"OD_FAN_CURVE:", "0: 0C 0%", "45C 15%", "2: 50C", "3: 70%", "4:", "OD_RANGE:"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveFanCurve(input); REQUIRE_FALSE(empty.has_value()); } } } SECTION("parseOverdriveFanCurveTempRange") { // clang-format off std::vector input{"OD_RANGE:", "FAN_CURVE(hotspot temp): 25C 100C"}; // clang-format on SECTION("Returns minimum and maximum temperature") { auto values = ::Utils::AMD::parseOverdriveFanCurveTempRange(input); REQUIRE(values.has_value()); REQUIRE(values->first == units::temperature::celsius_t(25)); REQUIRE(values->second == units::temperature::celsius_t(100)); } SECTION("Returns nothing when there is no OD_RANGE in input") { // clang-format off std::vector input{"OTHER:", "FAN_CURVE(hotspot temp): 25C 100C"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveFanCurveTempRange(input); REQUIRE_FALSE(empty.has_value()); } } SECTION("parseOverdriveFanCurveSpeedRange") { // clang-format off std::vector input{"OD_RANGE:", "FAN_CURVE(fan speed): 0% 100%"}; // clang-format on SECTION("Returns minimum and maximum speed") { auto values = ::Utils::AMD::parseOverdriveFanCurveSpeedRange(input); REQUIRE(values.has_value()); REQUIRE(values->first == units::concentration::percent_t(0)); REQUIRE(values->second == units::concentration::percent_t(100)); } SECTION("Returns nothing when there is no OD_RANGE in input") { // clang-format off std::vector input{"OTHER:", "FAN_CURVE(fan speed): 0% 100%"}; // clang-format on auto empty = ::Utils::AMD::parseOverdriveFanCurveTempRange(input); REQUIRE_FALSE(empty.has_value()); } } SECTION("isPowerProfileModeDataColumnar") { SECTION("Returns true when power profile mode data has columnar format") { // clang-format off std::vector data{" 0 BOOTUP_DEFAULT* 1 3D_FULL_SCREEN 2 POWER_SAVING 3 VIDEO"}; // clang-format on REQUIRE(::Utils::AMD::isPowerProfileModeDataColumnar(data)); } SECTION("Returns false when power profile mode data does not have columnar " "format") { // clang-format off std::vector data{"NUM MODE_NAME SCLK_UP_HYST SCLK_DOWN_HYST SCLK_ACTIVE_LEVEL"}; // clang-format on REQUIRE_FALSE(::Utils::AMD::isPowerProfileModeDataColumnar(data)); } SECTION("Returns false when power profile mode data is empty") { REQUIRE_FALSE(::Utils::AMD::isPowerProfileModeDataColumnar({})); } } SECTION("hasOverdriveClkVoltControl") { SECTION("Returns true when overdrive has clock + voltage state controls") { // clang-format off std::vector data{"OD_SCLK:", "0: 300MHz 800mV"}; // clang-format on REQUIRE(::Utils::AMD::hasOverdriveClkVoltControl(data)); } SECTION( "Returns false when overdrive has no clock + voltage state controls") { // clang-format off std::vector otherClkControlData{"OD_SCLK:", "0: 300MHz"}; std::vector noClkControlData{"OTHER_DATA"}; // clang-format on REQUIRE_FALSE( ::Utils::AMD::hasOverdriveClkVoltControl(otherClkControlData)); REQUIRE_FALSE(::Utils::AMD::hasOverdriveClkVoltControl(noClkControlData)); } } SECTION("hasOverdriveClkControl") { SECTION("Returns true when overdrive has clock state controls") { // clang-format off std::vector data{"OD_SCLK:", "0: 300MHz"}; // clang-format on REQUIRE(::Utils::AMD::hasOverdriveClkControl(data)); } SECTION("Returns false when overdrive has no clock state controls") { // clang-format off std::vector otherClkControlData{"OD_SCLK:", "0: 300MHz 800mV"}; std::vector noClkControlData{"OTHER_DATA"}; // clang-format on REQUIRE_FALSE(::Utils::AMD::hasOverdriveClkControl(otherClkControlData)); REQUIRE_FALSE(::Utils::AMD::hasOverdriveClkControl(noClkControlData)); } } SECTION("hasOverdriveVoltCurveControl") { SECTION("Returns true when overdrive has voltage curve control") { // clang-format off std::vector data{"OD_VDDC_CURVE:", "0: 700Mhz 800mV",}; // clang-format on REQUIRE(::Utils::AMD::hasOverdriveVoltCurveControl(data)); } SECTION("Returns false...") { SECTION("When overdrive has no voltage curve control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveVoltCurveControl(data)); } SECTION("When overdrive has no valid voltage curve points") { // clang-format off std::vector data{"OD_VDDC_CURVE:", "0: 800mV", "OD_RANGE:"}; // clang-format on REQUIRE_FALSE(::Utils::AMD::hasOverdriveVoltCurveControl(data)); } } } SECTION("hasOverdriveVoltOffsetControl") { SECTION("Returns true when overdrive has voltage offset control") { std::vector data{"OD_VDDGFX_OFFSET:"}; REQUIRE(::Utils::AMD::hasOverdriveVoltOffsetControl(data)); } SECTION("Returns false when overdrive has no voltage curve control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveVoltOffsetControl(data)); } } SECTION("hasOverdriveFanTargetTempControl") { SECTION("Returns true when overdrive has fan target temperature control") { std::vector data{"FAN_TARGET_TEMPERATURE:"}; REQUIRE(::Utils::AMD::hasOverdriveFanTargetTempControl(data)); } SECTION( "Returns false when overdrive has no fan target temperature control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveFanTargetTempControl(data)); } } SECTION("hasOverdriveFanMinimumPWMControl") { SECTION("Returns true when overdrive has fan minimum pwm control") { std::vector data{"FAN_MINIMUM_PWM:"}; REQUIRE(::Utils::AMD::hasOverdriveFanMinimumPWMControl(data)); } SECTION("Returns false when overdrive has no fan minimum pwm control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveFanMinimumPWMControl(data)); } } SECTION("hasOverdriveFanAcousticTargetControl") { SECTION("Returns true when overdrive has fan acoustic target rpm threshold " "control") { std::vector data{"OD_ACOUSTIC_TARGET:"}; REQUIRE(::Utils::AMD::hasOverdriveFanAcousticTargetControl(data)); } SECTION( "Returns false when overdrive has no fan acoustic target rpm threshold " "control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveFanAcousticTargetControl(data)); } } SECTION("hasOverdriveFanAcousticLimitControl") { SECTION("Returns true when overdrive has fan acoustic limit rpm threshold " "control") { std::vector data{"OD_ACOUSTIC_LIMIT:"}; REQUIRE(::Utils::AMD::hasOverdriveFanAcousticLimitControl(data)); } SECTION( "Returns false when overdrive has no fan acoustic limit rpm threshold " "control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveFanAcousticLimitControl(data)); } } SECTION("hasOverdriveFanCurveControl") { SECTION("Returns true when overdrive has fan curve control") { std::vector data{"OD_FAN_CURVE:"}; REQUIRE(::Utils::AMD::hasOverdriveFanCurveControl(data)); } SECTION("Returns false when overdrive has no fan curve control") { std::vector data{"OTHER_DATA"}; REQUIRE_FALSE(::Utils::AMD::hasOverdriveFanCurveControl(data)); } } } } // namespace Tests::Utils::AMD corectrl-v1.4.2/tests/src/test_commandqueue.cpp000066400000000000000000000077301467225065400217220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/commandqueue.h" #include namespace Tests::CommandQueue { class CommandQueueTestAdapter : public ::CommandQueue { public: using ::CommandQueue::CommandQueue; using ::CommandQueue::add; using ::CommandQueue::commands; using ::CommandQueue::pack; using ::CommandQueue::packIndex; using ::CommandQueue::packWritesTo; using ::CommandQueue::toRawData; }; TEST_CASE("CommandQueue tests", "[CommandQueue]") { CommandQueueTestAdapter ts; SECTION("Initially, is empty") { REQUIRE(ts.commands().size() == 0); SECTION("Commands can be added") { ts.add({"path", "value"}); REQUIRE(ts.commands().size() == 1); std::pair cmd{"path", "value"}; REQUIRE(ts.commands().front() == cmd); SECTION("Adding a command already queued has no effect") { ts.add({"path", "value"}); REQUIRE(ts.commands().size() == 1); } SECTION("Command packing mode...") { SECTION("Only has effect the first time it's activated") { REQUIRE_FALSE(ts.packIndex().has_value()); ts.pack(true); REQUIRE(ts.packIndex().has_value()); REQUIRE(*ts.packIndex() == 1); ts.add({"path1", "value1"}); ts.pack(true); REQUIRE(ts.packIndex().has_value()); REQUIRE(*ts.packIndex() == 1); } SECTION("Packs commands by file path") { ts.pack(true); ts.add({"other_path", "other_value"}); ts.add({"path", "value1"}); ts.add({"other_path", "other_value1"}); auto commands = ts.commands(); REQUIRE(commands.size() == 4); auto [path0, value0] = commands.at(0); REQUIRE(path0 == "path"); REQUIRE(value0 == "value"); auto [path1, value1] = commands.at(1); REQUIRE(path1 == "other_path"); REQUIRE(value1 == "other_value"); auto [path2, value2] = commands.at(2); REQUIRE(path2 == "other_path"); REQUIRE(value2 == "other_value1"); auto [path3, value3] = commands.at(3); REQUIRE(path3 == "path"); REQUIRE(value3 == "value1"); SECTION("Restores command queue behavior when it's deactivated") { ts.pack(false); ts.add({"other_path", "other_value2"}); std::pair last{"other_path", "other_value2"}; REQUIRE(ts.commands().back() == last); } } } SECTION("Check if queued commands writes to a file...") { SECTION("Returns nullopt when pack mode is not active") { REQUIRE(ts.packWritesTo("path") == std::nullopt); } SECTION("Returns false when there is no queued command in the pack") { ts.pack(true); ts.add({"other_path", "other_value"}); auto res = ts.packWritesTo("path"); REQUIRE(res.has_value()); REQUIRE_FALSE(*res); } SECTION("Returns true when there is a queued command in the pack") { ts.pack(true); ts.add({"other_path", "other_value"}); auto res = ts.packWritesTo("other_path"); REQUIRE(res.has_value()); REQUIRE(*res); } } SECTION("Commands are transformed into raw data...") { auto data = ts.toRawData(); REQUIRE(data == QByteArray("path\0value\0", 11)); SECTION("The queue is cleared") { REQUIRE(ts.commands().size() == 0); } SECTION("Pack commands mode is deactivated") { ts.pack(true); auto _ = ts.toRawData(); REQUIRE_FALSE(ts.packIndex().has_value()); } } } } } } // namespace Tests::CommandQueue corectrl-v1.4.2/tests/src/test_commonutils.cpp000066400000000000000000000065061467225065400216100ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/commonutils.h" #include namespace Tests::Utils::Common { TEST_CASE("CommonUtils tests", "[Utils][Common]") { SECTION("normalizePoints...") { SECTION("clamp points into range") { std::vector> points{std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(100)), std::make_pair(units::temperature::celsius_t(50), units::concentration::percent_t(150)), std::make_pair(units::temperature::celsius_t(90), units::concentration::percent_t(200))}; auto tempRange = std::make_pair(units::temperature::celsius_t(0), units::temperature::celsius_t(50)); ::Utils::Common::normalizePoints(points, tempRange); // temperature range REQUIRE_FALSE( std::any_of(points.cbegin(), points.cend(), [&](auto const &point) { return point.first < tempRange.first || point.first > tempRange.second; })); // percentage range REQUIRE_FALSE( std::any_of(points.cbegin(), points.cend(), [&](auto const &point) { return point.second < units::concentration::percent_t(0) || point.second > units::concentration::percent_t(100); })); } SECTION("clamp inner points y-axis coordinates into [prev.y, next.y] range") { std::vector> points{std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(20)), std::make_pair(units::temperature::celsius_t(30), units::concentration::percent_t(10)), std::make_pair(units::temperature::celsius_t(60), units::concentration::percent_t(30)), std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(25))}; std::vector> normalizedPoints{std::make_pair(units::temperature::celsius_t(0), units::concentration::percent_t(20)), std::make_pair(units::temperature::celsius_t(30), units::concentration::percent_t(20)), std::make_pair(units::temperature::celsius_t(60), units::concentration::percent_t(30)), std::make_pair(units::temperature::celsius_t(100), units::concentration::percent_t(30))}; auto tempRange = std::make_pair(units::temperature::celsius_t(0), units::temperature::celsius_t(100)); ::Utils::Common::normalizePoints(points, tempRange); REQUIRE_THAT(points, Catch::Matchers::Equals(normalizedPoints)); } } } } // namespace Tests::Utils::Common corectrl-v1.4.2/tests/src/test_control.cpp000066400000000000000000000065471467225065400207240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "core/components/controls/control.h" extern template struct trompeloeil::reporter; namespace Tests::Control { class ControlMock : public ::Control { public: ControlMock(bool active = true, bool forceClean = false) : ::Control(active, forceClean) { } MAKE_MOCK1(preInit, void(ICommandQueue &), override); MAKE_MOCK1(postInit, void(ICommandQueue &), override); MAKE_MOCK0(init, void(), override); MAKE_MOCK1(importControl, void(IControl::Importer &), override); MAKE_CONST_MOCK1(exportControl, void(IControl::Exporter &), override); MAKE_MOCK1(cleanControl, void(ICommandQueue &), override); MAKE_MOCK1(syncControl, void(ICommandQueue &), override); MAKE_CONST_MOCK0(ID, std::string const &(), override); }; class ControlImporterStub : public IControl::Importer { public: std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } }; class ControlExporterMock : public IControl::Exporter { public: MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("Control tests", "[GPU][Control]") { ControlMock ts; std::string const tsID("_id_"); ALLOW_CALL(ts, ID()).LR_RETURN(tsID); SECTION("Is active by default") { REQUIRE(ts.active()); SECTION("Can be deactivated") { ts.activate(false); REQUIRE_FALSE(ts.active()); SECTION("Can be activated") { ts.activate(true); REQUIRE(ts.active()); } } } SECTION("Imports active state and control") { REQUIRE_CALL(ts, importControl(trompeloeil::_)); ControlImporterStub i; ts.importWith(i); REQUIRE_FALSE(ts.active()); } SECTION("Exports active state and control") { REQUIRE_CALL(ts, exportControl(trompeloeil::_)); ControlExporterMock e; ALLOW_CALL(e, provideExporter(trompeloeil::_)).LR_RETURN(e); REQUIRE_CALL(e, takeActive(ts.active())); ts.exportWith(e); } SECTION("Cleans control when gone from active to inactive") { CommandQueueStub ctlCmds; REQUIRE_CALL(ts, cleanControl(trompeloeil::_)); ts.activate(true); ts.activate(false); ts.clean(ctlCmds); FORBID_CALL(ts, cleanControl(trompeloeil::_)); ts.activate(true); ts.clean(ctlCmds); } SECTION("Cleans control when force clean is true") { ControlMock tsForceClean(false, true); CommandQueueStub ctlCmds; REQUIRE_CALL(tsForceClean, cleanControl(trompeloeil::_)); tsForceClean.clean(ctlCmds); } SECTION("Cleans control when clean once is requested") { CommandQueueStub ctlCmds; REQUIRE_CALL(ts, cleanControl(trompeloeil::_)); ts.cleanOnce(); ts.clean(ctlCmds); } SECTION("Sync control when is active") { CommandQueueStub ctlCmds; REQUIRE_CALL(ts, syncControl(trompeloeil::_)); ts.activate(true); ts.sync(ctlCmds); FORBID_CALL(ts, syncControl(trompeloeil::_)); ts.activate(false); ts.sync(ctlCmds); } } } // namespace Tests::Control corectrl-v1.4.2/tests/src/test_controlgroup.cpp000066400000000000000000000164021467225065400217700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/controlmock.h" #include "core/components/controls/controlgroup.h" extern template struct trompeloeil::reporter; namespace Tests::ControlGroup { class ControlGroupTestAdapter : public ::ControlGroup { public: using ControlGroup::ControlGroup; using ControlGroup::cleanControl; using ControlGroup::exportControl; using ControlGroup::importControl; using ControlGroup::syncControl; }; class ControlModeImporterStub : public ::ControlGroup::Importer { public: std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } }; class ControlModeExporterMock : public ::ControlGroup::Exporter { public: MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("ControlGroup tests", "[GPU][ControlGroup]") { std::string_view const id{"_id_"}; std::vector> controlMocks; SECTION("ID is assigned") { ControlGroupTestAdapter ts(id, std::move(controlMocks), true); REQUIRE(ts.ID() == id); } SECTION("Pre-init its controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, preInit(trompeloeil::_)); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); CommandQueueStub ctlCmds; ts.preInit(ctlCmds); } SECTION("Post-init its controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, postInit(trompeloeil::_)); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); CommandQueueStub ctlCmds; ts.postInit(ctlCmds); } SECTION("On initialization...") { SECTION("Initialize its controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); REQUIRE_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); } SECTION("Activate all inactive controls on initialization") { controlMocks.emplace_back(std::make_unique()); controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const inactiveControlMockID0("_active_control_mock"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(inactiveControlMockID0); ALLOW_CALL(*controlMock, active()).RETURN(true); FORBID_CALL(*controlMock, activate(trompeloeil::_)); controlMock = static_cast(controlMocks[1].get()); std::string const inactiveControlMockID1("_inactive_control_mock"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(inactiveControlMockID1); ALLOW_CALL(*controlMock, active()).RETURN(false); REQUIRE_CALL(*controlMock, activate(true)); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); } } SECTION("Imports controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, importWith(trompeloeil::_)); REQUIRE_CALL(*controlMock, activate(true)); ControlModeImporterStub i; ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); ts.importControl(i); } SECTION("Export controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, exportWith(trompeloeil::_)); ControlModeExporterMock e; ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); ts.exportControl(e); } SECTION("Clean controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, clean(trompeloeil::_)); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); CommandQueueStub ctlCmds; ts.cleanControl(ctlCmds); } SECTION("Request clean once on controls when its in dirty state") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, cleanOnce()); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); ts.activate(true); ts.activate(false); } SECTION("Clean once is propagated to controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, cleanOnce()); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); ts.cleanOnce(); } SECTION("Sync controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, sync(trompeloeil::_)); ControlGroupTestAdapter ts(id, std::move(controlMocks), true); ts.init(); CommandQueueStub ctlCmds; ts.syncControl(ctlCmds); } } } // namespace Tests::ControlGroup corectrl-v1.4.2/tests/src/test_controlmode.cpp000066400000000000000000000222271467225065400215620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/controlmock.h" #include "core/components/controls/controlmode.h" extern template struct trompeloeil::reporter; namespace Tests::ControlMode { class ControlModeTestAdapter : public ::ControlMode { public: using ControlMode::ControlMode; using ControlMode::cleanControl; using ControlMode::exportControl; using ControlMode::importControl; using ControlMode::mode; using ControlMode::syncControl; }; class ControlModeImporterStub : public ::ControlMode::Importer { public: ControlModeImporterStub(std::string mode) : mode_(std::move(mode)) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &provideMode() const override { return mode_; } private: std::string mode_; }; class ControlModeExporterMock : public ::ControlMode::Exporter { public: MAKE_MOCK1(takeMode, void(std::string const &), override); MAKE_MOCK1(takeModes, void(std::vector const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("ControlMode tests", "[GPU][ControlMode]") { std::string_view const id{"_id_"}; std::vector> controlMocks; SECTION("ID is assigned") { ControlModeTestAdapter ts(id, std::move(controlMocks), true); REQUIRE(ts.ID() == id); } SECTION("mode are set only for known control ids") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.mode(controlMockID); REQUIRE(ts.mode() == controlMockID); ts.mode("unknown"); REQUIRE(ts.mode() == controlMockID); } SECTION("Pre-init its controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, preInit(trompeloeil::_)); ControlModeTestAdapter ts(id, std::move(controlMocks), true); CommandQueueStub ctlCmds; ts.preInit(ctlCmds); } SECTION("Post-init its controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, postInit(trompeloeil::_)); ControlModeTestAdapter ts(id, std::move(controlMocks), true); CommandQueueStub ctlCmds; ts.postInit(ctlCmds); } SECTION("On initialization...") { SECTION("Initialize its controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); REQUIRE_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); } SECTION("Sets as active control the first active control, deactivating the " "following active controls") { controlMocks.emplace_back(std::make_unique()); controlMocks.emplace_back(std::make_unique()); controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const inactiveControlMockID("_inactive_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(inactiveControlMockID); ALLOW_CALL(*controlMock, active()).RETURN(false); std::string const activeControlMockID("_active_control_mock_"); controlMock = static_cast(controlMocks[1].get()); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(activeControlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); controlMock = static_cast(controlMocks[2].get()); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(activeControlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, activate(false)); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); REQUIRE(ts.mode() == activeControlMockID); } SECTION("Set the first control as active when all controls are inactive") { controlMocks.emplace_back(std::make_unique()); controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const inactiveControlMockID0("_inactive_control_mock_0"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(inactiveControlMockID0); ALLOW_CALL(*controlMock, active()).RETURN(false); REQUIRE_CALL(*controlMock, activate(true)); controlMock = static_cast(controlMocks[1].get()); std::string const inactiveControlMockID1("_inactive_control_mock_1"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(inactiveControlMockID1); ALLOW_CALL(*controlMock, active()).RETURN(false); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); REQUIRE(ts.mode() == inactiveControlMockID0); } } SECTION("Imports controls and mode") { controlMocks.emplace_back(std::make_unique()); controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const activeControlMockID("_active_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(activeControlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, importWith(trompeloeil::_)); REQUIRE_CALL(*controlMock, activate(false)); controlMock = static_cast(controlMocks[1].get()); std::string const newActiveControlMockID("_new_active_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(newActiveControlMockID); ALLOW_CALL(*controlMock, active()).RETURN(false); REQUIRE_CALL(*controlMock, importWith(trompeloeil::_)); REQUIRE_CALL(*controlMock, activate(true)); ControlModeImporterStub i("_new_active_control_mock_"); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); auto oldMode = ts.mode(); ts.importControl(i); REQUIRE(ts.mode() != oldMode); REQUIRE(ts.mode() == newActiveControlMockID); } SECTION("Export controls and mode") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, exportWith(trompeloeil::_)); std::vector const modes{controlMockID}; ControlModeExporterMock e; REQUIRE_CALL(e, takeModes(trompeloeil::eq(modes))); REQUIRE_CALL(e, takeMode(trompeloeil::eq(controlMockID))); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); ts.exportControl(e); } SECTION("Clean controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, clean(trompeloeil::_)); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); CommandQueueStub ctlCmds; ts.cleanControl(ctlCmds); } SECTION("Sync controls") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); std::string const controlMockID("_control_mock_"); ALLOW_CALL(*controlMock, init()); ALLOW_CALL(*controlMock, ID()).LR_RETURN(controlMockID); ALLOW_CALL(*controlMock, active()).RETURN(true); REQUIRE_CALL(*controlMock, sync(trompeloeil::_)); ControlModeTestAdapter ts(id, std::move(controlMocks), true); ts.init(); CommandQueueStub ctlCmds; ts.syncControl(ctlCmds); } } } // namespace Tests::ControlMode corectrl-v1.4.2/tests/src/test_cpu.cpp000066400000000000000000000126601467225065400200240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/controlmock.h" #include "common/sensormock.h" #include "core/components/cpu.h" #include "core/info/icpuinfo.h" extern template struct trompeloeil::reporter; namespace Tests::CPU { class CPUInfoStub : public ICPUInfo { public: int physicalId() const override { return 0; } std::vector const &executionUnits() const override { return executionUnits_; } std::vector keys() const override { return std::vector{"info_k1"}; } std::string info(std::string_view) const override { return "info_1"; } bool hasCapability(std::string_view) const override { return true; } void initialize(std::vector> const &) override { } private: std::vector const executionUnits_{{0, 0, "/cpu0"}}; }; class CPUImporterStub : public ICPU::Importer { public: std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } }; class CPUExporterMock : public ICPU::Exporter { public: MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1(takeInfo, void(ICPUInfo const &), override); MAKE_MOCK1(takeSensor, void(ISensor const &), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("CPU tests", "[CPU]") { CommandQueueStub ctlCmds; auto info = std::make_unique(); auto &infoStub = *info; std::vector> controls; controls.emplace_back(std::make_unique()); auto &controlMock = static_cast(*controls[0]); std::vector> sensors; sensors.emplace_back(std::make_unique()); auto &sensorMock = static_cast(*sensors[0]); ::CPU ts(std::move(info), std::move(controls), std::move(sensors)); SECTION("Has ICPU ID") { REQUIRE(ts.ID() == ICPU::ItemID); } SECTION("Is active by default") { REQUIRE(ts.active()); SECTION("Can be deactivated") { ts.activate(false); REQUIRE_FALSE(ts.active()); SECTION("Can be activated") { ts.activate(true); REQUIRE(ts.active()); } } } SECTION("Has a unique key in a system component scope") { // 'CPU' + physical id combination seems to be good enough to differentiate // between system components. REQUIRE_THAT(ts.key(), Catch::Matchers::ContainsSubstring("CPU") && Catch::Matchers::ContainsSubstring("0")); } SECTION("Its CPU information can be retrieved") { REQUIRE(&ts.info() == &infoStub); } SECTION("CPU description and information can be retrieved") { auto [gpuDesc, infos] = ts.componentInfo(); REQUIRE_THAT(gpuDesc, Catch::Matchers::ContainsSubstring("CPU") && Catch::Matchers::ContainsSubstring("0")); REQUIRE_FALSE(infos.empty()); auto &[infoKey, info] = infos[0]; REQUIRE(infoKey == "info_k1"); REQUIRE(info == "info_1"); } SECTION("Update its sensors") { std::string const sensorid("sensorid"); ALLOW_CALL(sensorMock, ID()).LR_RETURN(sensorid); REQUIRE_CALL(sensorMock, update()); std::unordered_map> ignored; ts.updateSensors(ignored); } SECTION("Does not update ignored sensors") { std::string const sensorid("sensorid"); std::unordered_map> ignored; ignored[ts.key()] = {}; ignored[ts.key()].emplace(sensorid); ALLOW_CALL(sensorMock, ID()).LR_RETURN(sensorid); FORBID_CALL(sensorMock, update()); ts.updateSensors(ignored); } SECTION("Pre-init its controls") { REQUIRE_CALL(controlMock, preInit(trompeloeil::_)); ts.preInit(ctlCmds); } SECTION("Post-init its controls") { REQUIRE_CALL(controlMock, postInit(trompeloeil::_)); ts.postInit(ctlCmds); } SECTION("Init controls") { REQUIRE_CALL(controlMock, init()); ts.init(); } SECTION("Only clear and sync controls when is active") { ALLOW_CALL(sensorMock, update()); REQUIRE_CALL(controlMock, clean(trompeloeil::_)); REQUIRE_CALL(controlMock, sync(trompeloeil::_)); ts.activate(true); ts.sync(ctlCmds); FORBID_CALL(controlMock, clean(trompeloeil::_)); FORBID_CALL(controlMock, sync(trompeloeil::_)); ts.activate(false); ts.sync(ctlCmds); } SECTION("Imports its state and controls") { REQUIRE_CALL(controlMock, importWith(trompeloeil::_)); ts.activate(true); CPUImporterStub i; ts.importWith(i); REQUIRE_FALSE(ts.active()); } SECTION("Exports its state, sensors and controls") { CPUExporterMock e; ALLOW_CALL(e, provideExporter(trompeloeil::_)).LR_RETURN(e); REQUIRE_CALL(e, takeActive(true)); REQUIRE_CALL(e, takeInfo(trompeloeil::_)).LR_WITH(&_1 == &infoStub); REQUIRE_CALL(e, takeSensor(trompeloeil::_)).LR_WITH(&_1 == &sensorMock); REQUIRE_CALL(controlMock, exportWith(trompeloeil::_)); ts.activate(true); ts.exportWith(e); } } } // namespace Tests::CPU corectrl-v1.4.2/tests/src/test_cpuepphandler.cpp000066400000000000000000000044351467225065400220700ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2024 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/cpu/handlers/epphandler.h" namespace Tests::CPU::EPPHandler { TEST_CASE("AMD PpDpmHandler tests", "[CPU][DataSourceHandler][EPPHandler]") { CommandQueueStub ctlCmds; std::string defaultHint{"default"}; auto availableEPPHintsDataSource = std::make_unique( "energy_performance_available_preferences", "default power"); std::vector>> eppHintDataSource{}; eppHintDataSource.emplace_back(std::make_unique( "energy_performance_preference", "default")); ::EPPHandler ts(std::move(availableEPPHintsDataSource), std::move(eppHintDataSource)); ts.init(); SECTION("Initialize the available EPP hints from its data source") { std::vector eppHints = {"default", "power"}; REQUIRE_THAT(ts.hints(), Catch::Matchers::Equals(eppHints)); } SECTION("Has 'default' as the active hint by default when available") { REQUIRE(ts.hint() == defaultHint); } SECTION("Setting a hint...") { SECTION("Works with known hints") { ts.hint("power"); REQUIRE(ts.hint() == "power"); } SECTION("Ignores unknown hints") { ts.hint("unknown"); REQUIRE(ts.hint() == defaultHint); } } SECTION("Does not save and restore CPU data source state") { ts.saveState(); ts.restoreState(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate reset control commands") { ts.reset(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { ts.sync(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Generates sync control commands when CPU hint is out of sync") { ts.hint("power"); ts.sync(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmdPath, cmdValue] = commands.at(0); REQUIRE(cmdPath == "energy_performance_preference"); REQUIRE(cmdValue == "power"); } } } // namespace Tests::CPU::EPPHandler corectrl-v1.4.2/tests/src/test_cpufreq.cpp000066400000000000000000000311431467225065400206770ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/stringdatasourcestub.h" #include "core/components/controls/cpu/cpufreq.h" #include "core/components/controls/cpu/handlers/iepphandler.h" extern template struct trompeloeil::reporter; namespace Tests::CPUFreq { class CPUFreqTestAdapter : public ::CPUFreq { public: using ::CPUFreq::CPUFreq; using ::CPUFreq::cleanControl; using ::CPUFreq::exportControl; using ::CPUFreq::importControl; using ::CPUFreq::scalingGovernor; using ::CPUFreq::scalingGovernors; using ::CPUFreq::syncControl; }; class CPUFreqImporterStub : public ::CPUFreq::Importer { public: CPUFreqImporterStub(std::string_view scalingGovernor, std::optional eppHint = std::nullopt) : scalingGovernor_(scalingGovernor) , eppHint_(eppHint) { } std::optional> provideImporter(Item const &) override { return {}; } bool provideActive() const override { return false; } std::string const &provideCPUFreqScalingGovernor() const override { return scalingGovernor_; } std::optional const &provideCPUFreqEPPHint() const override { return eppHint_; } private: std::string scalingGovernor_; std::optional eppHint_; }; class EPPHandlerMock : public IEPPHandler { public: MAKE_CONST_MOCK0(hints, std::vector const &(void), override); MAKE_CONST_MOCK0(hint, std::string const &(), override); MAKE_MOCK1(hint, void(std::string const &), override); MAKE_MOCK0(init, void(), override); MAKE_MOCK0(saveState, void(), override); MAKE_MOCK1(restoreState, void(ICommandQueue &), override); MAKE_MOCK1(reset, void(ICommandQueue &), override); MAKE_MOCK1(sync, void(ICommandQueue &), override); }; class CPUFreqImporterMock : public ::CPUFreq::Importer { public: MAKE_CONST_MOCK0(provideCPUFreqScalingGovernor, std::string const &(void), override); MAKE_CONST_MOCK0(provideCPUFreqEPPHint, std::optional const &(void), override); MAKE_CONST_MOCK0(provideActive, bool(void), override); MAKE_MOCK1( provideImporter, std::optional>(Item const &), override); }; class CPUFreqExporterMock : public ::CPUFreq::Exporter { public: MAKE_MOCK1(takeCPUFreqScalingGovernor, void(std::string const &), override); MAKE_MOCK1(takeCPUFreqScalingGovernors, void(std::vector const &), override); MAKE_MOCK1(takeCPUFreqEPPHint, void(std::optional const &), override); MAKE_MOCK1(takeCPUFreqEPPHints, void(std::optional> const &), override); MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("AMD CPUFreq tests", "[CPU][CPUFreq]") { std::vector availableGovernors{"performance", "powersave"}; std::vector>> scalingGovernorDataSources; std::string defaultGovernor{"powersave"}; std::string const scalingGovernorPath{"scaling_governor"}; CommandQueueStub ctlCmds; SECTION("Has CPUFreq ID") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); REQUIRE(ts.ID() == ::CPUFreq::ItemID); } SECTION("Is active by default") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); REQUIRE(ts.active()); } SECTION("Has defaultGovernor selected by default when is available") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); REQUIRE(ts.scalingGovernor() == defaultGovernor); } SECTION("Has the first available scaling governor selected by default when " "defaultGovernor is not available") { std::vector otherGovernors{"_other_0_", "_other_1_"}; CPUFreqTestAdapter ts(std::move(otherGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); REQUIRE(ts.scalingGovernor() == "_other_0_"); } SECTION("scalingGovernor only sets known scaling governors") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); ts.scalingGovernor("performance"); REQUIRE(ts.scalingGovernor() == "performance"); ts.scalingGovernor("unknown"); REQUIRE(ts.scalingGovernor() == "performance"); } SECTION( "Does not generate pre-init control commands when EPP is not supported") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION( "Does not generate pre-init control commands when EPP is supported and " "the current scaling governor is the EPP scaling governor ('powersave')") { auto eppHandlerMock = std::make_unique(); scalingGovernorDataSources.emplace_back( std::make_unique(scalingGovernorPath, "powersave")); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate pre-init control commands to set the scaling governor " "when EPP is supported and the current scaling governor is not the " "EPP scaling governor ('powersave')") { auto eppHandlerMock = std::make_unique(); scalingGovernorDataSources.emplace_back( std::make_unique(scalingGovernorPath, "performance")); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == scalingGovernorPath); REQUIRE(value == "powersave"); } SECTION("Does not generate post-init control commands") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Initialize EPP handler when EPP is supported") { auto eppHandlerMock = std::make_unique(); REQUIRE_CALL(*eppHandlerMock, init()); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); ts.init(); } SECTION("Imports scaling governor state") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); CPUFreqImporterStub i("performance"); ts.importControl(i); REQUIRE(ts.scalingGovernor() == "performance"); } SECTION("Imports EPP hint state when EPP is supported") { std::string eppHint{"power"}; auto eppHandlerMock = std::make_unique(); REQUIRE_CALL(*eppHandlerMock, hint(trompeloeil::_)).LR_WITH(_1 == eppHint); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); CPUFreqImporterStub i("performance", eppHint); ts.importControl(i); } SECTION("Export scaling governor state and available scaling governors") { auto governors = availableGovernors; CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); trompeloeil::sequence seq; CPUFreqExporterMock e; REQUIRE_CALL(e, takeCPUFreqScalingGovernors(trompeloeil::_)) .LR_WITH(_1 == governors) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takeCPUFreqEPPHints(trompeloeil::eq(std::nullopt))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takeCPUFreqScalingGovernor(trompeloeil::eq(defaultGovernor))) .IN_SEQUENCE(seq); REQUIRE_CALL(e, takeCPUFreqEPPHint(trompeloeil::eq(std::nullopt))) .IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Export EPP hint state and available hints when EPP is supported") { std::vector eppHints{"default", "power"}; std::string eppHint{"default"}; auto eppHandlerMock = std::make_unique(); ALLOW_CALL(*eppHandlerMock, hints()).RETURN(eppHints); ALLOW_CALL(*eppHandlerMock, hint()).RETURN(eppHint); auto governors = availableGovernors; CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); trompeloeil::sequence seq; CPUFreqExporterMock e; ALLOW_CALL(e, takeCPUFreqScalingGovernors(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takeCPUFreqEPPHints(trompeloeil::_)) .LR_WITH(_1 == eppHints) .IN_SEQUENCE(seq); ALLOW_CALL(e, takeCPUFreqScalingGovernor(trompeloeil::_)).IN_SEQUENCE(seq); REQUIRE_CALL(e, takeCPUFreqEPPHint(trompeloeil::eq(eppHint))).IN_SEQUENCE(seq); ts.exportControl(e); } SECTION("Does not generate clean control commands") { CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands when is synced") { scalingGovernorDataSources.emplace_back( std::make_unique(scalingGovernorPath, defaultGovernor)); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does generate sync control commands when is out of sync") { scalingGovernorDataSources.emplace_back( std::make_unique(scalingGovernorPath, "_other_")); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources)); ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().size() == 1); auto &[path, value] = ctlCmds.commands().front(); REQUIRE(path == scalingGovernorPath); REQUIRE(value == defaultGovernor); } SECTION("Does not generate sync control commands for EPP when this feature " "is supported and the frequency scaling governor is not set " "to 'powersave'") { auto eppHandlerMock = std::make_unique(); FORBID_CALL(*eppHandlerMock, sync(trompeloeil::_)); scalingGovernorDataSources.emplace_back( std::make_unique(scalingGovernorPath, defaultGovernor)); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); ts.scalingGovernor("performance"); ts.syncControl(ctlCmds); } SECTION("Could generate sync control commands for EPP when this feature " "is supported and the frequency scaling governor is set " "to 'powersave'") { auto eppHandlerMock = std::make_unique(); REQUIRE_CALL(*eppHandlerMock, sync(trompeloeil::_)); scalingGovernorDataSources.emplace_back( std::make_unique(scalingGovernorPath, defaultGovernor)); CPUFreqTestAdapter ts(std::move(availableGovernors), defaultGovernor, std::move(scalingGovernorDataSources), std::move(eppHandlerMock)); ts.syncControl(ctlCmds); } } } // namespace Tests::CPUFreq corectrl-v1.4.2/tests/src/test_cpufreqmode.cpp000066400000000000000000000011611467225065400215410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include "core/components/controls/cpu/cpufreqmode.h" namespace Tests::CPUFreqMode { TEST_CASE("AMD CPUFreqMode tests", "[CPU][CPUFreqMode]") { std::vector> controlMocks; SECTION("Has CPUFreqMode ID") { ::CPUFreqMode ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::CPUFreqMode::ItemID); } SECTION("Is active by default") { ::CPUFreqMode ts(std::move(controlMocks)); REQUIRE(ts.active()); } } } // namespace Tests::CPUFreqMode corectrl-v1.4.2/tests/src/test_cpuinfo.cpp000066400000000000000000000031711467225065400206750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/info/cpuinfo.h" namespace Tests::CPUInfo { class ProviderStub : public ICPUInfo::IProvider { public: std::vector> provideInfo(int, std::vector const &) override { std::vector> info; info.emplace_back("info_key", "info"); return info; } std::vector provideCapabilities(int, std::vector const &) override { std::vector cap; cap.emplace_back("capability"); return cap; } }; TEST_CASE("CPUInfo tests", "[Info][CPUInfo]") { int physicalId{0}; ::CPUInfo ts(physicalId, {{0, 0, "/proc/cpu0"}}); SECTION("Has CPU physical id") { REQUIRE(ts.physicalId() == physicalId); } SECTION("Has execution units") { REQUIRE_FALSE(ts.executionUnits().empty()); auto &unit = ts.executionUnits().front(); REQUIRE(unit.cpuId == 0); REQUIRE(unit.coreId == 0); REQUIRE(unit.sysPath == "/proc/cpu0"); } SECTION("CPU info and capabilities are collected on initialization") { REQUIRE(ts.keys().empty()); std::vector> providers; providers.emplace_back(std::make_unique()); ts.initialize(providers); auto keys = ts.keys(); REQUIRE(keys.size() == 1); REQUIRE(keys.front() == "info_key"); REQUIRE(ts.info("info_key") == "info"); REQUIRE(ts.hasCapability("capability")); } } } // namespace Tests::CPUInfo corectrl-v1.4.2/tests/src/test_cpuinfolscpu.cpp000066400000000000000000000076241467225065400217530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "common/vectorstringdatasourcestub.h" #include "core/info/common/cpuinfolscpu.h" namespace Tests::CPUInfoLsCpu { TEST_CASE("CPUInfoLsCpu tests", "[Info][CPUInfo][CPUInfoLsCpu]") { SECTION("Returns empty info when there is no data") { std::vector const infoData; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); REQUIRE(output.empty()); } SECTION("Provides architecture") { std::vector const infoData{"Architecture: z48"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::arch), std::string("z48")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides operation mode") { std::vector const infoData{"CPU op-mode(s): 48-bit"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::opMode), std::string("48-bit")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides byte order") { std::vector const infoData{ "Byte Order: Middle Endian"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::byteOrder), std::string("Middle Endian")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides virtualization") { std::vector const infoData{"Virtualization: zzz"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::virt), std::string("zzz")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides L1d cache size") { std::vector const infoData{"L1d cache: 320K"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::l1dCache), std::string("320K")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides L1i cache size") { std::vector const infoData{"L1i cache: 320K"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::l1iCache), std::string("320K")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides L2 cache size") { std::vector const infoData{"L2 cache: 640K"}; ::CPUInfoLsCpu ts( std::make_unique("lscpu", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::CPUInfoLsCpu::Keys::l2Cache), std::string("640K")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } } } // namespace Tests::CPUInfoLsCpu corectrl-v1.4.2/tests/src/test_cpuinfoproccpuinfo.cpp000066400000000000000000000137021467225065400231460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "common/vectorstringdatasourcestub.h" #include "core/info/common/cpuinfoproccpuinfo.h" namespace Tests::CPUInfoProcCpuInfo { TEST_CASE("CPUInfoProcCpuInfo tests", "[Info][CPUInfo][CPUInfoProcCpuInfo]") { std::vector infoData{"processor : 0"}; SECTION("Returns empty info when there is no data") { infoData.clear(); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData, false)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); REQUIRE(output.empty()); } SECTION("Provides execution units count") { ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::executionUnits), std::string("1")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides vendor id") { infoData.emplace_back("vendor_id : TheVendor"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::vendorId), std::string("TheVendor")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides cpu family") { infoData.emplace_back("cpu family : 128"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::cpuFamily), std::string("128")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides model") { infoData.emplace_back("model : 8"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::model), std::string("8")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides model name") { infoData.emplace_back("model name : Potato"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::modelName), std::string("Potato")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides stepping") { infoData.emplace_back("stepping : 2"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::stepping), std::string("2")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides microcode") { infoData.emplace_back("microcode : 0x01"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::ucode), std::string("0x01")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides L3 cache size") { infoData.emplace_back("cache size : 8192 KB"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::l3Cache), std::string("8192 KB")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides cores count") { infoData.emplace_back("cpu cores : 64"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::cores), std::string("64")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides flags") { infoData.emplace_back("flags : a lot"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::flags), std::string("a lot")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides bugs") { infoData.emplace_back("bugs : yes"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::bugs), std::string("yes")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } SECTION("Provides bogomips") { infoData.emplace_back("bogomips : 20.45"); ::CPUInfoProcCpuInfo ts(std::make_unique( "/proc/cpuinfo", infoData)); auto output = ts.provideInfo(0, {{0, 0, "/cpu0"}}); auto data = std::make_pair(std::string(::ICPUInfo::Keys::bogomips), std::string("20.45")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(data)); } } } // namespace Tests::CPUInfoProcCpuInfo corectrl-v1.4.2/tests/src/test_cpuutils.cpp000066400000000000000000000066471467225065400211150ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/components/cpuutils.h" namespace Tests::Utils::CPU { TEST_CASE("CPU utils tests", "[Utils][CPU]") { SECTION("parseProcCpuInfo") { // clang-format off std::vector input{"processor : 0", "target : data"}; // clang-format on SECTION("Returns target data") { auto data = ::Utils::CPU::parseProcCpuInfo(input, 0, "target"); REQUIRE(data.has_value()); REQUIRE(*data == "data"); } SECTION("Returns nothing when input doesn't have the requested processor") { auto data = ::Utils::CPU::parseProcCpuInfo(input, 10, "target"); REQUIRE_FALSE(data.has_value()); } SECTION("Returns nothing when input doesn't have the requested target on " "the processor") { auto data = ::Utils::CPU::parseProcCpuInfo(input, 0, "wrong_target"); REQUIRE_FALSE(data.has_value()); } } SECTION("parseProcStat") { SECTION("Returns the CPU aggregate stats from /proc/stat info") { std::vector input{ "cpu 141434 264 40474 2021588 12439 5752 2750 0 0 0"}; auto stat = ::Utils::CPU::parseProcStat(input); REQUIRE(stat.has_value()); REQUIRE(stat->user == 141434); REQUIRE(stat->nice == 264); REQUIRE(stat->system == 40474); REQUIRE(stat->idle == 2021588); REQUIRE(stat->ioWait == 12439); REQUIRE(stat->irq == 5752); REQUIRE(stat->softIrq == 2750); REQUIRE(stat->steal == 0); REQUIRE(stat->total == 141434 + 264 + 40474 + 2021588 + 12439 + 5752 + 2750 + 0); } SECTION("Returns nothing when some stat values are missing from the cpu " "aggregate line") { std::vector input{"cpu 141434 264 40474 2021588 0 0 0"}; auto stat = ::Utils::CPU::parseProcStat(input); REQUIRE_FALSE(stat.has_value()); } SECTION("Returns nothing when the cpu aggregate line is missing") { std::vector input{"other data"}; auto stat = ::Utils::CPU::parseProcStat(input); REQUIRE_FALSE(stat.has_value()); } } SECTION("computeCPUUsage") { SECTION("Returns CPU usage") { std::uint64_t total = 723998 + 5703 + 159187 + 9095956 + 22936 + 23633 + 10115 + 0; auto statT0 = ::Utils::CPU::Stat{723998, 5703, 159187, 9095956, 22936, 23633, 10115, 0, total}; total = 725077 + 5703 + 159248 + 9095956 + 22936 + 23638 + 10116 + 0; auto statT1 = ::Utils::CPU::Stat{725077, 5703, 159248, 9095956, 22936, 23638, 10116, 0, total}; auto usage = ::Utils::CPU::computeCPUUsage(statT0, statT1); REQUIRE(usage == 100); total = 664215 + 2940 + 147770 + 6752849 + 19569 + 21752 + 9330 + 0; statT0 = ::Utils::CPU::Stat{664215, 2940, 147770, 6752849, 19569, 21752, 9330, 0, total}; total = 664215 + 2940 + 147770 + 6754574 + 19583 + 21752 + 9330 + 0; statT1 = ::Utils::CPU::Stat{664215, 2940, 147770, 6754574, 19583, 21752, 9330, 0, total}; usage = ::Utils::CPU::computeCPUUsage(statT0, statT1); REQUIRE(usage == 0); } } } } // namespace Tests::Utils::CPU corectrl-v1.4.2/tests/src/test_gpu.cpp000066400000000000000000000127151467225065400200310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "common/controlmock.h" #include "common/sensormock.h" #include "core/components/gpu.h" #include "core/info/igpuinfo.h" extern template struct trompeloeil::reporter; namespace Tests::GPU { class GPUInfoStub : public IGPUInfo { public: Vendor vendor() const override { return Vendor::AMD; } int index() const override { return 123; } IGPUInfo::Path const &path() const override { return path_; } std::vector keys() const override { return std::vector{"info_k1"}; } std::string info(std::string_view) const override { return "info_1"; } bool hasCapability(std::string_view) const override { return true; } void initialize(std::vector> const &, IHWIDTranslator const &) override { } private: IGPUInfo::Path path_{"_sys_", "_dev_"}; }; class GPUImporterStub : public IGPU::Importer { public: std::optional> provideImporter(Item const &) override { return *this; } bool provideActive() const override { return false; } }; class GPUExporterMock : public IGPU::Exporter { public: MAKE_MOCK1(takeActive, void(bool), override); MAKE_MOCK1(takeInfo, void(IGPUInfo const &), override); MAKE_MOCK1(takeSensor, void(ISensor const &), override); MAKE_MOCK1( provideExporter, std::optional>(Item const &), override); }; TEST_CASE("GPU tests", "[GPU]") { CommandQueueStub ctlCmds; auto info = std::make_unique(); auto &infoStub = *info; std::vector> controls; controls.emplace_back(std::make_unique()); auto &controlMock = static_cast(*controls[0]); std::vector> sensors; sensors.emplace_back(std::make_unique()); auto &sensorMock = static_cast(*sensors[0]); ::GPU ts(std::move(info), std::move(controls), std::move(sensors)); SECTION("Has IGPU ID") { REQUIRE(ts.ID() == IGPU::ItemID); } SECTION("Is active by default") { REQUIRE(ts.active()); SECTION("Can be deactivated") { ts.activate(false); REQUIRE_FALSE(ts.active()); SECTION("Can be activated") { ts.activate(true); REQUIRE(ts.active()); } } } SECTION("Has a unique key in a system component scope") { // 'GPU' + gpu index combination seems to be good enough to differentiate // between system components. REQUIRE_THAT(ts.key(), Catch::Matchers::ContainsSubstring("GPU") && Catch::Matchers::ContainsSubstring("123")); } SECTION("Its GPU information can be retrieved") { REQUIRE(&ts.info() == &infoStub); } SECTION("GPU description and information can be retrieved") { auto [gpuDesc, infos] = ts.componentInfo(); REQUIRE_THAT(gpuDesc, Catch::Matchers::ContainsSubstring("GPU") && Catch::Matchers::ContainsSubstring("123")); REQUIRE_FALSE(infos.empty()); auto &[infoKey, info] = infos[0]; REQUIRE(infoKey == "info_k1"); REQUIRE(info == "info_1"); } SECTION("Update its sensors") { std::string const sensorid("sensorid"); ALLOW_CALL(sensorMock, ID()).LR_RETURN(sensorid); REQUIRE_CALL(sensorMock, update()); std::unordered_map> ignored; ts.updateSensors(ignored); } SECTION("Does not update ignored sensors") { std::string const sensorid("sensorid"); std::unordered_map> ignored; ignored[ts.key()] = {}; ignored[ts.key()].emplace(sensorid); ALLOW_CALL(sensorMock, ID()).LR_RETURN(sensorid); FORBID_CALL(sensorMock, update()); ts.updateSensors(ignored); } SECTION("Pre-init its controls") { REQUIRE_CALL(controlMock, preInit(trompeloeil::_)); ts.preInit(ctlCmds); } SECTION("Post-init its controls") { REQUIRE_CALL(controlMock, postInit(trompeloeil::_)); ts.postInit(ctlCmds); } SECTION("Init controls") { REQUIRE_CALL(controlMock, init()); ts.init(); } SECTION("Only clear and sync controls when is active") { ALLOW_CALL(sensorMock, update()); REQUIRE_CALL(controlMock, clean(trompeloeil::_)); REQUIRE_CALL(controlMock, sync(trompeloeil::_)); ts.activate(true); ts.sync(ctlCmds); FORBID_CALL(controlMock, clean(trompeloeil::_)); FORBID_CALL(controlMock, sync(trompeloeil::_)); ts.activate(false); ts.sync(ctlCmds); } SECTION("Imports its state and controls") { REQUIRE_CALL(controlMock, importWith(trompeloeil::_)); ts.activate(true); GPUImporterStub i; ts.importWith(i); REQUIRE_FALSE(ts.active()); } SECTION("Exports its state, sensors and controls") { GPUExporterMock e; ALLOW_CALL(e, provideExporter(trompeloeil::_)).LR_RETURN(e); REQUIRE_CALL(e, takeActive(true)); REQUIRE_CALL(e, takeInfo(trompeloeil::_)).LR_WITH(&_1 == &infoStub); REQUIRE_CALL(e, takeSensor(trompeloeil::_)).LR_WITH(&_1 == &sensorMock); REQUIRE_CALL(controlMock, exportWith(trompeloeil::_)); ts.activate(true); ts.exportWith(e); } } } // namespace Tests::GPU corectrl-v1.4.2/tests/src/test_gpuinfo.cpp000066400000000000000000000041421467225065400207000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/info/gpuinfo.h" #include "core/info/ihwidtranslator.h" namespace Tests::GPUInfo { class ProviderStub : public IGPUInfo::IProvider { public: std::vector> provideInfo(Vendor, int, IGPUInfo::Path const &, IHWIDTranslator const &) const override { std::vector> info; info.emplace_back("info_key", "info"); return info; } std::vector provideCapabilities(Vendor, int, IGPUInfo::Path const &) const override { std::vector cap; cap.emplace_back("capability"); return cap; } }; class HWIDTranslatorStub : public IHWIDTranslator { public: std::string vendor(std::string const &) const override { return ""; } std::string device(std::string const &, std::string const &) const override { return ""; } std::string subdevice(std::string const &, std::string const &, std::string const &, std::string const &) const override { return ""; } }; TEST_CASE("GPUInfo tests", "[Info][GPUInfo]") { int gpuIndex{123}; ::GPUInfo ts(Vendor::AMD, gpuIndex, IGPUInfo::Path("_sys_", "_dev_")); SECTION("Has vendor") { REQUIRE(ts.vendor() == Vendor::AMD); } SECTION("Has GPU index") { REQUIRE(ts.index() == gpuIndex); } SECTION("Has device paths") { REQUIRE(ts.path().sys == "_sys_"); REQUIRE(ts.path().dev == "_dev_"); } SECTION("GPU info and capabilities are collected on initialization") { REQUIRE(ts.keys().empty()); HWIDTranslatorStub hwidTranStub; std::vector> providers; providers.emplace_back(std::make_unique()); ts.initialize(providers, hwidTranStub); auto keys = ts.keys(); REQUIRE(keys.size() == 1); REQUIRE(keys.front() == "info_key"); REQUIRE(ts.info("info_key") == "info"); REQUIRE(ts.hasCapability("capability")); } } } // namespace Tests::GPUInfo corectrl-v1.4.2/tests/src/test_gpuinfoopengl.cpp000066400000000000000000000035131467225065400221060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "core/idatasource.h" #include "core/info/common/gpuinfoopengl.h" namespace Tests::GPUInfoOpenGL { class GPUInfoOpenGLDataSourceStub : public IDataSource { public: GPUInfoOpenGLDataSourceStub(std::string source = "", std::string data = "") : source_(std::move(source)) , data_(std::move(data)) { } std::string source() const override { return source_; } bool read(std::string &data, int const &) override { data = data_; return true; } private: std::string const source_; std::string const data_; }; TEST_CASE("GPUInfoOpenGL tests", "[Info][GPUInfo][GPUInfoOpenGL]") { std::string const infoData( // clang-format off "...\n\ Extended renderer info (GLX_MESA_query_renderer):\n\ ...\n\ Max core profile version: 1.1\n\ Max compat profile version: 2.2\n\ ..."); // clang-format on Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorStub hwIDTranslator; ::GPUInfoOpenGL ts( std::make_unique("glxinfo", infoData)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); SECTION("Provides core version") { auto coreVersion = std::make_pair( std::string(::GPUInfoOpenGL::Keys::coreVersion), std::string("1.1")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(coreVersion)); } SECTION("Provides compat version") { auto compatVersion = std::make_pair( std::string(::GPUInfoOpenGL::Keys::compatVersion), std::string("2.2")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(compatVersion)); } } } // namespace Tests::GPUInfoOpenGL corectrl-v1.4.2/tests/src/test_gpuinforevision.cpp000066400000000000000000000017601467225065400224620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "common/stringpathdatasourcestub.h" #include "core/info/common/gpuinforevision.h" namespace Tests::GPUInfoRevision { TEST_CASE("GPUInfoRevision tests", "[Info][GPUInfo][GPUInfoRevision]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorStub hwIDTranslator; SECTION("Provides revision") { std::string const infoData("0x123"); ::GPUInfoRevision ts( std::make_unique("revision", infoData)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto revision = std::make_pair(std::string(IGPUInfo::Keys::revision), std::string("123")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(revision)); } } } // namespace Tests::GPUInfoRevision corectrl-v1.4.2/tests/src/test_gpuinfouevent.cpp000066400000000000000000000116011467225065400221250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "core/idatasource.h" #include "core/info/common/gpuinfouevent.h" #include "core/info/ihwidtranslator.h" extern template struct trompeloeil::reporter; using trompeloeil::_; namespace Tests::GPUInfoUevent { class GPUInfoUeventDataSourceStub : public IDataSource, std::filesystem::path const> { public: std::string source() const override { return "uevent"; } bool read(std::vector &data, std::filesystem::path const &) override { data.clear(); data.emplace_back("DRIVER=driver"); data.emplace_back("PCI_ID=1111:2222"); data.emplace_back("PCI_SUBSYS_ID=3333:4444"); data.emplace_back("PCI_SLOT_NAME=0000:01:00.0"); return true; } }; class HWIDTranslatorMock : public IHWIDTranslator { public: MAKE_CONST_MOCK1(vendor, std::string(std::string const &)); MAKE_CONST_MOCK2(device, std::string(std::string const &, std::string const &)); MAKE_CONST_MOCK4(subdevice, std::string(std::string const &, std::string const &, std::string const &, std::string const &)); }; TEST_CASE("GPUInfoUevent tests", "[Info][GPUInfo][GPUInfoUevent]") { std::string vName("v_name"); std::string dName("d_name"); std::string sdName("s_name"); Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorMock hwIDTranslator; ALLOW_CALL(hwIDTranslator, vendor(_)).LR_RETURN(vName); ALLOW_CALL(hwIDTranslator, device(_, _)).LR_RETURN(dName); ALLOW_CALL(hwIDTranslator, subdevice(_, _, _, _)).LR_RETURN(sdName); ::GPUInfoUevent ts(std::make_unique()); SECTION("Provides driver") { auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto driver = std::make_pair(std::string(IGPUInfo::Keys::driver), std::string("driver")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(driver)); } SECTION("Provides PCI slot") { auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto driver = std::make_pair(std::string(IGPUInfo::Keys::pciSlot), std::string("0000:01:00.0")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(driver)); } SECTION("Provides vendor id") { auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto vendorID = std::make_pair(std::string(IGPUInfo::Keys::vendorID), std::string("1111")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(vendorID)); } SECTION("Provides vendor name") { REQUIRE_CALL(hwIDTranslator, vendor("1111")).LR_RETURN(vName); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto vendorName = std::make_pair(std::string(IGPUInfo::Keys::vendorName), vName); REQUIRE_THAT(output, Catch::Matchers::VectorContains(vendorName)); } SECTION("Provides device id") { auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto deviceID = std::make_pair(std::string(IGPUInfo::Keys::deviceID), std::string("2222")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(deviceID)); } SECTION("Provides device name") { REQUIRE_CALL(hwIDTranslator, device("1111", "2222")).LR_RETURN(dName); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto deviceName = std::make_pair(std::string(IGPUInfo::Keys::deviceName), dName); REQUIRE_THAT(output, Catch::Matchers::VectorContains(deviceName)); } SECTION("Provides subvendor id") { auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto subvendorID = std::make_pair(std::string(IGPUInfo::Keys::subvendorID), std::string("3333")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(subvendorID)); } SECTION("Provides subdevice id") { auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto subdeviceID = std::make_pair(std::string(IGPUInfo::Keys::subdeviceID), std::string("4444")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(subdeviceID)); } SECTION("Provides subdevice name") { REQUIRE_CALL(hwIDTranslator, subdevice("1111", "2222", "3333", "4444")) .LR_RETURN(sdName); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto subdeviceName = std::make_pair( std::string(IGPUInfo::Keys::subdeviceName), sdName); REQUIRE_THAT(output, Catch::Matchers::VectorContains(subdeviceName)); } } } // namespace Tests::GPUInfoUevent corectrl-v1.4.2/tests/src/test_gpuinfovram.cpp000066400000000000000000000172261467225065400215750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include #include "common/hwidtranslatorstub.h" #include "core/idatasource.h" #include "core/info/amd/gpuinfovram.h" #include #include extern template struct trompeloeil::reporter; namespace Tests::GPUInfoVRam { class KernelSWInfoDataSourceStub : public IDataSource { public: KernelSWInfoDataSourceStub(std::string data = "") : data_(std::move(data)) { } std::string source() const override { return "/proc/version"; } bool read(std::string &data) override { data = data_; return true; } private: std::string const data_; }; class GPUInfoDataSourceStub : public IDataSource, std::filesystem::path const> { public: GPUInfoDataSourceStub(std::vector data) : data_(std::move(data)) { } std::string source() const override { return ""; } bool read(std::vector &data, std::filesystem::path const &) override { data = data_; return true; } private: std::vector const data_; }; class GPUInfoVRamDataSourceStub : public IDataSource { public: GPUInfoVRamDataSourceStub(units::data::megabyte_t data, bool success) : data_(std::move(data)) , success_(success) { } std::string source() const override { return ""; } bool read(units::data::megabyte_t &data, std::filesystem::path const &) override { data = data_; return success_; } private: units::data::megabyte_t const data_; bool const success_; }; class HWIDTranslatorMock : public IHWIDTranslator { public: MAKE_CONST_MOCK1(vendor, std::string(std::string const &)); MAKE_CONST_MOCK2(device, std::string(std::string const &, std::string const &)); MAKE_CONST_MOCK4(subdevice, std::string(std::string const &, std::string const &, std::string const &, std::string const &)); }; TEST_CASE("GPUInfoVRam tests", "[Info][GPUInfo][GPUInfoVRam]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorStub hwIDTranslator; SECTION("radeon driver") { auto driverDataSource = std::make_unique( std::vector({std::string("DRIVER=radeon")})); auto amdgpuVRamDataSource = std::make_unique( units::make_unit(16), true); SECTION("Valid vram data source") { auto radeonVRamDataSource = std::make_unique( units::make_unit(8), true); SECTION("Provides vram size when kernel >= 2.6.31") { ::GPUInfoVRam ts(std::make_unique( "Linux version 2.6.31_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto memory = std::make_pair(std::string(::IGPUInfo::Keys::memory), std::string("8 MB")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(memory)); } SECTION("Does not provide vram size when kernel < 2.6.31") { ::GPUInfoVRam ts(std::make_unique( "Linux version 2.6.30_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); REQUIRE(output.empty()); } } SECTION( "Does not provide vram size when the vram data source cannot be read") { auto radeonVRamDataSource = std::make_unique( units::make_unit(8), false); ::GPUInfoVRam ts(std::make_unique( "Linux version 2.6.31_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); REQUIRE(output.empty()); } } SECTION("amdgpu driver") { auto driverDataSource = std::make_unique( std::vector({std::string("DRIVER=amdgpu")})); auto radeonVRamDataSource = std::make_unique( units::make_unit(8), true); SECTION("Valid vram data source") { auto amdgpuVRamDataSource = std::make_unique( units::make_unit(16), true); SECTION("Provides vram size when kernel >= 4.10") { ::GPUInfoVRam ts(std::make_unique( "Linux version 4.10.0_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto memory = std::make_pair(std::string(::IGPUInfo::Keys::memory), std::string("16 MB")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(memory)); } SECTION("Does not provide vram size when kernel < 4.10") { ::GPUInfoVRam ts(std::make_unique( "Linux version 4.9.0_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); REQUIRE(output.empty()); } } SECTION( "Does not provide vram size when the vram data source cannot be read") { auto amdgpuVRamDataSource = std::make_unique( units::make_unit(16), false); ::GPUInfoVRam ts(std::make_unique( "Linux version 4.10.0_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); REQUIRE(output.empty()); } } SECTION("Does not provide vram size when using an unknown driver") { auto driverDataSource = std::make_unique( std::vector({std::string("DRIVER=unknown")})); auto radeonVRamDataSource = std::make_unique( units::make_unit(8), true); auto amdgpuVRamDataSource = std::make_unique( units::make_unit(16), true); ::GPUInfoVRam ts(std::make_unique( "Linux version 4.19.0_..."), std::move(driverDataSource), std::move(radeonVRamDataSource), std::move(amdgpuVRamDataSource)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); REQUIRE(output.empty()); } } } // namespace Tests::GPUInfoVRam corectrl-v1.4.2/tests/src/test_gpuinfovulkan.cpp000066400000000000000000000032351467225065400221230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/hwidtranslatorstub.h" #include "common/stringdatasourcestub.h" #include "core/info/common/gpuinfovulkan.h" namespace Tests::GPUInfoVulkan { TEST_CASE("GPUInfoVulkan tests", "[Info][GPUInfo][GPUInfoVulkan]") { Vendor vendor(Vendor::AMD); int const gpuIndex = 0; IGPUInfo::Path path("_sys_", "_dev_"); HWIDTranslatorStub hwIDTranslator; SECTION("Provides api version (v1)") { std::string const infoData( // clang-format off "...\n\ VkPhysicalDeviceProperties:\n\ ...\n\ apiVersion = 4194306\n\ ..."); // clang-format on ::GPUInfoVulkan ts( std::make_unique("vulkaninfo", infoData)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto apiVersion = std::make_pair( std::string(::GPUInfoVulkan::Keys::apiVersion), std::string("4194306")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(apiVersion)); } SECTION("Provides api version (v2)") { std::string const infoData( // clang-format off "...\n\ VkPhysicalDeviceProperties:\n\ ...\n\ apiVersion = 0x401046 (1.1.70)\n\ ..."); // clang-format on ::GPUInfoVulkan ts( std::make_unique("vulkaninfo", infoData)); auto output = ts.provideInfo(vendor, gpuIndex, path, hwIDTranslator); auto apiVersion = std::make_pair( std::string(::GPUInfoVulkan::Keys::apiVersion), std::string("1.1.70")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(apiVersion)); } } } // namespace Tests::GPUInfoVulkan corectrl-v1.4.2/tests/src/test_hwidtranslator.cpp000066400000000000000000000031131467225065400222730ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/idatasource.h" #include "core/info/hwidtranslator.h" namespace Tests::HWIDTranslator { class HWIDDataSourceStub : public IDataSource> { std::string source() const override { return ""; } bool read(std::vector &data) override { data.clear(); std::copy(data_.cbegin(), data_.cend(), std::back_inserter(data)); return true; } // In pci.ids format (https://pci-ids.ucw.cz) static constexpr std::string_view data_{ // clang-format off "\ # commentary\n\ # commentary\n\ \ 1002 Vendor Name # (something)\n\ aaaa Device Name # [something]\n\ bbbb cccc Subdevice Name (something) [something] more text #\n\ \n\ C 11 Class Name # (something) [something]\n\ aa Subclass Name # (something) [something]\n\ bb Programming Interface (something) mode text #\n\ " // clang-format on }; }; TEST_CASE("HWIDTranslator tests", "[Info][HWIDTranslator]") { std::vector vendors{Vendor::AMD}; ::HWIDTranslator ts(vendors, std::make_unique()); SECTION("Parses pci-ids formatted data...") { SECTION("Extract vendors") { REQUIRE(ts.vendor("1002") == "Vendor Name #"); } SECTION("Extract devices") { REQUIRE(ts.device("1002", "aaaa") == "Device Name #"); } SECTION("Extract subdevices") { REQUIRE(ts.subdevice("1002", "aaaa", "bbbb", "cccc") == "Subdevice Name"); } } } } // namespace Tests::HWIDTranslator corectrl-v1.4.2/tests/src/test_mathutils.cpp000066400000000000000000000016121467225065400212420ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/mathutils.h" #include namespace Tests::Utils::Math { TEST_CASE("MathUtils tests", "[Utils][Math]") { SECTION("linearNorm") { std::vector values{1, 50, 100}; std::pair oldRange(1, 100); std::pair newRange(1, 50); std::vector normValues{1, 25, 50}; ::Utils::Math::linearNorm(values, oldRange, newRange); REQUIRE(values == normValues); } SECTION("lerpX") { auto p1 = std::make_pair(0, 0); auto p2 = std::make_pair(10, 10); REQUIRE(::Utils::Math::lerpX(5, p1, p2) == 5); } SECTION("lerpY") { auto p1 = std::make_pair(0, 0); auto p2 = std::make_pair(10, 10); REQUIRE(::Utils::Math::lerpY(5, p1, p2) == 5); } } } // namespace Tests::Utils::Math corectrl-v1.4.2/tests/src/test_noop.cpp000066400000000000000000000024301467225065400202020ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include "common/commandqueuestub.h" #include "core/components/controls/noop.h" namespace Tests::Noop { class NoopTestAdapter : public ::Noop { public: using ::Noop::Noop; using ::Noop::cleanControl; using ::Noop::syncControl; }; TEST_CASE("Noop control tests", "[Noop]") { CommandQueueStub ctlCmds; SECTION("Has Noop ID") { NoopTestAdapter ts; REQUIRE(ts.ID() == ::Noop::ItemID); } SECTION("Is active by default") { NoopTestAdapter ts; REQUIRE(ts.active()); } SECTION("Does not generate pre-init control commands") { NoopTestAdapter ts; ts.preInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate post-init control commands") { NoopTestAdapter ts; ts.postInit(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate clean control commands") { NoopTestAdapter ts; ts.cleanControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } SECTION("Does not generate sync control commands") { NoopTestAdapter ts; ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } } } // namespace Tests::Noop corectrl-v1.4.2/tests/src/test_pmoverdrive.cpp000066400000000000000000000214121467225065400215720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/commandqueuestub.h" #include "common/controlmock.h" #include "common/stringdatasourcestub.h" #include "common/vectorstringdatasourcestub.h" #include "core/components/controls/amd/pm/advanced/overdrive/pmoverdrive.h" namespace Tests::AMD::PMOverdrive { class PMOverdriveTestAdapter : public ::AMD::PMOverdrive { public: using ::AMD::PMOverdrive::PMOverdrive; using ::AMD::PMOverdrive::cleanControl; using ::AMD::PMOverdrive::perfLevelPreInitValue; using ::AMD::PMOverdrive::syncControl; }; TEST_CASE("AMD PMOverdrive tests", "[GPU][AMD][PM][PMOverdrive]") { std::vector> controlMocks; SECTION("Has PMOverdrive ID") { ::AMD::PMOverdrive ts(std::make_unique(), std::make_unique(), std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::PMOverdrive::ItemID); } SECTION("Is not active by default") { ::AMD::PMOverdrive ts(std::make_unique(), std::make_unique(), std::move(controlMocks)); REQUIRE_FALSE(ts.active()); } SECTION("Pre-init its controls, generating pre-init overdrive commands...") { std::vector ppOdClkVoltageData{"..."}; controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, preInit(trompeloeil::_)); SECTION("Including performance level command when its value is not manual") { PMOverdriveTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.preInit(ctlCmds); auto perfLevelEntry = ts.perfLevelPreInitValue(); REQUIRE(perfLevelEntry == "auto"); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 3); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "r"); auto &[cmd2Path, cmd2Value] = commands.at(2); REQUIRE(cmd2Path == "pp_od_clk_voltage"); REQUIRE(cmd2Value == "c"); } SECTION("Excluding performance level command when its value is manual") { PMOverdriveTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.preInit(ctlCmds); auto perfLevelEntry = ts.perfLevelPreInitValue(); REQUIRE(perfLevelEntry == "manual"); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "r"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "c"); } } SECTION("Post-init its controls and generate post-init overdrive commands") { std::vector ppOdClkVoltageData{"..."}; controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); ALLOW_CALL(*controlMock, preInit(trompeloeil::_)); REQUIRE_CALL(*controlMock, postInit(trompeloeil::_)); PMOverdriveTestAdapter ts(std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique( "pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.preInit(ctlCmds); ctlCmds.clear(); ts.postInit(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "c"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "power_dpm_force_performance_level"); REQUIRE(cmd1Value == "auto"); } SECTION("Generate overdrive clean controls commands...") { std::vector ppOdClkVoltageData{"..."}; controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, clean(trompeloeil::_)); SECTION("Including performance level command when its value is not manual") { PMOverdriveTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 3); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "r"); auto &[cmd2Path, cmd2Value] = commands.at(2); REQUIRE(cmd2Path == "pp_od_clk_voltage"); REQUIRE(cmd2Value == "c"); } SECTION("Excluding performance level command when its value is manual") { PMOverdriveTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.cleanControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 2); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "pp_od_clk_voltage"); REQUIRE(cmd0Value == "r"); auto &[cmd1Path, cmd1Value] = commands.at(1); REQUIRE(cmd1Path == "pp_od_clk_voltage"); REQUIRE(cmd1Value == "c"); } } SECTION("Sync its controls, generating sync control commands when is out of " "sync...") { std::vector ppOdClkVoltageData{"..."}; SECTION("Including performance level command when its value is not manual") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, sync(trompeloeil::_)); PMOverdriveTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "auto"), std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.syncControl(ctlCmds); auto &commands = ctlCmds.commands(); REQUIRE(commands.size() == 1); auto &[cmd0Path, cmd0Value] = commands.at(0); REQUIRE(cmd0Path == "power_dpm_force_performance_level"); REQUIRE(cmd0Value == "manual"); } SECTION("Excluding performance level command when its value is manual") { controlMocks.emplace_back(std::make_unique()); ControlMock *controlMock = static_cast(controlMocks[0].get()); REQUIRE_CALL(*controlMock, sync(trompeloeil::_)); PMOverdriveTestAdapter ts( std::make_unique( "power_dpm_force_performance_level", "manual"), std::make_unique("pp_od_clk_voltage", ppOdClkVoltageData), std::move(controlMocks)); CommandQueueStub ctlCmds; ts.syncControl(ctlCmds); REQUIRE(ctlCmds.commands().empty()); } } } } // namespace Tests::AMD::PMOverdrive corectrl-v1.4.2/tests/src/test_pmpowerstatemode.cpp000066400000000000000000000013161467225065400226300ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2021 Juan Palacios #include #include "core/components/controls/amd/pm/powerstate/pmpowerstatemode.h" namespace Tests::AMD::PMPowerStateMode { TEST_CASE("AMD PMPowerStateMode tests", "[GPU][AMD][PM][PMPowerStateMode]") { std::vector> controlMocks; SECTION("Has PMPowerStateMode ID") { ::AMD::PMPowerStateMode ts(std::move(controlMocks)); REQUIRE(ts.ID() == ::AMD::PMPowerStateMode::ItemID); } SECTION("Is active by default") { ::AMD::PMPowerStateMode ts(std::move(controlMocks)); REQUIRE(ts.active()); } } } // namespace Tests::AMD::PMPowerStateMode corectrl-v1.4.2/tests/src/test_sensor.cpp000066400000000000000000000052251467225065400205450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "core/components/sensors/sensor.h" extern template struct trompeloeil::reporter; namespace Tests::Sensor { class SensorTestAdapter : public ::Sensor { public: using ::Sensor::Sensor; using ::Sensor::value; }; class SensorDataSourceStub : public IDataSource { public: SensorDataSourceStub(unsigned int data) : data_(data) { } std::string source() const override { return ""; } bool read(unsigned int &data) override { data = data_; return true; } unsigned int const data_; }; class SensorExporterMock : public ::Sensor::Exporter { public: MAKE_MOCK1(takeValue, void(units::frequency::megahertz_t)); MAKE_MOCK1(takeRange, void(std::optional> const &)); MAKE_MOCK1( provideExporter, std::optional>(Item const &)); }; TEST_CASE("Sensor tests", "[GPU][Sensor]") { std::vector>> dataSources; dataSources.emplace_back(std::make_unique(1)); dataSources.emplace_back(std::make_unique(2)); SensorTestAdapter ts("_test_sensor_", std::move(dataSources), std::make_pair(units::frequency::megahertz_t(100), units::frequency::megahertz_t(20000)), [](std::vector const &input) { return input[0] + input[1]; }); auto testValue = units::frequency::megahertz_t(3); std::pair range( 100, 20000); SECTION("Has 0 as initial value") { REQUIRE(ts.value() == units::frequency::megahertz_t(0)); SECTION("Update its value from DataSource") { ts.update(); REQUIRE(ts.value() == testValue); SECTION("Exports its value") { SensorExporterMock e; ALLOW_CALL(e, provideExporter(trompeloeil::_)).LR_RETURN(e); REQUIRE_CALL(e, takeValue(trompeloeil::eq(testValue))); REQUIRE_CALL(e, takeRange(trompeloeil::_)).LR_WITH(_1.value() == range); ts.exportWith(e); } } } } } // namespace Tests::Sensor corectrl-v1.4.2/tests/src/test_stringutils.cpp000066400000000000000000000102241467225065400216160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/stringutils.h" extern template struct trompeloeil::reporter; namespace Tests::Utils::String { TEST_CASE("StringUtils tests", "[Utils][String]") { SECTION("cleanPrefix") { SECTION("Returns a string without the prefix when the input string " "contains the prefix") { std::string prefix("prefix "); std::string data("prefix text"); auto res = ::Utils::String::cleanPrefix(data, prefix); REQUIRE(res == "text"); } SECTION("Returns the input string when the prefix is not a substring of " "the input string") { std::string prefix("prefix"); std::string data("some data"); auto res = ::Utils::String::cleanPrefix(data, prefix); REQUIRE(res == "some data"); } SECTION("Returns an empty string when the input string equals the prefix") { std::string prefix("prefix"); std::string data("prefix"); auto res = ::Utils::String::cleanPrefix(data, prefix); REQUIRE(res == ""); } SECTION("Returns the input string when it is shorter than the prefix") { std::string prefix("prefix"); std::string data("pref"); auto res = ::Utils::String::cleanPrefix(data, prefix); REQUIRE(res == "pref"); } SECTION("Returns the input string when the prefix is empty") { std::string prefix(""); std::string data("data"); auto res = ::Utils::String::cleanPrefix(data, prefix); REQUIRE(res == "data"); } } SECTION("parseVersion") { SECTION("Returns version when the input string is in 'mayor.minor.patch' " "format") { auto version = ::Utils::String::parseVersion("1.2.3"); REQUIRE(version == std::make_tuple(1, 2, 3)); } SECTION("Returns 0.0.0 version when the input string is not in " "'mayor.minor.patch' format") { auto version = ::Utils::String::parseVersion("not a version"); REQUIRE(version == std::make_tuple(0, 0, 0)); } } SECTION("split") { SECTION("Doesn't include the delimiter character in the results") { auto result = ::Utils::String::split(" ", ' '); REQUIRE(result.empty()); } SECTION("Returns the original string when it doesn't contains the " "delimiter character") { auto result = ::Utils::String::split("one", ' '); REQUIRE(result.size() == 1); REQUIRE(result[0] == "one"); } SECTION("Split a string into substrings") { auto result = ::Utils::String::split("one two three ", ' '); REQUIRE(result.size() == 3); REQUIRE(result[0] == "one"); REQUIRE(result[1] == "two"); REQUIRE(result[2] == "three"); } } SECTION("parseKernelProcVersion") { SECTION("Provides kernel version when data is using...") { SECTION("Semver format") { std::string const data("Linux version 1.2.3_other_info ..."); auto output = ::Utils::String::parseKernelProcVersion(data); REQUIRE(output.has_value()); REQUIRE(*output == "1.2.3"); } SECTION("Invalid semver format...") { SECTION("Missing patch version (see #254)") { std::string const data("Linux version 1.2_other_info ..."); auto output = ::Utils::String::parseKernelProcVersion(data); REQUIRE(output.has_value()); REQUIRE(*output == "1.2.0"); } SECTION("With additional version numbers after patch version") { std::string const data("Linux version 1.2.3.4_other_info ..."); auto output = ::Utils::String::parseKernelProcVersion(data); REQUIRE(output.has_value()); REQUIRE(*output == "1.2.3"); } } } SECTION("Returns no value when the string follow an unknown format") { std::string const data("Other format"); auto output = ::Utils::String::parseKernelProcVersion(data); REQUIRE_FALSE(output.has_value()); } } } } // namespace Tests::Utils::String corectrl-v1.4.2/tests/src/test_swinfo.cpp000066400000000000000000000016751467225065400205460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "core/info/swinfo.h" namespace Tests::SWInfo { class ProviderStub : public ISWInfo::IProvider { public: std::vector> provideInfo() const override { std::vector> info; info.emplace_back("info_key", "info"); return info; } }; TEST_CASE("SWInfo tests", "[Info][SWInfo]") { ::SWInfo ts; SECTION("Software info is collected on initialization") { REQUIRE(ts.keys().empty()); std::vector> providers; providers.emplace_back(std::make_unique()); ts.initialize(providers); auto keys = ts.keys(); REQUIRE(keys.size() == 1); REQUIRE(keys.front() == "info_key"); REQUIRE(ts.info("info_key") == "info"); } } } // namespace Tests::SWInfo corectrl-v1.4.2/tests/src/test_swinfokernel.cpp000066400000000000000000000033341467225065400217410ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/stringdatasourcestub.h" #include "core/info/common/swinfokernel.h" namespace Tests::SWInfoKernel { TEST_CASE("SWInfoKernel tests", "[Info][SWInfo][SWInfoKernel]") { SECTION("Provides kernel version when /proc/version has a known format") { std::string const infoData("Linux version 1.2.3_other_info ..."); ::SWInfoKernel ts( std::make_unique("/proc/version", infoData)); auto output = ts.provideInfo(); auto kernelVersion = std::make_pair( std::string(ISWInfo::Keys::kernelVersion), std::string("1.2.3")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(kernelVersion)); } SECTION("Provides fake kernel version (0.0.0) when...") { SECTION("Cannot read /proc/version") { ::SWInfoKernel ts( std::make_unique("/proc/version", "", false)); auto output = ts.provideInfo(); auto kernelVersion = std::make_pair( std::string(ISWInfo::Keys::kernelVersion), std::string("0.0.0")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(kernelVersion)); } SECTION("/proc/version data has an unknown format") { std::string const infoData("Other format ..."); ::SWInfoKernel ts( std::make_unique("/proc/version", infoData)); auto output = ts.provideInfo(); auto kernelVersion = std::make_pair( std::string(ISWInfo::Keys::kernelVersion), std::string("0.0.0")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(kernelVersion)); } } } } // namespace Tests::SWInfoKernel corectrl-v1.4.2/tests/src/test_swinfomesa.cpp000066400000000000000000000015731467225065400214110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include "common/stringdatasourcestub.h" #include "core/info/common/swinfomesa.h" namespace Tests::SWInfoMesa { TEST_CASE("SWInfoMesa tests", "[Info][SWInfo][SWInfoMesa]") { std::string const infoData( // clang-format off "...\n\ Extended renderer info (GLX_MESA_query_renderer):\n\ ...\n\ Version: 1.2.3\n\ ..."); // clang-format on ::SWInfoMesa ts(std::make_unique("glxinfo", infoData)); auto output = ts.provideInfo(); SECTION("Provides mesa version") { auto mesaVersion = std::make_pair(std::string(ISWInfo::Keys::mesaVersion), std::string("1.2.3")); REQUIRE_THAT(output, Catch::Matchers::VectorContains(mesaVersion)); } } } // namespace Tests::SWInfoMesa corectrl-v1.4.2/tests/src/test_sysmodel.cpp000066400000000000000000000104651467225065400210750ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Copyright 2019 Juan Palacios #include #include #include "common/commandqueuestub.h" #include "core/info/iswinfo.h" #include "core/isyscomponent.h" #include "core/sysmodel.h" extern template struct trompeloeil::reporter; namespace Tests::SysModel { class SWInfoStub : public ISWInfo { public: std::string info(std::string_view) const override { return "sw_info"; } std::vector keys() const override { return {"sw_info_key"}; } void initialize(std::vector> const &) override { } }; class SysComponentMock : public ISysComponent { public: MAKE_MOCK0(init, void(), override); MAKE_MOCK1(preInit, void(ICommandQueue &), override); MAKE_MOCK1(postInit, void(ICommandQueue &), override); MAKE_CONST_MOCK0(active, bool(), override); MAKE_MOCK1(activate, void(bool), override); MAKE_CONST_MOCK0(key, std::string const &(), override); // trompeloeil fails to mock this method std::pair>> componentInfo() const override { std::vector> cInfo; cInfo.emplace_back("c_info_key", "c_info"); return {"component", std::move(cInfo)}; } MAKE_MOCK1(sync, void(ICommandQueue &), override); MAKE_MOCK1(updateSensors, void(std::unordered_map> const &), override); MAKE_CONST_MOCK0(ID, std::string const &(), override); MAKE_MOCK1(importWith, void(Importable::Importer &), override); MAKE_CONST_MOCK1(exportWith, void(Exportable::Exporter &), override); }; class SysModelImporterStub : public ISysModel::Importer { public: std::optional> provideImporter(Item const &) override { return *this; } }; class SysModelExporterStub : public ISysModel::Exporter { public: std::optional> provideExporter(Item const &) override { return *this; } }; TEST_CASE("SysModel tests", "[SysModel]") { CommandQueueStub ctlCmds; auto info = std::make_unique(); std::vector> components; components.emplace_back(std::make_unique()); auto &componentMock = static_cast(*components[0]); ::SysModel ts(std::move(info), std::move(components)); SECTION("Has ISysModel ID") { REQUIRE(ts.ID() == ISysModel::ItemID); } SECTION("Pre-init components") { REQUIRE_CALL(componentMock, preInit(trompeloeil::_)); ts.preInit(ctlCmds); } SECTION("Init components") { REQUIRE_CALL(componentMock, init()); ts.init(); } SECTION("Post-init components") { REQUIRE_CALL(componentMock, postInit(trompeloeil::_)); ts.postInit(ctlCmds); } SECTION("Update component's sensors") { std::unordered_map> ignored; REQUIRE_CALL(componentMock, updateSensors(trompeloeil::_)) .LR_WITH(&_1 == &ignored); ts.updateSensors(ignored); } SECTION("Sync components") { REQUIRE_CALL(componentMock, sync(trompeloeil::_)); ts.sync(ctlCmds); } SECTION("System info can be retrieved") { auto sysInfo = ts.info(); REQUIRE_FALSE(sysInfo.empty()); SECTION("Software info is always present") { std::vector> swInfoData; swInfoData.emplace_back("sw_info_key", "sw_info"); auto swInfo = std::make_pair(std::string("Software"), std::move(swInfoData)); REQUIRE_THAT(sysInfo, Catch::Matchers::VectorContains(swInfo)); } SECTION("Has components info") { auto compInfo = componentMock.componentInfo(); REQUIRE_THAT(sysInfo, Catch::Matchers::VectorContains(compInfo)); } } SECTION("Imports its components") { REQUIRE_CALL(componentMock, importWith(trompeloeil::_)); SysModelImporterStub i; ts.importWith(i); } SECTION("Exports its components") { REQUIRE_CALL(componentMock, exportWith(trompeloeil::_)); SysModelExporterStub e; ts.exportWith(e); } } } // namespace Tests::SysModel