diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8519726 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +* text=auto +*.c text +*.h text +*.cpp text +*.hpp text +*.cc text +*.txt text +*.sln text eol=crlf +*.csproj text eol=crlf +*.csproj.user text eol=crlf +*.editorconfig text eol=crlf +app.config text eol=crlf +packages.config text eol=crlf +*.cs text \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8001cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +/out/ +/build/ +/cmake-build-debug/ +/cmake-build-release/ +/install/ + + + + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.idea/vcs.xml +.idea/modules.xml +.idea/misc.xml +.idea/*.iml +.idea/.name + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..86125c9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "rainmeter-plugin-sdk"] + path = rainmeter-plugin-sdk + url = https://github.com/rainmeter/rainmeter-plugin-sdk + branch = master diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/cmake.xml b/.idea/cmake.xml new file mode 100644 index 0000000..d5f97c9 --- /dev/null +++ b/.idea/cmake.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/Emerson_Pinter.xml b/.idea/copyright/Emerson_Pinter.xml new file mode 100644 index 0000000..b97087e --- /dev/null +++ b/.idea/copyright/Emerson_Pinter.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..672e8fd --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..95a53b2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.21) + +set(PROJECT_NAME "rainmeter_lhws") +set(PROJECT_VERSION 0.2.0) +set(PROJECT_DESCRIPTION "LibreHardwareService plugin for Rainmeter") +set(PROJECT_HOMEPAGE_URL "https://github.com/epinter/rainmeter-lhws") +enable_language(CXX) +set(CMAKE_CXX_STANDARD 17) + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +project (${PROJECT_NAME} VERSION ${PROJECT_VERSION}) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +add_subdirectory(src) + +if (PROJECT_IS_TOP_LEVEL) + message("Configuring CMAKE_INSTALL_PREFIX to ${CMAKE_CURRENT_SOURCE_DIR}/install") + set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/install" CACHE PATH "Installation directory" FORCE) + message("CMAKE_INSTALL_PREFIX = ${CMAKE_CURRENT_SOURCE_DIR}/install") + + include(GNUInstallDirs) + + install(TARGETS ${MAINTARGET} + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endif() \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md new file mode 100644 index 0000000..abad8b6 --- /dev/null +++ b/README.md @@ -0,0 +1,168 @@ +# LibreHardwareService plugin for Rainmeter + +[![Latest Release](https://img.shields.io/github/release/epinter/rainmeter-lhws.svg)](https://github.com/epinter/rainmeter-lhws/releases/latest) +[![Downloads](https://img.shields.io/github/downloads/epinter/rainmeter-lhws/total.svg)](https://github.com/epinter/rainmeter-lhws/releases/latest) +[![Release Date](https://img.shields.io/github/release-date/epinter/rainmeter-lhws.svg)](https://github.com/epinter/rainmeter-lhws/releases/latest) +[![License](https://img.shields.io/github/license/epinter/rainmeter-lhws.svg)](https://github.com/epinter/rainmeter-lhws/blob/main/LICENSE) + +## Introduction + +This plugin collects hardware sensors from [LibreHardwareService](https://github.com/epinter/LibreHardwareService), allowing skins to access all hardware sensors exposed by [LibreHardwareMonitor](https://github.com/LibreHardwareMonitor/LibreHardwareMonitor), SMART status, and RTSS framerate and frametime. + +## Requirements + +[LibreHardwareService](https://github.com/epinter/LibreHardwareService) and [Visual C++ Redistributable 2022](https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist). + +## Usage + +Copy LibreHardwareService.dll to %APPDATA%/Rainmeter/Plugins and setup measures like the examples below. + +## Building + +This library depends on [LibHardwareService](https://github.com/epinter/lhwservice) and Boost. The dependencies are found using CMake find_package, so [vcpkg](https://vcpkg.io) is strongly recommended for Boost. Scripts for building can be found in cmake directory. +Visual Studio 2022 and CMake are required. + +## Measure Examples + +Hardware names are the ones returned by LibreHardwareMonitor or ShowSensors.exe from LibreHardwareService. + +Motherboard: +``` +[MBTemp] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#mbSubhardwareName# +SensorName=Temperature #2 +SensorType=Temperature +``` + +CPU usage: +``` +[CPUTotalLoad] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#cpuHardwareName# +SensorName=CPU Total +SensorType=Load +MinValue=0 +MaxValue=100 +``` + +RTSS fps: +``` +[Fps] +Measure=Plugin +Plugin=LibreHardwareService +SensorName=RTSS +SensorType=Framerate +``` + +RTSS Frametime (milliseconds): +``` +[Frametime] +Measure=Plugin +Plugin=LibreHardwareService +SensorName=RTSS +SensorType=frametime +``` + +Storage activity: +``` +[Drive1Load] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#drive1HwName# +SensorName=Total Activity +SensorType=Load +``` + +Storage Temperature: +``` +[Drive1Temp] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#drive1HwName# +SensorName=Temperature +SensorType=Temperature +``` +Storage Temperature: +``` +[Drive2Temp] +Measure=Plugin +Plugin=LibreHardwareService +SensorIdentifier=/hdd/1/temperature/0 +``` + +SMART SATA status, returns one of the following strings: +- "Pre-fail" if the smart Prefail bit is set; +- "End-of-Life" if the smart Advisory bit is set; +- "Warning" if smart attributes 0x05, 0xC5, or 0xC6 have raw values above 10 +- "OK" if none of above is detected +``` +[SmartDrive1] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#drive1HwName# +HardwareType=Storage +HwStatusType=storage_smart_ata +HwStatusItem=Status +``` + +SMART NVME: +``` +[SmartDrive2availableSpare] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#drive2HwName# +HardwareType=Storage +HwStatusType=storage_smart_nvme +HwStatusItem=availableSpare +``` + +SMART NVME: +``` +[SmartDrive2criticalWarning] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#drive2HwName# +HardwareType=Storage +HwStatusType=storage_smart_nvme +HwStatusItem=criticalWarning +``` + +SMART NVME: +``` +[SmartDrive2percentageUsed] +Measure=Plugin +Plugin=LibreHardwareService +HardwareName=#drive2HwName# +HardwareType=Storage +HwStatusType=storage_smart_nvme +HwStatusItem=percentageUsed +``` + +NVME attributes available: +``` +availableSpare +availableSpareThreshold +controllerBusyTime +criticalCompositeTemperatureTime +criticalWarning +dataUnitRead +dataUnitWritten +errorInfoLogEntryCount +hostReadCommands +hostWriteCommands +mediaErrors +percentageUsed +powerCycle +powerOnHours +temperature +unsafeShutdowns +warningCompositeTemperatureTime +``` + +## License + +This software is licensed under the terms of [Mozilla Public License Version 2.0](https://www.mozilla.org/en-US/MPL/2.0/). + diff --git a/cmake/build-release-x64.ps1 b/cmake/build-release-x64.ps1 new file mode 100644 index 0000000..abf6df5 --- /dev/null +++ b/cmake/build-release-x64.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = "Stop" + +$projectRoot = Resolve-Path "$PSScriptRoot/.." + + +#if lhwservice is not built and installed at the parent directory of this project, build will fail +$lhwservicePath = Resolve-Path "../../lhwservice/install" + +if(!(Test-Path "$projectRoot/out/release-msvc-x64")) { + mkdir "$projectRoot/out/release-msvc-x64" +} + +$cwd = Get-Location +Set-Location "$projectRoot/out/release-msvc-x64" + +write-host "Starting cmake" +write-host $pwd + +cmake "$projectRoot" -G "Visual Studio 17 2022" -T v143,host=x64 -A x64 -DCMAKE_TOOLCHAIN_FILE="$($Env:VCPKG_ROOT)/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static-md -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH="$lhwservicePath" -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release +cmake --build . --config Release --target package + +Set-Location $cwd diff --git a/cmake/build-release-x86.ps1 b/cmake/build-release-x86.ps1 new file mode 100644 index 0000000..c99e7bd --- /dev/null +++ b/cmake/build-release-x86.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = "Stop" + +$projectRoot = Resolve-Path "$PSScriptRoot/.." + + +#if lhwservice is not built and installed at the parent directory of this project, build will fail +$lhwservicePath = Resolve-Path "../../lhwservice/install" + +if(!(Test-Path "$projectRoot/out/release-msvc-x86")) { + mkdir "$projectRoot/out/release-msvc-x86" +} + +$cwd = Get-Location +Set-Location "$projectRoot/out/release-msvc-x86" + +write-host "Starting cmake" +write-host $pwd + +cmake "$projectRoot" -G "Visual Studio 17 2022" -T v143,host=x86 -A Win32 -DCMAKE_TOOLCHAIN_FILE="$($Env:VCPKG_ROOT)/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x86-windows-static-md -DBUILD_SHARED_LIBS=ON -DCMAKE_PREFIX_PATH="$lhwservicePath" -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release +cmake --build . --config Release --target package + +Set-Location $cwd diff --git a/external/include/README.md b/external/include/README.md new file mode 100644 index 0000000..8bd96dc --- /dev/null +++ b/external/include/README.md @@ -0,0 +1 @@ +The RTSS headers are licensed and copyrighted by their respective owners. Information can be found at https://www.guru3d.com/files-details/rtss-rivatuner-statistics-server-download.html. diff --git a/external/include/RTSSHooksTypes.h b/external/include/RTSSHooksTypes.h new file mode 100644 index 0000000..b08d16b --- /dev/null +++ b/external/include/RTSSHooksTypes.h @@ -0,0 +1,23 @@ +#ifndef _RTSSHOOKSTYPES_H_INCLUDED_ +#define _RTSSHOOKSTYPES_H_INCLUDED_ +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +typedef struct VIDEO_CAPTURE_PARAM +{ + DWORD dwVersion; + char szFilename[MAX_PATH]; + DWORD dwFramerate; + DWORD dwFramesize; + DWORD dwFormat; + DWORD dwQuality; + DWORD dwThreads; + BOOL bCaptureOSD; + DWORD dwAudioCaptureFlags; + DWORD dwVideoCaptureFlagsEx; + DWORD dwAudioCaptureFlags2; + DWORD dwPrerecordSizeLimit; + DWORD dwPrerecordTimeLimit; +} VIDEO_CAPTURE_PARAM, *LPVIDEO_CAPTURE_PARAM; +////////////////////////////////////////////////////////////////////// +#endif +////////////////////////////////////////////////////////////////////// diff --git a/external/include/RTSSSharedMemory.h b/external/include/RTSSSharedMemory.h new file mode 100644 index 0000000..89729c4 --- /dev/null +++ b/external/include/RTSSSharedMemory.h @@ -0,0 +1,645 @@ +///////////////////////////////////////////////////////////////////////////// +// +// This header file defines statistics server's shared memory format +// +///////////////////////////////////////////////////////////////////////////// +#ifndef _RTSS_SHARED_MEMORY_INCLUDED_ +#define _RTSS_SHARED_MEMORY_INCLUDED_ +///////////////////////////////////////////////////////////////////////////// +#include "RTSSHooksTypes.h" +///////////////////////////////////////////////////////////////////////////// +// v1.0 memory structure +typedef struct RTSS_SHARED_MEMORY_V_1_0 +{ + DWORD dwSignature; + //signature allows applications to verify status of shared memory + + //The signature can be set to: + //'RTSS' - statistics server's memory is initialized and contains + // valid data + //0xDEAD - statistics server's memory is marked for deallocation and + // no longer contain valid data + //otherwise the memory is not initialized + DWORD dwVersion; + //structure version ((major<<16) + minor) + //must be set to 0x00010000 for v1.0 structure + DWORD dwTime0; + //start time of framerate measurement period (in milliseconds) + + //Take a note that this field must contain non-zero value to calculate + //framerate properly! + DWORD dwTime1; + //end time of framerate measurement period (in milliseconds) + DWORD dwFrames; + //amount of frames rendered during (dwTime1 - dwTime0) period + + //to calculate framerate use the following formula: + //1000.0f * dwFrames / (dwTime1 - dwTime0) + +} RTSS_SHARED_MEMORY_V_1_0, *LPRTSS_SHARED_MEMORY_V_1_0; +///////////////////////////////////////////////////////////////////////////// +#define OSDFLAG_UPDATED 0x00000001 + //use this flag to force the server to update OSD +///////////////////////////////////////////////////////////////////////////// +// v1.1 memory structure +typedef struct RTSS_SHARED_MEMORY_V_1_1 +{ + DWORD dwSignature; + //signature allows applications to verify status of shared memory + + //The signature can be set to: + //'RTSS' - statistics server's memory is initialized and contains + // valid data + //0xDEAD - statistics server's memory is marked for deallocation and + // no longer contain valid data + //otherwise the memory is not initialized + DWORD dwVersion; + //structure version ((major<<16) + minor) + //must be set to 0x00010001 for v1.1 structure + DWORD dwTime0; + //start time of framerate measurement period (in milliseconds) + + //Take a note that this field must contain non-zero value to calculate + //framerate properly! + DWORD dwTime1; + //end time of framerate measurement period (in milliseconds) + DWORD dwFrames; + //amount of frames rendered during (dwTime1 - dwTime0) period + + //to calculate framerate use the following formula: + //1000.0f * dwFrames / (dwTime1 - dwTime0) + + DWORD dwOSDFlags; + //bitmask, containing combination of OSDFLAG_... flags + + //Note: set OSDFLAG_UPDATED flag as soon as you change any OSD related + //field + DWORD dwOSDX; + //OSD X-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the right side of the screen) + DWORD dwOSDY; + //OSD Y-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the bottom side of the screen) + DWORD dwOSDPixel; + //OSD pixel zooming ratio + DWORD dwOSDColor; + //OSD color in RGB format + char szOSD[256]; + //OSD text + char szOSDOwner[32]; + //OSD owner ID + + //Use this field to capture OSD and prevent other applications from + //using OSD when it is already in use by your application. + //You should change this field only if it is empty (i.e. when OSD is + //not owned by any application) or if it is set to your own application's + //ID (i.e. when you own OSD) + //You shouldn't change any OSD related feilds until you own OSD + +} RTSS_SHARED_MEMORY_V_1_1, *LPRTSS_SHARED_MEMORY_V_1_1; +///////////////////////////////////////////////////////////////////////////// +// v1.2 memory structure +typedef struct RTSS_SHARED_MEMORY_V_1_2 +{ + DWORD dwSignature; + //signature allows applications to verify status of shared memory + + //The signature can be set to: + //'RTSS' - statistics server's memory is initialized and contains + // valid data + //0xDEAD - statistics server's memory is marked for deallocation and + // no longer contain valid data + //otherwise the memory is not initialized + DWORD dwVersion; + //structure version ((major<<16) + minor) + //must be set to 0x00010002 for v1.2 structure + DWORD dwTime0; + //start time of framerate measurement period (in milliseconds) + + //Take a note that this field must contain non-zero value to calculate + //framerate properly! + DWORD dwTime1; + //end time of framerate measurement period (in milliseconds) + DWORD dwFrames; + //amount of frames rendered during (dwTime1 - dwTime0) period + + //to calculate framerate use the following formula: + //1000.0f * dwFrames / (dwTime1 - dwTime0) + + DWORD dwOSDFlags; + //bitmask, containing combination of OSDFLAG_... flags + + //Note: set OSDFLAG_UPDATED flag as soon as you change any OSD related + //field + DWORD dwOSDX; + //OSD X-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the right side of the screen) + DWORD dwOSDY; + //OSD Y-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the bottom side of the screen) + DWORD dwOSDPixel; + //OSD pixel zooming ratio + DWORD dwOSDColor; + //OSD color in RGB format + char szOSD[256]; + //primary OSD slot text + char szOSDOwner[32]; + //primary OSD slot owner ID + + //Use this field to capture OSD slot and prevent other applications from + //using OSD when it is already in use by your application. + //You should change this field only if it is empty (i.e. when OSD slot is + //not owned by any application) or if it is set to your own application's + //ID (i.e. when you own OSD slot) + //You shouldn't change any OSD related feilds until you own OSD slot + + char szOSD1[256]; + //OSD slot 1 text + char szOSD1Owner[32]; + //OSD slot 1 owner ID + char szOSD2[256]; + //OSD slot 2 text + char szOSD2Owner[32]; + //OSD slot 2 owner ID + char szOSD3[256]; + //OSD slot 3 text + char szOSD3Owner[32]; + //OSD slot 3 owner ID +} RTSS_SHARED_MEMORY_V_1_2, *LPRTSS_SHARED_MEMORY_V_1_2; +///////////////////////////////////////////////////////////////////////////// +#define STATFLAG_RECORD 0x00000001 +///////////////////////////////////////////////////////////////////////////// +// v1.3 memory structure +typedef struct RTSS_SHARED_MEMORY_V_1_3 +{ + DWORD dwSignature; + //signature allows applications to verify status of shared memory + + //The signature can be set to: + //'RTSS' - statistics server's memory is initialized and contains + // valid data + //0xDEAD - statistics server's memory is marked for deallocation and + // no longer contain valid data + //otherwise the memory is not initialized + DWORD dwVersion; + //structure version ((major<<16) + minor) + //must be set to 0x00010003 for v1.3 structure + DWORD dwTime0; + //start time of framerate measurement period (in milliseconds) + + //Take a note that this field must contain non-zero value to calculate + //framerate properly! + DWORD dwTime1; + //end time of framerate measurement period (in milliseconds) + DWORD dwFrames; + //amount of frames rendered during (dwTime1 - dwTime0) period + + //to calculate framerate use the following formula: + //1000.0f * dwFrames / (dwTime1 - dwTime0) + + DWORD dwOSDFlags; + //bitmask, containing combination of OSDFLAG_... flags + + //Note: set OSDFLAG_UPDATED flag as soon as you change any OSD related + //field + DWORD dwOSDX; + //OSD X-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the right side of the screen) + DWORD dwOSDY; + //OSD Y-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the bottom side of the screen) + DWORD dwOSDPixel; + //OSD pixel zooming ratio + DWORD dwOSDColor; + //OSD color in RGB format + char szOSD[256]; + //primary OSD slot text + char szOSDOwner[32]; + //primary OSD slot owner ID + + //Use this field to capture OSD slot and prevent other applications from + //using OSD when it is already in use by your application. + //You should change this field only if it is empty (i.e. when OSD slot is + //not owned by any application) or if it is set to your own application's + //ID (i.e. when you own OSD slot) + //You shouldn't change any OSD related feilds until you own OSD slot + + char szOSD1[256]; + //OSD slot 1 text + char szOSD1Owner[32]; + //OSD slot 1 owner ID + char szOSD2[256]; + //OSD slot 2 text + char szOSD2Owner[32]; + //OSD slot 2 owner ID + char szOSD3[256]; + //OSD slot 3 text + char szOSD3Owner[32]; + //OSD slot 3 owner ID + + DWORD dwStatFlags; + //bitmask containing combination of STATFLAG_... flags + DWORD dwStatTime0; + //statistics record period start time + DWORD dwStatTime1; + //statistics record period end time + DWORD dwStatFrames; + //total amount of frames rendered during statistics record period + DWORD dwStatCount; + //amount of min/avg/max measurements during statistics record period + DWORD dwStatFramerateMin; + //minimum instantaneous framerate measured during statistics record period + DWORD dwStatFramerateAvg; + //average instantaneous framerate measured during statistics record period + DWORD dwStatFramerateMax; + //maximum instantaneous framerate measured during statistics record period +} RTSS_SHARED_MEMORY_V_1_3, *LPRTSS_SHARED_MEMORY_V_1_3; +///////////////////////////////////////////////////////////////////////////// + +// WARNING! The following API usage flags are deprecated and valid in 2.9 +// and older shared memory layout only + +#define APPFLAG_DEPRECATED_DD 0x00000010 +#define APPFLAG_DEPRECATED_D3D8 0x00000100 +#define APPFLAG_DEPRECATED_D3D9 0x00001000 +#define APPFLAG_DEPRECATED_D3D9EX 0x00002000 +#define APPFLAG_DEPRECATED_OGL 0x00010000 +#define APPFLAG_DEPRECATED_D3D10 0x00100000 +#define APPFLAG_DEPRECATED_D3D11 0x01000000 + +#define APPFLAG_DEPRECATED_API_USAGE_MASK (APPFLAG_DD | APPFLAG_D3D8 | APPFLAG_D3D9 | APPFLAG_D3D9EX | APPFLAG_OGL | APPFLAG_D3D10 | APPFLAG_D3D11) + +// The following API usage flags are valid in 2.10 and newer shared memory +// layout only + +#define APPFLAG_OGL 0x00000001 +#define APPFLAG_DD 0x00000002 +#define APPFLAG_D3D8 0x00000003 +#define APPFLAG_D3D9 0x00000004 +#define APPFLAG_D3D9EX 0x00000005 +#define APPFLAG_D3D10 0x00000006 +#define APPFLAG_D3D11 0x00000007 +#define APPFLAG_D3D12 0x00000008 +#define APPFLAG_D3D12AFR 0x00000009 +#define APPFLAG_VULKAN 0x0000000A + +#define APPFLAG_API_USAGE_MASK 0x0000FFFF + +#define APPFLAG_ARCHITECTURE_X64 0x00010000 +#define APPFLAG_ARCHITECTURE_UWP 0x00020000 + +#define APPFLAG_PROFILE_UPDATE_REQUESTED 0x10000000 +///////////////////////////////////////////////////////////////////////////// +#define SCREENCAPTUREFLAG_REQUEST_CAPTURE 0x00000001 +#define SCREENCAPTUREFLAG_REQUEST_CAPTURE_OSD 0x00000010 +///////////////////////////////////////////////////////////////////////////// +#define VIDEOCAPTUREFLAG_REQUEST_CAPTURE_START 0x00000001 +#define VIDEOCAPTUREFLAG_REQUEST_CAPTURE_PROGRESS 0x00000002 +#define VIDEOCAPTUREFLAG_REQUEST_CAPTURE_STOP 0x00000004 +#define VIDEOCAPTUREFLAG_REQUEST_CAPTURE_MASK 0x00000007 +#define VIDEOCAPTUREFLAG_REQUEST_CAPTURE_OSD 0x00000010 + +#define VIDEOCAPTUREFLAG_INTERNAL_RESIZE 0x00010000 +///////////////////////////////////////////////////////////////////////////// +#define PROCESS_PERF_COUNTER_ID_RAM_USAGE 0x00000001 +#define PROCESS_PERF_COUNTER_ID_D3DKMT_VRAM_USAGE_LOCAL 0x00000100 +#define PROCESS_PERF_COUNTER_ID_D3DKMT_VRAM_USAGE_SHARED 0x00000101 +///////////////////////////////////////////////////////////////////////////// + +// v2.0 memory structure +typedef struct RTSS_SHARED_MEMORY +{ + DWORD dwSignature; + //signature allows applications to verify status of shared memory + + //The signature can be set to: + //'RTSS' - statistics server's memory is initialized and contains + // valid data + //0xDEAD - statistics server's memory is marked for deallocation and + // no longer contain valid data + //otherwise the memory is not initialized + DWORD dwVersion; + //structure version ((major<<16) + minor) + //must be set to 0x0002xxxx for v2.x structure + + DWORD dwAppEntrySize; + //size of RTSS_SHARED_MEMORY_OSD_ENTRY for compatibility with future versions + DWORD dwAppArrOffset; + //offset of arrOSD array for compatibility with future versions + DWORD dwAppArrSize; + //size of arrOSD array for compatibility with future versions + + DWORD dwOSDEntrySize; + //size of RTSS_SHARED_MEMORY_APP_ENTRY for compatibility with future versions + DWORD dwOSDArrOffset; + //offset of arrApp array for compatibility with future versions + DWORD dwOSDArrSize; + //size of arrOSD array for compatibility with future versions + + DWORD dwOSDFrame; + //Global OSD frame ID. Increment it to force the server to update OSD for all currently active 3D + //applications. + + //next fields are valid for v2.14 and newer shared memory format only + + LONG dwBusy; + //set bit 0 when you're writing to shared memory and reset it when done + + //WARNING: do not forget to reset it, otherwise you'll completely lock OSD updates for all clients + + + //next fields are valid for v2.15 and newer shared memory format only + + DWORD dwDesktopVideoCaptureFlags; + DWORD dwDesktopVideoCaptureStat[5]; + //shared copy of desktop video capture flags and performance stats for 64-bit applications + + //next fields are valid for v2.16 and newer shared memory format only + + DWORD dwLastForegroundApp; + //last foreground application entry index + DWORD dwLastForegroundAppProcessID; + //last foreground application process ID + + //next fields are valid for v2.18 and newer shared memory format only + + DWORD dwProcessPerfCountersEntrySize; + //size of RTSS_SHARED_MEMORY_PROCESS_PERF_COUNTER_ENTRY for compatibility with future versions + DWORD dwProcessPerfCountersArrOffset; + //offset of arrPerfCounters array for compatibility with future versions (relative to application entry) + + //next fields are valid for v2.19 and newer shared memory format only + + LARGE_INTEGER qwLatencyMarkerSetTimestamp; + LARGE_INTEGER qwLatencyMarkerResetTimestamp; + + //OSD slot descriptor structure + + typedef struct RTSS_SHARED_MEMORY_OSD_ENTRY + { + char szOSD[256]; + //OSD slot text + char szOSDOwner[256]; + //OSD slot owner ID + + //next fields are valid for v2.7 and newer shared memory format only + + char szOSDEx[4096]; + //extended OSD slot text + + //next fields are valid for v2.12 and newer shared memory format only + + BYTE buffer[262144]; + //OSD slot data buffer + + //next fields are valid for v2.20 and newer shared memory format only + + char szOSDEx2[32768]; + //additional 32KB extended OSD slot text + + } RTSS_SHARED_MEMORY_OSD_ENTRY, *LPRTSS_SHARED_MEMORY_OSD_ENTRY; + + //process performance counter structure + + typedef struct RTSS_SHARED_MEMORY_PROCESS_PERF_COUNTER_ENTRY + { + DWORD dwID; + //performance counter ID, PROCESS_PERF_COUNTER_ID_XXX + DWORD dwParam; + //performance counter parameters specific to performance counter ID + //PROCESS_PERF_COUNTER_ID_D3DKMT_VRAM_USAGE_LOCAL : contains GPU location (PCI bus, device and function) + //PROCESS_PERF_COUNTER_ID_D3DKMT_VRAM_USAGE_SHARED : contains GPU location (PCI bus, device and function) + DWORD dwData; + //performance counter data + } RTSS_SHARED_MEMORY_PROCESS_PERF_COUNTER_ENTRY, *LPRTSS_SHARED_MEMORY_PROCESS_PERF_COUNTER_ENTRY; + + //application descriptor structure + + typedef struct RTSS_SHARED_MEMORY_APP_ENTRY + { + //application identification related fields + + DWORD dwProcessID; + //process ID + char szName[MAX_PATH]; + //process executable name + DWORD dwFlags; + //application specific flags + + //instantaneous framerate related fields + + DWORD dwTime0; + //start time of framerate measurement period (in milliseconds) + + //Take a note that this field must contain non-zero value to calculate + //framerate properly! + DWORD dwTime1; + //end time of framerate measurement period (in milliseconds) + DWORD dwFrames; + //amount of frames rendered during (dwTime1 - dwTime0) period + DWORD dwFrameTime; + //frame time (in microseconds) + + + //to calculate framerate use the following formulas: + + //1000.0f * dwFrames / (dwTime1 - dwTime0) for framerate calculated once per second + //or + //1000000.0f / dwFrameTime for framerate calculated once per frame + + //framerate statistics related fields + + DWORD dwStatFlags; + //bitmask containing combination of STATFLAG_... flags + DWORD dwStatTime0; + //statistics record period start time + DWORD dwStatTime1; + //statistics record period end time + DWORD dwStatFrames; + //total amount of frames rendered during statistics record period + DWORD dwStatCount; + //amount of min/avg/max measurements during statistics record period + DWORD dwStatFramerateMin; + //minimum instantaneous framerate measured during statistics record period + DWORD dwStatFramerateAvg; + //average instantaneous framerate measured during statistics record period + DWORD dwStatFramerateMax; + //maximum instantaneous framerate measured during statistics record period + + //OSD related fields + + DWORD dwOSDX; + //OSD X-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the right side of the screen) + DWORD dwOSDY; + //OSD Y-coordinate (coordinate wrapping is allowed, i.e. -5 defines 5 + //pixel offset from the bottom side of the screen) + DWORD dwOSDPixel; + //OSD pixel zooming ratio + DWORD dwOSDColor; + //OSD color in RGB format + DWORD dwOSDFrame; + //application specific OSD frame ID. Don't change it directly! + + DWORD dwScreenCaptureFlags; + char szScreenCapturePath[MAX_PATH]; + + //next fields are valid for v2.1 and newer shared memory format only + + DWORD dwOSDBgndColor; + //OSD background color in RGB format + + //next fields are valid for v2.2 and newer shared memory format only + + DWORD dwVideoCaptureFlags; + char szVideoCapturePath[MAX_PATH]; + DWORD dwVideoFramerate; + DWORD dwVideoFramesize; + DWORD dwVideoFormat; + DWORD dwVideoQuality; + DWORD dwVideoCaptureThreads; + + DWORD dwScreenCaptureQuality; + DWORD dwScreenCaptureThreads; + + //next fields are valid for v2.3 and newer shared memory format only + + DWORD dwAudioCaptureFlags; + + //next fields are valid for v2.4 and newer shared memory format only + + DWORD dwVideoCaptureFlagsEx; + + //next fields are valid for v2.5 and newer shared memory format only + + DWORD dwAudioCaptureFlags2; + + DWORD dwStatFrameTimeMin; + DWORD dwStatFrameTimeAvg; + DWORD dwStatFrameTimeMax; + DWORD dwStatFrameTimeCount; + + DWORD dwStatFrameTimeBuf[1024]; + DWORD dwStatFrameTimeBufPos; + DWORD dwStatFrameTimeBufFramerate; + + //next fields are valid for v2.6 and newer shared memory format only + + LARGE_INTEGER qwAudioCapturePTTEventPush; + LARGE_INTEGER qwAudioCapturePTTEventRelease; + + LARGE_INTEGER qwAudioCapturePTTEventPush2; + LARGE_INTEGER qwAudioCapturePTTEventRelease2; + + //next fields are valid for v2.8 and newer shared memory format only + + DWORD dwPrerecordSizeLimit; + DWORD dwPrerecordTimeLimit; + + //next fields are valid for v2.13 and newer shared memory format only + + LARGE_INTEGER qwStatTotalTime; + DWORD dwStatFrameTimeLowBuf[1024]; + DWORD dwStatFramerate1Dot0PercentLow; + DWORD dwStatFramerate0Dot1PercentLow; + + //next fields are valid for v2.17 and newer shared memory format only + + DWORD dw1Dot0PercentLowBufPos; + DWORD dw0Dot1PercentLowBufPos; + + //next fields are valid for v2.18 and newer shared memory format only + + DWORD dwProcessPerfCountersFlags; + DWORD dwProcessPerfCountersCount; + DWORD dwProcessPerfCountersSamplingPeriod; + DWORD dwProcessPerfCountersSamplingTime; + DWORD dwProcessPerfCountersTimestamp; + + //next fields are valid for v2.19 and newer shared memory format only + + LARGE_INTEGER qwLatencyMarkerPresentTimestamp; + + //next fields are valid for v2.20 and newer shared memory format only + + DWORD dwResolutionX; + DWORD dwResolutionY; + + //WARNING: next fields should never (!!!) be accessed directly, use the offsets to access them in order to provide + //compatibility with future versions + + RTSS_SHARED_MEMORY_PROCESS_PERF_COUNTER_ENTRY arrPerfCounters[256]; + + } RTSS_SHARED_MEMORY_APP_ENTRY, *LPRTSS_SHARED_MEMORY_APP_ENTRY; + + //WARNING: next fields should never (!!!) be accessed directly, use the offsets to access them in order to provide + //compatibility with future versions + + RTSS_SHARED_MEMORY_OSD_ENTRY arrOSD[8]; + //array of OSD slots + RTSS_SHARED_MEMORY_APP_ENTRY arrApp[256]; + //array of application descriptors + + //next fields are valid for v2.9 and newer shared memory format only + + //WARNING: due to design flaw there is no offset available for this field, so it must be calculated manually as + //dwAppArrOffset + dwAppArrSize * dwAppEntrySize + + VIDEO_CAPTURE_PARAM autoVideoCaptureParam; + +} RTSS_SHARED_MEMORY, *LPRTSS_SHARED_MEMORY; +///////////////////////////////////////////////////////////////////////////// +typedef struct RTSS_EMBEDDED_OBJECT +{ + DWORD dwSignature; + //embedded object signature + DWORD dwSize; + //embedded object size in bytes + LONG dwWidth; + //embedded object width in pixels (if positive) or in chars (if negative) + LONG dwHeight; + //embedded object height in pixels (if positive) or in chars (if negative) + LONG dwMargin; + //embedded object margin in pixels +} RTSS_EMBEDDED_OBJECT, *LPRTSS_EMBEDDED_OBJECT; +///////////////////////////////////////////////////////////////////////////// +#define RTSS_EMBEDDED_OBJECT_GRAPH_SIGNATURE 'GR00' +///////////////////////////////////////////////////////////////////////////// +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FILLED 1 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMERATE 2 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMETIME 4 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_BAR 8 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_BGND 16 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_VERTICAL 32 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_MIRRORED 64 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_AUTOSCALE 128 + +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMERATE_MIN 256 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMERATE_AVG 512 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMERATE_MAX 1024 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMERATE_1DOT0_PERCENT_LOW 2048 +#define RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_FRAMERATE_0DOT1_PERCENT_LOW 4096 +///////////////////////////////////////////////////////////////////////////// +#pragma warning (disable : 4200) + +typedef struct RTSS_EMBEDDED_OBJECT_GRAPH +{ + RTSS_EMBEDDED_OBJECT header; + //embedded object header + + DWORD dwFlags; + //bitmask containing RTSS_EMBEDDED_OBJECT_GRAPH_FLAG_XXX flags + FLOAT fltMin; + //graph mininum value + FLOAT fltMax; + //graph maximum value + DWORD dwDataCount; + //count of data samples in fltData array + FLOAT fltData[0]; + //graph data samples array + +} RTSS_EMBEDDED_OBJECT_GRAPH, *LPRTSS_EMBEDDED_OBJECT_GRAPH; + +#pragma warning (default : 4200) +///////////////////////////////////////////////////////////////////////////// +#endif //_RTSS_SHARED_MEMORY_INCLUDED_ \ No newline at end of file diff --git a/rainmeter-plugin-sdk b/rainmeter-plugin-sdk new file mode 160000 index 0000000..a32273c --- /dev/null +++ b/rainmeter-plugin-sdk @@ -0,0 +1 @@ +Subproject commit a32273c2c4092f8d5d8f2ad010623559198bbdc4 diff --git a/src/API.cpp b/src/API.cpp new file mode 100644 index 0000000..fa03809 --- /dev/null +++ b/src/API.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 15/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include "API.h" + +std::wstring Rainmeter::API::readString(const std::wstring &option, const std::wstring &defaultValue, const bool &replaceMeasures) { + return std::wstring{RmReadString(rm, option.c_str(), defaultValue.c_str(), replaceMeasures)}; +} + +double Rainmeter::API::readFormula(const std::wstring &option, const double &defaultValue) { + return RmReadFormula(rm, option.c_str(), defaultValue); +} + +std::wstring Rainmeter::API::replaceVariables(const std::wstring &str) { + return std::wstring{RmReplaceVariables(rm, str.c_str())}; +} + +std::wstring Rainmeter::API::pathToAbsolute(const std::wstring &relativePath) { + return std::wstring{RmPathToAbsolute(rm, relativePath.c_str())}; +} + +LPVOID Rainmeter::API::get(Rainmeter::API::GetType type) const { + return RmGet(rm, type); +} + +std::wstring Rainmeter::API::readPath(const std::wstring &option, const std::wstring &defaultValue) { + std::wstring relativePath = readString(option, defaultValue, true); + return pathToAbsolute(relativePath); +} + +int Rainmeter::API::readInt(const std::wstring &option, const int &defaultValue) { + return static_cast(readFormula(option, defaultValue)); +} + +double Rainmeter::API::readDouble(const std::wstring &option, const double &defaultValue) { + return static_cast(readFormula(option, defaultValue)); +} + +std::wstring Rainmeter::API::readMeasureName() const { + return std::wstring{static_cast(get(GetType::RMG_MEASURENAME))}; +} + +std::wstring Rainmeter::API::getSettingsFile() const { + return std::wstring{static_cast(get(GetType::RMG_SETTINGSFILE))}; +} + +void *Rainmeter::API::getSkin() const { + return static_cast(get(GetType::RMG_SKIN)); +} + +std::wstring Rainmeter::API::getSkinName() const { + return std::wstring{static_cast(get(GetType::RMG_SKINNAME))}; +} + +void *Rainmeter::API::getSkinWindow() const { + return static_cast(get(GetType::RMG_SKINWINDOWHANDLE)); +} + +void Rainmeter::API::log(int level, const std::wstring &message) { + RmLog(rm, level, message.c_str()); +} + +void Rainmeter::API::logError(const std::wstring &message) { + log(LogLevel::LOG_ERROR, message); +} + +void Rainmeter::API::logNotice(const std::wstring &message) { + log(LogLevel::LOG_NOTICE, message); +} + +void Rainmeter::API::logDebug(const std::wstring &message) { + log(LogLevel::LOG_DEBUG, message); +} + +void Rainmeter::API::logWarning(const std::wstring &message) { + log(LogLevel::LOG_WARNING, message); +} diff --git a/src/API.h b/src/API.h new file mode 100644 index 0000000..3e188ec --- /dev/null +++ b/src/API.h @@ -0,0 +1,85 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 15/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +namespace Rainmeter { + class API { + public: + enum LogLevel { + LOG_ERROR = 1, + LOG_WARNING = 2, + LOG_NOTICE = 3, + LOG_DEBUG = 4 + }; + + enum GetType { + RMG_MEASURENAME = 0, + RMG_SKIN = 1, + RMG_SETTINGSFILE = 2, + RMG_SKINNAME = 3, + RMG_SKINWINDOWHANDLE = 4 + }; + + private: + void *rm; + + [[maybe_unused]] [[nodiscard]] void *get(GetType type) const; + + public: + explicit API(void *rainmeter) { + rm = rainmeter; + } + + API(API const &aApi) { + rm = aApi.rm; + } + + [[maybe_unused]] [[nodiscard]] std::wstring + readString(std::wstring const &option, std::wstring const &defaultValue, bool const &replaceMeasures = true); + + [[maybe_unused]] [[nodiscard]] double readFormula(std::wstring const &option, double const &defaultValue); + + [[maybe_unused]] [[nodiscard]] std::wstring replaceVariables(std::wstring const &str); + + [[maybe_unused]] [[nodiscard]] std::wstring pathToAbsolute(std::wstring const &relativePath); + + [[maybe_unused]] [[nodiscard]] std::wstring readPath(std::wstring const &option, std::wstring const &defaultValue); + + [[maybe_unused]] [[nodiscard]] int readInt(std::wstring const &option, int const &defaultValue); + + [[maybe_unused]] [[nodiscard]] double readDouble(std::wstring const &option, double const &defaultValue); + + [[maybe_unused]] [[nodiscard]] std::wstring readMeasureName() const; + + [[maybe_unused]] [[nodiscard]] std::wstring getSettingsFile() const; + + [[maybe_unused]] [[nodiscard]] void *getSkin() const; + + [[maybe_unused]] [[nodiscard]] std::wstring getSkinName() const; + + [[maybe_unused]] [[nodiscard]] void *getSkinWindow() const; + + [[maybe_unused]] void log(int level, std::wstring const &message); + + [[maybe_unused]] void logError(std::wstring const &message); + + [[maybe_unused]] void logNotice(std::wstring const &message); + + [[maybe_unused]] void logDebug(std::wstring const &message); + + [[maybe_unused]] void logWarning(std::wstring const &message); + }; +} diff --git a/src/BackgroundTimer.h b/src/BackgroundTimer.h new file mode 100644 index 0000000..acd3850 --- /dev/null +++ b/src/BackgroundTimer.h @@ -0,0 +1,59 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 30/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace LhwsPlugin { + class BackgroundTimer { + private: + std::chrono::milliseconds time{}; + std::mutex mutex{}; + std::function func; + std::atomic runThread{true}; + std::condition_variable cv{}; + + void timer() { + std::unique_lock lock{mutex}; + while (runThread) { + mutex.unlock(); + func(); + mutex.lock(); + auto now = std::chrono::steady_clock::now(); + cv.wait_until(lock, now + time, [this] { return !runThread.load(); }); + } + } + + std::thread timerThread{[this]() { timer(); }}; + + public: + explicit BackgroundTimer(std::chrono::milliseconds const &time, std::function function) : time(time), + func(std::move( + function)) {} + + ~BackgroundTimer() { + runThread = false; + cv.notify_all(); + timerThread.join(); + } + + void setTime(const std::chrono::milliseconds &aTime) { + BackgroundTimer::time = aTime; + } + }; +} // LhwsPlugin diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..268dac7 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,72 @@ +cmake_minimum_required(VERSION 3.21) +set(CMAKE_CXX_STANDARD 17) + +if (MSVC) + string(TOLOWER ${CMAKE_VS_PLATFORM_NAME} ARCHITECTURE) +else () + string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} ARCHITECTURE) +endif () +if (ARCHITECTURE STREQUAL "amd64" OR ARCHITECTURE STREQUAL "x86_64") + set(ARCHITECTURE "x64") +elseif (ARCHITECTURE STREQUAL "win32") + set(ARCHITECTURE "x86") +endif () +message("architecture: ${ARCHITECTURE}") + +if(ARCHITECTURE STREQUAL x86) + set(RAINMETER_ARCH x32) +else() + set(RAINMETER_ARCH x64) +endif() + +set(MAINTARGET "LibreHardwareService") +set(MAINTARGET "${MAINTARGET}" PARENT_SCOPE) + +message("TARGET=${MAINTARGET}") + +set(SOURCE_FILES Plugin.cpp Measure.cpp API.cpp RtssAppStat.cpp) + + +if (BUILD_SHARED_LIBS) + add_library(${MAINTARGET} SHARED ${SOURCE_FILES}) +else () + add_library(${MAINTARGET} STATIC ${SOURCE_FILES}) +endif () + +target_compile_features(${MAINTARGET} PUBLIC cxx_std_${CMAKE_CXX_STANDARD}) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "MSVC") + message("Compiler is MSVC") + if (BUILD_SHARED_LIBS) + target_compile_options(${MAINTARGET} PRIVATE /W4 /WX /EHs) + else () + target_compile_options(${MAINTARGET} PRIVATE /W4 /WX /EHs "$<$:/MD>" "$<$:/MDd>" + "$<$:/O2>" "$<$:/Od>" /fp:fast) + target_compile_definitions(${MAINTARGET} PRIVATE _Boost_USE_STATIC_LIBS BOOST_ALL_NO_LIB) + set_property(TARGET ${MAINTARGET} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + endif () +else () + message("UNSUPPORTED COMPILER") +endif () + +set(Boost_USE_MULTITHREADED ON) +set(Boost_NO_WARN_NEW_VERSIONS ON) + +find_package(Boost 1.79.0 REQUIRED COMPONENTS locale) +find_package(lhwservice CONFIG REQUIRED) + +target_include_directories(${MAINTARGET} PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/external/include" + "${CMAKE_SOURCE_DIR}/rainmeter-plugin-sdk/API" + lhwservice + ${Boost_INCLUDE_DIR}) + +target_link_libraries(${MAINTARGET} PRIVATE + lhwservice + ${Boost_LIBRARIES} + "${CMAKE_SOURCE_DIR}/rainmeter-plugin-sdk/API/${RAINMETER_ARCH}/Rainmeter.lib") + + +set(CPACK_GENERATOR ZIP) +include(CPack) \ No newline at end of file diff --git a/src/Constants.h b/src/Constants.h new file mode 100644 index 0000000..f4cfc71 --- /dev/null +++ b/src/Constants.h @@ -0,0 +1,34 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 24/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#define ATASMART_PREFAIL L"Pre-fail" +#define ATASMART_WARNING L"Warning" +#define ATASMART_ENDOFLIFE L"End-of-Life" +#define ATASMART_OK L"OK" + +#define OPTION_HWSTATUSTYPE L"HwStatusType" +#define OPTION_HWSTATUSITEM L"HwStatusItem" +#define OPTION_SENSORNAME L"SensorName" +#define OPTION_SENSORTYPE L"SensorType" +#define OPTION_HARDWARENAME L"HardwareName" +#define OPTION_HARDWARETYPE L"HardwareType" +#define OPTION_SENSORID L"SensorIdentifier" +#define OPTION_STALEAFTERSECS L"StaleAfterSecs" + +#define SMART_ITEM_STATUS "Status" +#define SMARTTYPE_ATA L"storage_smart_ata" +#define SMARTTYPE_NVME L"storage_smart_nvme" + +#define WARNING_THRESHOLD_ATASMART 10 +#define VALUE_STALE_SECS 5 +#define MIN_UPDATE_INTERVAL 1000 +#define MAX_UPDATE_INTERVAL 5000 \ No newline at end of file diff --git a/src/Measure.cpp b/src/Measure.cpp new file mode 100644 index 0000000..47fb925 --- /dev/null +++ b/src/Measure.cpp @@ -0,0 +1,293 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 15/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "API.h" +#include "Measure.h" +#include "Constants.h" +#include "RtssAppStat.h" +#include "BackgroundTimer.h" + +namespace LhwsPlugin { + Measure::Measure(Rainmeter::API const &rm) : api(rm) { + } + + void Measure::reload([[maybe_unused]] double maxValue) { + loadOptions(); + } + + double Measure::update() { + calculateUpdateInterval(); + return lastValue; + } + + void Measure::logError(std::wstring const &message) { + api.log(Rainmeter::API::LogLevel::LOG_ERROR, message); + } + + void Measure::logError(const std::string &message) { + logError(boost::locale::conv::utf_to_utf(message)); + } + + long long Measure::unixTime() { + std::chrono::system_clock::time_point time = std::chrono::system_clock::now(); + return std::chrono::duration_cast(time.time_since_epoch()).count(); + } + + long long rawValueToLong(std::vector const &bytes) { + long long ret = 0; + for (auto i = bytes.end() - 1; i >= bytes.begin(); i--) { + ret |= static_cast(*i) << ((i - bytes.begin())) * 8; + } + return ret; + } + + double Measure::updateSmartAta() { + std::vector smartAttributes{}; + try { + smartAttributes = hardwareService.getSmartAttributes( + boost::locale::conv::utf_to_utf(hardwareName), + boost::locale::conv::utf_to_utf(hardwareType)); + } catch (std::exception const &e) { + logError(e.what()); + return -1.0f; + } + bool prefail = false; + bool advisory = false; + bool warning = false; + for (auto const &a: smartAttributes) { + long long rawValue = rawValueToLong(a.getRawValue()); + + if (!a.getRawValue().empty()) { + if ((a.getId() == 0x05 || a.getId() == 0xC5 || a.getId() == 0xC6) && rawValue > WARNING_THRESHOLD_ATASMART) { + warning = true; + logError((boost::format("warning: id:'%1%'; name:'%2%';") % a.getId() % a.getName()).str()); + } + + if (a.isPrefail()) { + prefail = true; + logError((boost::format("prefail: id:'%1%'; name:'%2%';") % a.getId() % a.getName()).str()); + } + + if (a.isAdvisory()) { + advisory = true; + } + } + } + + if (boost::iequals(hwStatusItem, SMART_ITEM_STATUS)) { + if (prefail) { + stringValue = ATASMART_PREFAIL; + } else if (advisory) { + stringValue = ATASMART_ENDOFLIFE; + } else if (warning) { + stringValue = ATASMART_WARNING; + } else { + stringValue = ATASMART_OK; + } + } else { + for (auto const &a: smartAttributes) { + if (!a.getRawValue().empty() && boost::iequals(hwStatusItem, a.getName())) { + return static_cast(a.getCurrentValue()); + } + } + } + + return -1.0f; + } + + double Measure::updateSmartNvme() { + try { + lhws::NvmeSmart nvmeSmart = hardwareService.getNvmeSmart(boost::locale::conv::utf_to_utf(hardwareName), + boost::locale::conv::utf_to_utf(hardwareType)); + if (boost::iequals(hwStatusItem, "availableSpare")) { + return static_cast(nvmeSmart.getAvailableSpare()); + } + if (boost::iequals(hwStatusItem, "availableSpareThreshold")) { + return static_cast(nvmeSmart.getAvailableSpareThreshold()); + } + if (boost::iequals(hwStatusItem, "controllerBusyTime")) { + return static_cast(nvmeSmart.getControllerBusyTime()); + } + if (boost::iequals(hwStatusItem, "criticalCompositeTemperatureTime")) { + return static_cast(nvmeSmart.getCriticalCompositeTemperatureTime()); + } + if (boost::iequals(hwStatusItem, "criticalWarning")) { + return static_cast(nvmeSmart.getCriticalWarning()); + } + if (boost::iequals(hwStatusItem, "dataUnitRead")) { + return static_cast(nvmeSmart.getDataUnitRead()); + } + if (boost::iequals(hwStatusItem, "dataUnitWritten")) { + return static_cast(nvmeSmart.getDataUnitWritten()); + } + if (boost::iequals(hwStatusItem, "errorInfoLogEntryCount")) { + return static_cast(nvmeSmart.getErrorInfoLogEntryCount()); + } + if (boost::iequals(hwStatusItem, "hostReadCommands")) { + return static_cast(nvmeSmart.getHostReadCommands()); + } + if (boost::iequals(hwStatusItem, "hostWriteCommands")) { + return static_cast(nvmeSmart.getHostWriteCommands()); + } + if (boost::iequals(hwStatusItem, "mediaErrors")) { + return static_cast(nvmeSmart.getMediaErrors()); + } + if (boost::iequals(hwStatusItem, "percentageUsed")) { + return static_cast(nvmeSmart.getPercentageUsed()); + } + if (boost::iequals(hwStatusItem, "powerCycle")) { + return static_cast(nvmeSmart.getPowerCycle()); + } + if (boost::iequals(hwStatusItem, "powerOnHours")) { + return static_cast(nvmeSmart.getPowerOnHours()); + } + if (boost::iequals(hwStatusItem, "temperature")) { + return static_cast(nvmeSmart.getTemperature()); + } + if (boost::iequals(hwStatusItem, "unsafeShutdowns")) { + return static_cast(nvmeSmart.getUnsafeShutdowns()); + } + if (boost::iequals(hwStatusItem, "warningCompositeTemperatureTime")) { + return static_cast(nvmeSmart.getWarningCompositeTemperatureTime()); + } + } catch (std::exception const &e) { + logError(e.what()); + } + return -1.0f; + } + + double Measure::updateRtss() { + RtssAppStat stat = RtssAppStat::getStatLastForeground(); + if (boost::iequals(sensorType, "framerate")) { + return stat.getFramerate(); + } else if (boost::iequals(sensorType, "frametime")) { + return (stat.getFrametime() / 1000.0); + } else if (boost::iequals(sensorType, "frametimeMax")) { + return (stat.getFrametimeMax() / 1000.0); + } else if (boost::iequals(sensorType, "frametimeMin")) { + return (stat.getFrametimeMin() / 1000.0); + } else if (boost::iequals(sensorType, "frametimeAvg")) { + return (stat.getFrametimeAvg() / 1000.0); + } + return -1.0f; + } + + double Measure::updateSensor() { + bool stale = false; + try { + if (staleAfterSecs > 0) { + int sensorUpdateInterval = hardwareService.getSensorsMetadata().getUpdateInterval(); + long long lastUpdate = hardwareService.getSensorsMetadata().getLastUpdate(); + long long now = unixTime(); + + if (lastUpdate < (now - sensorUpdateInterval - staleAfterSecs)) { + stale = true; + } + } else { + stale = true; + } + } catch (std::exception const &e) { + logError(e.what()); + return -1.0f; + } + + try { + lhws::Sensor sensor; + if(sensorId.empty()) { + sensor = hardwareService.getSensorByName( + boost::locale::conv::utf_to_utf(sensorName), + boost::locale::conv::utf_to_utf(sensorType), + boost::locale::conv::utf_to_utf(hardwareName)); + } else { + sensor = hardwareService.getSensorById(boost::locale::conv::utf_to_utf(sensorId)); + } + + return sensor.getValue(); + } catch (std::exception const &e) { + logError(e.what()); + } + if (!stale) { + return lastValue; + } + return -1.0f; + } + + void Measure::doUpdate() { + double value = -1.0; + if (!hwStatusType.empty() && !hwStatusItem.empty()) { + if (boost::iequals(hwStatusType, SMARTTYPE_ATA)) { + value = updateSmartAta(); + } else if (boost::iequals(hwStatusType, SMARTTYPE_NVME)) { + value = updateSmartNvme(); + } + } else if (boost::iequals(sensorName, "rtss")) { + value = updateRtss(); + } else if ((!sensorName.empty() && !sensorType.empty() && !hardwareName.empty()) || !sensorId.empty()) { + value = updateSensor(); + } else { + value = -1.0f; + } + + Measure::lastValue = value; + } + + void Measure::calculateUpdateInterval() { + auto now = std::chrono::steady_clock::now(); + + auto realInterval = now - previousUpdate; + long long realIntervalMs = std::chrono::duration_cast(realInterval).count(); + + if (realIntervalMs < MIN_UPDATE_INTERVAL) { + realIntervalMs = MIN_UPDATE_INTERVAL; + } + if (realIntervalMs > MAX_UPDATE_INTERVAL) { + realIntervalMs = MAX_UPDATE_INTERVAL; + } + + auto currentInterval = std::chrono::milliseconds(static_cast( + std::round(static_cast(realIntervalMs) / 500.0) * 500) + ); + + previousUpdate = std::chrono::steady_clock::now(); + + setUpdateInterval(currentInterval); + } + + void Measure::loadOptions() { + hwStatusType = api.readString(OPTION_HWSTATUSTYPE, L""); + hwStatusItem = api.readString(OPTION_HWSTATUSITEM, L""); + sensorName = api.readString(OPTION_SENSORNAME, L""); + sensorType = api.readString(OPTION_SENSORTYPE, L""); + hardwareName = api.readString(OPTION_HARDWARENAME, L""); + hardwareType = api.readString(OPTION_HARDWARETYPE, L""); + sensorId = api.readString(OPTION_SENSORID, L""); + staleAfterSecs = api.readInt(OPTION_STALEAFTERSECS, VALUE_STALE_SECS); + + if (staleAfterSecs < 0) { + staleAfterSecs = 0; + } + } + + void Measure::setUpdateInterval(std::chrono::milliseconds &aInterval) { + updateInterval = aInterval; + timer.setTime(updateInterval); + } +} \ No newline at end of file diff --git a/src/Measure.h b/src/Measure.h new file mode 100644 index 0000000..0cdf8c7 --- /dev/null +++ b/src/Measure.h @@ -0,0 +1,87 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 15/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include "lhwservice/HardwareService.h" +#include "Constants.h" +#include "API.h" +#include "BackgroundTimer.h" + +namespace LhwsPlugin { + class Measure { + private: + lhws::HardwareService hardwareService{}; + std::wstring sensorIdentifier{}; + std::wstring hardwareName{}; + std::wstring hardwareType{}; + std::wstring sensorName{}; + std::wstring sensorType{}; + std::wstring hwStatusType{}; + std::wstring hwStatusItem{}; + std::wstring stringValue{}; + std::wstring sensorId{}; + std::wstring fps{}; + double lastValue = -1.0f; + int staleAfterSecs = VALUE_STALE_SECS; + Rainmeter::API api; + std::mutex mtxValue{}; + std::chrono::milliseconds updateInterval{}; + std::chrono::time_point previousUpdate{std::chrono::steady_clock::now()}; + + BackgroundTimer timer{std::chrono::milliseconds(1000), [this]() { + if (!mtxValue.try_lock()) { + return; + } + std::scoped_lock lock(std::adopt_lock, mtxValue); + doUpdate(); + }}; + + void loadOptions(); + + public: + explicit Measure(Rainmeter::API const &rm); + + [[nodiscard]] std::wstring getString() { + return stringValue; + } + + void reload(double maxValue); + + double update(); + + void logError(std::wstring const &message); + + void logError(std::string const &message); + + double updateSmartAta(); + + double updateSmartNvme(); + + double updateRtss(); + + double updateSensor(); + + static long long unixTime(); + + void doUpdate(); + + void calculateUpdateInterval(); + + void setUpdateInterval(std::chrono::milliseconds &aInterval); + }; +} \ No newline at end of file diff --git a/src/Plugin.cpp b/src/Plugin.cpp new file mode 100644 index 0000000..8b62142 --- /dev/null +++ b/src/Plugin.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 15/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include "API.h" +#include "Measure.h" +#include "RainmeterAPI.h" + +namespace LhwsPlugin { + PLUGIN_EXPORT void Initialize([[maybe_unused]] void **data, [[maybe_unused]] void *rm) { + Rainmeter::API api(rm); + auto *measure = new Measure(api); + *data = measure; + } + + PLUGIN_EXPORT void Reload([[maybe_unused]] void *data, [[maybe_unused]] void *rm, + [[maybe_unused]] double *maxValue) { // NOLINT(readability-non-const-parameter) + auto *measure = static_cast(data); + measure->reload(*maxValue); + } + + PLUGIN_EXPORT double Update([[maybe_unused]] void *data) { + auto *measure = static_cast(data); + return measure->update(); + } + + PLUGIN_EXPORT LPCWSTR GetString([[maybe_unused]] void *data) { + auto *measure = static_cast(data); + std::wstring wstr = measure->getString(); + if (wstr.empty()) { + return nullptr; + } + + int stringSize = static_cast(wstr.size() * sizeof(wchar_t)); + auto *str = new wchar_t[stringSize + 1]; + wcsncpy_s(str, stringSize, wstr.c_str(), stringSize); + return str; + } + + PLUGIN_EXPORT void Finalize([[maybe_unused]] void *data) { + delete (static_cast(data)); + } +} \ No newline at end of file diff --git a/src/RtssAppStat.cpp b/src/RtssAppStat.cpp new file mode 100644 index 0000000..73b4e5d --- /dev/null +++ b/src/RtssAppStat.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 28/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include "RtssAppStat.h" + +namespace LhwsPlugin { + RtssAppStat::RtssAppStat(std::string appName, unsigned long processId, unsigned long framerate, unsigned long frametime, + unsigned long framerateMin, unsigned long framerateAvg, unsigned long framerateMax, + unsigned long frametimeMin, unsigned long frametimeAvg, unsigned long frametimeMax) + : appName(std::move(appName)), processId(processId), framerate(framerate), frametime(frametime), + framerateMin(framerateMin), + framerateAvg(framerateAvg), framerateMax(framerateMax), frametimeMin(frametimeMin), frametimeAvg(frametimeAvg), + frametimeMax(frametimeMax) {} + + RtssAppStat RtssAppStat::getStatLastForeground() { + HANDLE hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, "RTSSSharedMemoryV2"); + + if (hMapFile) { + LPVOID pMapAddr = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); + auto pMem = (LPRTSS_SHARED_MEMORY) pMapAddr; + + if (pMem) { + if ((pMem->dwSignature == 'RTSS') && (pMem->dwVersion >= 0x00020000)) { + auto appEntry = + reinterpret_cast( + ((LPBYTE) pMem + pMem->dwAppArrOffset + pMem->dwLastForegroundApp * pMem->dwAppEntrySize) + ); + if (appEntry->dwTime0 != 0 && appEntry->dwFrames != 0 && + pMem->dwLastForegroundAppProcessID == appEntry->dwProcessID) { + return {appEntry->szName, + appEntry->dwProcessID, + static_cast(std::round( + 1000.0 * appEntry->dwFrames / (appEntry->dwTime1 - appEntry->dwTime0))), + appEntry->dwFrameTime, + appEntry->dwStatFramerateMin, + appEntry->dwStatFramerateAvg, + appEntry->dwStatFramerateMax, + appEntry->dwStatFrameTimeMin, + appEntry->dwStatFrameTimeAvg, + appEntry->dwStatFrameTimeMax + }; + } + } + + UnmapViewOfFile(pMapAddr); + } + + CloseHandle(hMapFile); + } + + return {}; + } + + const std::string &RtssAppStat::getAppName() const { + return appName; + } + + unsigned long RtssAppStat::getProcessId() const { + return processId; + } + + unsigned long RtssAppStat::getFramerate() const { + return framerate; + } + + unsigned long RtssAppStat::getFrametime() const { + return frametime; + } + + unsigned long RtssAppStat::getFramerateMin() const { + return framerateMin; + } + + unsigned long RtssAppStat::getFramerateAvg() const { + return framerateAvg; + } + + unsigned long RtssAppStat::getFramerateMax() const { + return framerateMax; + } + + unsigned long RtssAppStat::getFrametimeMin() const { + return frametimeMin; + } + + unsigned long RtssAppStat::getFrametimeAvg() const { + return frametimeAvg; + } + + unsigned long RtssAppStat::getFrametimeMax() const { + return frametimeMax; + } +} \ No newline at end of file diff --git a/src/RtssAppStat.h b/src/RtssAppStat.h new file mode 100644 index 0000000..0f7d491 --- /dev/null +++ b/src/RtssAppStat.h @@ -0,0 +1,59 @@ +// Copyright (C) 2022 Emerson Pinter - All Rights Reserved + +// +// Created by epinter on 28/05/2022. +// + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +namespace LhwsPlugin { + class RtssAppStat { + private: + std::string appName{}; + unsigned long processId{}; + unsigned long framerate{}; + unsigned long frametime{}; + unsigned long framerateMin{}; + unsigned long framerateAvg{}; + unsigned long framerateMax{}; + unsigned long frametimeMin{}; + unsigned long frametimeAvg{}; + unsigned long frametimeMax{}; + public: + RtssAppStat(std::string appName, unsigned long processId, unsigned long framerate, unsigned long frametime, + unsigned long framerateMin, unsigned long framerateAvg, unsigned long framerateMax, unsigned long frametimeMin, + unsigned long frametimeAvg, unsigned long frametimeMax); + + RtssAppStat() = default; + + static RtssAppStat getStatLastForeground(); + + [[nodiscard]] [[maybe_unused]] const std::string &getAppName() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getProcessId() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFramerate() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFrametime() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFramerateMin() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFramerateAvg() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFramerateMax() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFrametimeMin() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFrametimeAvg() const; + + [[nodiscard]] [[maybe_unused]] unsigned long getFrametimeMax() const; + }; +} \ No newline at end of file