mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2025-12-23 23:37:48 -05:00
1992 lines
81 KiB
C++
1992 lines
81 KiB
C++
/*---------------------------------------------------------*\
|
|
| ResourceManager.cpp |
|
|
| |
|
|
| OpenRGB Resource Manager controls access to application |
|
|
| components including RGBControllers, I2C interfaces, |
|
|
| and network SDK components |
|
|
| |
|
|
| Adam Honse (CalcProgrammer1) 27 Sep 2020 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-only |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#ifdef _WIN32
|
|
#include <codecvt>
|
|
#include <locale>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
#include <hidapi.h>
|
|
#include "cli.h"
|
|
#include "pci_ids/pci_ids.h"
|
|
#include "ResourceManager.h"
|
|
#include "ProfileManager.h"
|
|
#include "LogManager.h"
|
|
#include "SettingsManager.h"
|
|
#include "NetworkClient.h"
|
|
#include "NetworkServer.h"
|
|
#include "filesystem.h"
|
|
#include "StringUtils.h"
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Translation Strings |
|
|
\*-------------------------------------------------------------------------*/
|
|
const char *I2C_ERR_WIN = QT_TRANSLATE_NOOP(
|
|
"ResourceManager",
|
|
"<h2>Some internal devices may not be detected:</h2>"
|
|
"<p>One or more I2C or SMBus interfaces failed to initialize.</p>"
|
|
"<p><b>RGB DRAM modules, some motherboards' onboard RGB lighting, and RGB Graphics Cards, will "
|
|
"not be available in OpenRGB</b> without I2C or SMBus.</p>"
|
|
"<h4>How to fix this:</h4>"
|
|
"<p>On Windows, this is usually caused by a failure to load the WinRing0 driver.</p>"
|
|
"<p>You must run OpenRGB as administrator at least once to allow WinRing0 to set up.</p>"
|
|
"<p>See <a href='https://help.openrgb.org/'>help.openrgb.org</a> for additional "
|
|
"troubleshooting steps if you keep seeing this message.<br></p>"
|
|
"<h3>If you are not using internal RGB on a desktop this message is not important to "
|
|
"you.</h3>");
|
|
const char *I2C_ERR_LINUX = QT_TRANSLATE_NOOP(
|
|
"ResourceManager",
|
|
"<h2>Some internal devices may not be detected:</h2>"
|
|
"<p>One or more I2C or SMBus interfaces failed to initialize.</p>"
|
|
"<p><b>RGB DRAM modules, some motherboards' onboard RGB lighting, and RGB Graphics Cards, will "
|
|
"not be available in OpenRGB</b> without I2C or SMBus.</p>"
|
|
"<h4>How to fix this:</h4>"
|
|
"<p>On Linux, this is usually because the i2c-dev module is not loaded.</p>"
|
|
"<p>You must load the i2c-dev module along with the correct i2c driver for your motherboard. "
|
|
"This is usually i2c-piix4 for AMD systems and i2c-i801 for Intel systems.</p>"
|
|
"<p>See <a href='https://help.openrgb.org/'>help.openrgb.org</a> for additional "
|
|
"troubleshooting steps if you keep seeing this message.<br></p>"
|
|
"<h3>If you are not using internal RGB on a desktop this message is not important to "
|
|
"you.</h3>");
|
|
|
|
const char *UDEV_MISSING
|
|
= QT_TRANSLATE_NOOP("ResourceManager",
|
|
"<h2>WARNING:</h2>"
|
|
"<p>The OpenRGB udev rules are not installed.</p>"
|
|
"<p>Most devices will not be available unless running OpenRGB as root.</p>"
|
|
"<p>If using AppImage, Flatpak, or self-compiled versions of OpenRGB you "
|
|
"must install the udev rules manually</p>"
|
|
"<p>See <a href='https://openrgb.org/udev'>https://openrgb.org/udev</a> to "
|
|
"install the udev rules manually</p>");
|
|
const char *UDEV_MUTLI = QT_TRANSLATE_NOOP(
|
|
"ResourceManager",
|
|
"<h2>WARNING:</h2>"
|
|
"<p>Multiple OpenRGB udev rules are installed.</p>"
|
|
"<p>The udev rules file 60-openrgb.rules is installed in both /etc/udev/rules.d and "
|
|
"/usr/lib/udev/rules.d.</p>"
|
|
"<p>Multiple udev rules files can conflict, it is recommended to remove one of them.</p>");
|
|
|
|
const hidapi_wrapper default_wrapper
|
|
= {NULL,
|
|
(hidapi_wrapper_send_feature_report) hid_send_feature_report,
|
|
(hidapi_wrapper_get_feature_report) hid_get_feature_report,
|
|
(hidapi_wrapper_get_serial_number_string) hid_get_serial_number_string,
|
|
(hidapi_wrapper_open_path) hid_open_path,
|
|
(hidapi_wrapper_enumerate) hid_enumerate,
|
|
(hidapi_wrapper_free_enumeration) hid_free_enumeration,
|
|
(hidapi_wrapper_close) hid_close,
|
|
(hidapi_wrapper_error) hid_error};
|
|
|
|
bool BasicHIDBlock::compare(hid_device_info *info)
|
|
{
|
|
return ((vid == info->vendor_id) && (pid == info->product_id)
|
|
#ifdef USE_HID_USAGE
|
|
&& ((usage_page == HID_USAGE_PAGE_ANY) || (usage_page == info->usage_page))
|
|
&& ((usage == HID_USAGE_ANY) || (usage == info->usage))
|
|
&& ((interface == HID_INTERFACE_ANY) || (interface == info->interface_number))
|
|
#else
|
|
&& ((interface == HID_INTERFACE_ANY) || (interface == info->interface_number))
|
|
#endif
|
|
);
|
|
}
|
|
|
|
ResourceManager *ResourceManager::instance;
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
ResourceManager *ResourceManager::get()
|
|
{
|
|
if (!instance) {
|
|
instance = new ResourceManager();
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
ResourceManager::ResourceManager()
|
|
{
|
|
/*-------------------------------------------------------------------------*\
|
|
| Initialize Detection Variables |
|
|
\*-------------------------------------------------------------------------*/
|
|
detection_enabled = true;
|
|
detection_percent = 100;
|
|
detection_string = "";
|
|
detection_is_required = false;
|
|
dynamic_detectors_processed = false;
|
|
init_finished = false;
|
|
background_thread_running = true;
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Start the background detection thread in advance; it will be suspended |
|
|
| until necessary |
|
|
\*-------------------------------------------------------------------------*/
|
|
DetectDevicesThread = new std::thread(&ResourceManager::BackgroundThreadFunction, this);
|
|
|
|
SetupConfigurationDirectory();
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Load settings from file |
|
|
\*-------------------------------------------------------------------------*/
|
|
settings_manager = new SettingsManager();
|
|
|
|
settings_manager->LoadSettings(GetConfigurationDirectory() / "OpenRGB.json");
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Configure the log manager |
|
|
\*-------------------------------------------------------------------------*/
|
|
LogManager::get()->configure(settings_manager->GetSettings("LogManager"),
|
|
GetConfigurationDirectory());
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Initialize Server Instance |
|
|
| If configured, pass through full controller list including clients |
|
|
| Otherwise, pass only local hardware controllers |
|
|
\*-------------------------------------------------------------------------*/
|
|
json server_settings = settings_manager->GetSettings("Server");
|
|
bool all_controllers = false;
|
|
bool legacy_workaround = false;
|
|
|
|
if (server_settings.contains("all_controllers")) {
|
|
all_controllers = server_settings["all_controllers"];
|
|
}
|
|
|
|
if (all_controllers) {
|
|
server = new NetworkServer(rgb_controllers);
|
|
} else {
|
|
server = new NetworkServer(rgb_controllers_hw);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Enable legacy SDK workaround in server if configured |
|
|
\*-------------------------------------------------------------------------*/
|
|
if (server_settings.contains("legacy_workaround")) {
|
|
legacy_workaround = server_settings["legacy_workaround"];
|
|
}
|
|
|
|
if (legacy_workaround) {
|
|
server->SetLegacyWorkaroundEnable(true);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Initialize Saved Client Connections |
|
|
\*-------------------------------------------------------------------------*/
|
|
json client_settings = settings_manager->GetSettings("Client");
|
|
|
|
if (client_settings.contains("clients")) {
|
|
for (unsigned int client_idx = 0; client_idx < client_settings["clients"].size();
|
|
client_idx++) {
|
|
NetworkClient *client = new NetworkClient(rgb_controllers);
|
|
|
|
std::string titleString = "OpenRGB ";
|
|
titleString.append(VERSION_STRING);
|
|
|
|
std::string client_ip = client_settings["clients"][client_idx]["ip"];
|
|
unsigned short client_port = client_settings["clients"][client_idx]["port"];
|
|
|
|
client->SetIP(client_ip.c_str());
|
|
client->SetName(titleString.c_str());
|
|
client->SetPort(client_port);
|
|
|
|
client->StartClient();
|
|
|
|
for (int timeout = 0; timeout < 100; timeout++) {
|
|
if (client->GetConnected()) {
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(10ms);
|
|
}
|
|
|
|
clients.push_back(client);
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Load sizes list from file |
|
|
\*-------------------------------------------------------------------------*/
|
|
profile_manager = new ProfileManager(GetConfigurationDirectory());
|
|
server->SetProfileManager(profile_manager);
|
|
rgb_controllers_sizes = profile_manager->LoadProfileToList("sizes", true);
|
|
}
|
|
|
|
ResourceManager::~ResourceManager()
|
|
{
|
|
Cleanup();
|
|
|
|
// Mark the background detection thread as not running
|
|
// And then wake it up so it knows that it has to stop
|
|
background_thread_running = false;
|
|
BackgroundFunctionStartTrigger.notify_one();
|
|
|
|
// Stop the background thread
|
|
if (DetectDevicesThread) {
|
|
DetectDevicesThread->join();
|
|
delete DetectDevicesThread;
|
|
DetectDevicesThread = nullptr;
|
|
}
|
|
}
|
|
|
|
void ResourceManager::RegisterI2CBus(i2c_smbus_interface *bus)
|
|
{
|
|
LOG_INFO(
|
|
"[ResourceManager] Registering I2C interface: %s Device %04X:%04X Subsystem: %04X:%04X",
|
|
bus->device_name,
|
|
bus->pci_vendor,
|
|
bus->pci_device,
|
|
bus->pci_subsystem_vendor,
|
|
bus->pci_subsystem_device);
|
|
busses.push_back(bus);
|
|
}
|
|
|
|
std::vector<i2c_smbus_interface *> &ResourceManager::GetI2CBusses()
|
|
{
|
|
return busses;
|
|
}
|
|
|
|
void ResourceManager::RegisterRGBController(RGBController *rgb_controller)
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| Mark this controller as locally owned |
|
|
\*-------------------------------------------------*/
|
|
rgb_controller->flags &= ~CONTROLLER_FLAG_REMOTE;
|
|
rgb_controller->flags |= CONTROLLER_FLAG_LOCAL;
|
|
|
|
LOG_INFO("[%s] Registering RGB controller", rgb_controller->name.c_str());
|
|
rgb_controllers_hw.push_back(rgb_controller);
|
|
|
|
/*-------------------------------------------------*\
|
|
| If the device list size has changed, call the |
|
|
| device list changed callbacks |
|
|
| |
|
|
| TODO: If all detection is reworked to use |
|
|
| RegisterRGBController, tracking of previous list |
|
|
| size can be removed and profile can be loaded per |
|
|
| controller before adding to list |
|
|
\*-------------------------------------------------*/
|
|
if (rgb_controllers_hw.size() != detection_prev_size) {
|
|
/*-------------------------------------------------*\
|
|
| First, load sizes for the new controllers |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int controller_size_idx = detection_prev_size;
|
|
controller_size_idx < rgb_controllers_hw.size();
|
|
controller_size_idx++) {
|
|
profile_manager->LoadDeviceFromListWithOptions(rgb_controllers_sizes,
|
|
detection_size_entry_used,
|
|
rgb_controllers_hw[controller_size_idx],
|
|
true,
|
|
false);
|
|
}
|
|
|
|
UpdateDeviceList();
|
|
}
|
|
|
|
detection_prev_size = (unsigned int) rgb_controllers_hw.size();
|
|
|
|
UpdateDeviceList();
|
|
}
|
|
|
|
void ResourceManager::UnregisterRGBController(RGBController *rgb_controller)
|
|
{
|
|
LOG_INFO("[%s] Unregistering RGB controller", rgb_controller->name.c_str());
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Clear callbacks from the controller before removal |
|
|
\*-------------------------------------------------------------------------*/
|
|
rgb_controller->ClearCallbacks();
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Find the controller to remove and remove it from the hardware list |
|
|
\*-------------------------------------------------------------------------*/
|
|
std::vector<RGBController *>::iterator hw_it = std::find(rgb_controllers_hw.begin(),
|
|
rgb_controllers_hw.end(),
|
|
rgb_controller);
|
|
|
|
if (hw_it != rgb_controllers_hw.end()) {
|
|
rgb_controllers_hw.erase(hw_it);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Find the controller to remove and remove it from the master list |
|
|
\*-------------------------------------------------------------------------*/
|
|
std::vector<RGBController *>::iterator rgb_it = std::find(rgb_controllers.begin(),
|
|
rgb_controllers.end(),
|
|
rgb_controller);
|
|
|
|
if (rgb_it != rgb_controllers.end()) {
|
|
rgb_controllers.erase(rgb_it);
|
|
}
|
|
|
|
UpdateDeviceList();
|
|
}
|
|
|
|
std::vector<RGBController *> &ResourceManager::GetRGBControllers()
|
|
{
|
|
return rgb_controllers;
|
|
}
|
|
|
|
void ResourceManager::RegisterI2CBusDetector(I2CBusDetectorFunction detector)
|
|
{
|
|
i2c_bus_detectors.push_back(detector);
|
|
}
|
|
|
|
void ResourceManager::RegisterI2CDeviceDetector(std::string name, I2CDeviceDetectorFunction detector)
|
|
{
|
|
i2c_device_detector_strings.push_back(name);
|
|
i2c_device_detectors.push_back(detector);
|
|
}
|
|
|
|
void ResourceManager::RegisterI2CDIMMDeviceDetector(std::string name,
|
|
I2CDIMMDeviceDetectorFunction detector,
|
|
uint16_t jedec_id,
|
|
uint8_t dimm_type)
|
|
{
|
|
I2CDIMMDeviceDetectorBlock block;
|
|
|
|
block.name = name;
|
|
block.function = detector;
|
|
block.jedec_id = jedec_id;
|
|
block.dimm_type = dimm_type;
|
|
|
|
i2c_dimm_device_detectors.push_back(block);
|
|
}
|
|
|
|
void ResourceManager::RegisterI2CPCIDeviceDetector(std::string name,
|
|
I2CPCIDeviceDetectorFunction detector,
|
|
uint16_t ven_id,
|
|
uint16_t dev_id,
|
|
uint16_t subven_id,
|
|
uint16_t subdev_id,
|
|
uint8_t i2c_addr)
|
|
{
|
|
I2CPCIDeviceDetectorBlock block;
|
|
|
|
block.name = name;
|
|
block.function = detector;
|
|
block.ven_id = ven_id;
|
|
block.dev_id = dev_id;
|
|
block.subven_id = subven_id;
|
|
block.subdev_id = subdev_id;
|
|
block.i2c_addr = i2c_addr;
|
|
|
|
i2c_pci_device_detectors.push_back(block);
|
|
}
|
|
|
|
void ResourceManager::RegisterDeviceDetector(std::string name, DeviceDetectorFunction detector)
|
|
{
|
|
device_detector_strings.push_back(name);
|
|
device_detectors.push_back(detector);
|
|
}
|
|
|
|
void ResourceManager::RegisterHIDDeviceDetector(std::string name,
|
|
HIDDeviceDetectorFunction detector,
|
|
uint16_t vid,
|
|
uint16_t pid,
|
|
int interface,
|
|
int usage_page,
|
|
int usage)
|
|
{
|
|
HIDDeviceDetectorBlock block;
|
|
|
|
block.name = name;
|
|
block.vid = vid;
|
|
block.pid = pid;
|
|
block.function = detector;
|
|
block.interface = interface;
|
|
block.usage_page = usage_page;
|
|
block.usage = usage;
|
|
|
|
hid_device_detectors.push_back(block);
|
|
}
|
|
|
|
void ResourceManager::RegisterHIDWrappedDeviceDetector(std::string name,
|
|
HIDWrappedDeviceDetectorFunction detector,
|
|
uint16_t vid,
|
|
uint16_t pid,
|
|
int interface,
|
|
int usage_page,
|
|
int usage)
|
|
{
|
|
HIDWrappedDeviceDetectorBlock block;
|
|
|
|
block.name = name;
|
|
block.vid = vid;
|
|
block.pid = pid;
|
|
block.function = detector;
|
|
block.interface = interface;
|
|
block.usage_page = usage_page;
|
|
block.usage = usage;
|
|
|
|
hid_wrapped_device_detectors.push_back(block);
|
|
}
|
|
|
|
void ResourceManager::RegisterDynamicDetector(std::string name, DynamicDetectorFunction detector)
|
|
{
|
|
dynamic_detector_strings.push_back(name);
|
|
dynamic_detectors.push_back(detector);
|
|
}
|
|
|
|
void ResourceManager::RegisterPreDetectionHook(PreDetectionHookFunction hook)
|
|
{
|
|
pre_detection_hooks.push_back(hook);
|
|
}
|
|
|
|
void ResourceManager::RegisterDeviceListChangeCallback(DeviceListChangeCallback new_callback,
|
|
void *new_callback_arg)
|
|
{
|
|
DeviceListChangeCallbacks.push_back(new_callback);
|
|
DeviceListChangeCallbackArgs.push_back(new_callback_arg);
|
|
|
|
LOG_TRACE(
|
|
"[ResourceManager] Registered device list change callback. Total callbacks registered: %d",
|
|
DeviceListChangeCallbacks.size());
|
|
}
|
|
|
|
void ResourceManager::UnregisterDeviceListChangeCallback(DeviceListChangeCallback callback,
|
|
void *callback_arg)
|
|
{
|
|
for (size_t idx = 0; idx < DeviceListChangeCallbacks.size(); idx++) {
|
|
if (DeviceListChangeCallbacks[idx] == callback
|
|
&& DeviceListChangeCallbackArgs[idx] == callback_arg) {
|
|
DeviceListChangeCallbacks.erase(DeviceListChangeCallbacks.begin() + idx);
|
|
DeviceListChangeCallbackArgs.erase(DeviceListChangeCallbackArgs.begin() + idx);
|
|
}
|
|
}
|
|
|
|
LOG_TRACE("[ResourceManager] Unregistered device list change callback. Total callbacks "
|
|
"registered: %d",
|
|
DeviceListChangeCallbacks.size());
|
|
}
|
|
|
|
void ResourceManager::RegisterI2CBusListChangeCallback(I2CBusListChangeCallback new_callback,
|
|
void *new_callback_arg)
|
|
{
|
|
I2CBusListChangeCallbacks.push_back(new_callback);
|
|
I2CBusListChangeCallbackArgs.push_back(new_callback_arg);
|
|
}
|
|
|
|
void ResourceManager::UnregisterI2CBusListChangeCallback(I2CBusListChangeCallback callback,
|
|
void *callback_arg)
|
|
{
|
|
for (size_t idx = 0; idx < I2CBusListChangeCallbacks.size(); idx++) {
|
|
if (I2CBusListChangeCallbacks[idx] == callback
|
|
&& I2CBusListChangeCallbackArgs[idx] == callback_arg) {
|
|
I2CBusListChangeCallbacks.erase(I2CBusListChangeCallbacks.begin() + idx);
|
|
I2CBusListChangeCallbackArgs.erase(I2CBusListChangeCallbackArgs.begin() + idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResourceManager::RegisterDetectionProgressCallback(DetectionProgressCallback new_callback,
|
|
void *new_callback_arg)
|
|
{
|
|
DetectionProgressCallbacks.push_back(new_callback);
|
|
DetectionProgressCallbackArgs.push_back(new_callback_arg);
|
|
|
|
LOG_TRACE(
|
|
"[ResourceManager] Registered detection progress callback. Total callbacks registered: %d",
|
|
DetectionProgressCallbacks.size());
|
|
}
|
|
|
|
void ResourceManager::UnregisterDetectionProgressCallback(DetectionProgressCallback callback,
|
|
void *callback_arg)
|
|
{
|
|
for (size_t idx = 0; idx < DetectionProgressCallbacks.size(); idx++) {
|
|
if (DetectionProgressCallbacks[idx] == callback
|
|
&& DetectionProgressCallbackArgs[idx] == callback_arg) {
|
|
DetectionProgressCallbacks.erase(DetectionProgressCallbacks.begin() + idx);
|
|
DetectionProgressCallbackArgs.erase(DetectionProgressCallbackArgs.begin() + idx);
|
|
}
|
|
}
|
|
|
|
LOG_TRACE("[ResourceManager] Unregistered detection progress callback. Total callbacks "
|
|
"registered: %d",
|
|
DetectionProgressCallbacks.size());
|
|
}
|
|
|
|
void ResourceManager::RegisterDetectionStartCallback(DetectionStartCallback new_callback,
|
|
void *new_callback_arg)
|
|
{
|
|
DetectionStartCallbacks.push_back(new_callback);
|
|
DetectionStartCallbackArgs.push_back(new_callback_arg);
|
|
}
|
|
|
|
void ResourceManager::UnregisterDetectionStartCallback(DetectionStartCallback callback,
|
|
void *callback_arg)
|
|
{
|
|
for (size_t idx = 0; idx < DetectionStartCallbacks.size(); idx++) {
|
|
if (DetectionStartCallbacks[idx] == callback
|
|
&& DetectionStartCallbackArgs[idx] == callback_arg) {
|
|
DetectionStartCallbacks.erase(DetectionStartCallbacks.begin() + idx);
|
|
DetectionStartCallbackArgs.erase(DetectionStartCallbackArgs.begin() + idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResourceManager::RegisterDetectionEndCallback(DetectionEndCallback new_callback,
|
|
void *new_callback_arg)
|
|
{
|
|
DetectionEndCallbacks.push_back(new_callback);
|
|
DetectionEndCallbackArgs.push_back(new_callback_arg);
|
|
}
|
|
|
|
void ResourceManager::UnregisterDetectionEndCallback(DetectionEndCallback callback,
|
|
void *callback_arg)
|
|
{
|
|
for (size_t idx = 0; idx < DetectionEndCallbacks.size(); idx++) {
|
|
if (DetectionEndCallbacks[idx] == callback
|
|
&& DetectionEndCallbackArgs[idx] == callback_arg) {
|
|
DetectionEndCallbacks.erase(DetectionEndCallbacks.begin() + idx);
|
|
DetectionEndCallbackArgs.erase(DetectionEndCallbackArgs.begin() + idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResourceManager::UpdateDeviceList()
|
|
{
|
|
DeviceListChangeMutex.lock();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Insert hardware controllers into controller list |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int hw_controller_idx = 0; hw_controller_idx < rgb_controllers_hw.size();
|
|
hw_controller_idx++) {
|
|
/*-------------------------------------------------*\
|
|
| Check if the controller is already in the list |
|
|
| at the correct index |
|
|
\*-------------------------------------------------*/
|
|
if (hw_controller_idx < rgb_controllers.size()) {
|
|
if (rgb_controllers[hw_controller_idx] == rgb_controllers_hw[hw_controller_idx]) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If not, check if the controller is already in the |
|
|
| list at a different index |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int controller_idx = 0; controller_idx < rgb_controllers.size();
|
|
controller_idx++) {
|
|
if (rgb_controllers[controller_idx] == rgb_controllers_hw[hw_controller_idx]) {
|
|
rgb_controllers.erase(rgb_controllers.begin() + controller_idx);
|
|
rgb_controllers.insert(rgb_controllers.begin() + hw_controller_idx,
|
|
rgb_controllers_hw[hw_controller_idx]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If it still hasn't been found, add it to the list |
|
|
\*-------------------------------------------------*/
|
|
rgb_controllers.insert(rgb_controllers.begin() + hw_controller_idx,
|
|
rgb_controllers_hw[hw_controller_idx]);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Device list has changed, call the callbacks |
|
|
\*-------------------------------------------------*/
|
|
DeviceListChanged();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Device list has changed, inform all clients |
|
|
| connected to this server |
|
|
\*-------------------------------------------------*/
|
|
server->DeviceListChanged();
|
|
|
|
DeviceListChangeMutex.unlock();
|
|
}
|
|
|
|
void ResourceManager::DeviceListChanged()
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| Device list has changed, call the callbacks |
|
|
\*-------------------------------------------------*/
|
|
LOG_TRACE("[ResourceManager] Calling device list change callbacks.");
|
|
|
|
for (std::size_t callback_idx = 0;
|
|
callback_idx < (unsigned int) DeviceListChangeCallbacks.size();
|
|
callback_idx++) {
|
|
ResourceManager::DeviceListChangeCallbacks[callback_idx](
|
|
DeviceListChangeCallbackArgs[callback_idx]);
|
|
}
|
|
}
|
|
|
|
void ResourceManager::DetectionProgressChanged()
|
|
{
|
|
DetectionProgressMutex.lock();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detection progress has changed, call the callbacks|
|
|
\*-------------------------------------------------*/
|
|
LOG_TRACE("[ResourceManager] Calling detection progress callbacks.");
|
|
|
|
for (std::size_t callback_idx = 0;
|
|
callback_idx < (unsigned int) DetectionProgressCallbacks.size();
|
|
callback_idx++) {
|
|
DetectionProgressCallbacks[callback_idx](DetectionProgressCallbackArgs[callback_idx]);
|
|
}
|
|
|
|
DetectionProgressMutex.unlock();
|
|
}
|
|
|
|
void ResourceManager::I2CBusListChanged()
|
|
{
|
|
I2CBusListChangeMutex.lock();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detection progress has changed, call the callbacks|
|
|
\*-------------------------------------------------*/
|
|
for (std::size_t callback_idx = 0;
|
|
callback_idx < (unsigned int) I2CBusListChangeCallbacks.size();
|
|
callback_idx++) {
|
|
I2CBusListChangeCallbacks[callback_idx](I2CBusListChangeCallbackArgs[callback_idx]);
|
|
}
|
|
|
|
I2CBusListChangeMutex.unlock();
|
|
}
|
|
|
|
void ResourceManager::SetupConfigurationDirectory()
|
|
{
|
|
config_dir.clear();
|
|
#ifdef _WIN32
|
|
const wchar_t *appdata = _wgetenv(L"APPDATA");
|
|
if (appdata != NULL) {
|
|
config_dir = appdata;
|
|
}
|
|
#else
|
|
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
|
|
const char *home = getenv("HOME");
|
|
/*-----------------------------------------------------*\
|
|
| Check both XDG_CONFIG_HOME and APPDATA environment |
|
|
| variables. If neither exist, use current directory |
|
|
\*-----------------------------------------------------*/
|
|
if (xdg_config_home != NULL) {
|
|
config_dir = xdg_config_home;
|
|
} else if (home != NULL) {
|
|
config_dir = home;
|
|
config_dir /= ".config";
|
|
}
|
|
#endif
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If a configuration directory was found, append OpenRGB|
|
|
\*-----------------------------------------------------*/
|
|
if (config_dir != "") {
|
|
config_dir.append("OpenRGB");
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Create OpenRGB configuration directory if it doesn't exist |
|
|
\*-------------------------------------------------------------------------*/
|
|
filesystem::create_directories(config_dir);
|
|
} else {
|
|
config_dir = "./";
|
|
}
|
|
}
|
|
|
|
filesystem::path ResourceManager::GetConfigurationDirectory()
|
|
{
|
|
return (config_dir);
|
|
}
|
|
|
|
void ResourceManager::SetConfigurationDirectory(const filesystem::path &directory)
|
|
{
|
|
config_dir = directory;
|
|
settings_manager->LoadSettings(directory / "OpenRGB.json");
|
|
profile_manager->SetConfigurationDirectory(directory);
|
|
|
|
rgb_controllers_sizes.clear();
|
|
rgb_controllers_sizes = profile_manager->LoadProfileToList("sizes", true);
|
|
}
|
|
|
|
NetworkServer *ResourceManager::GetServer()
|
|
{
|
|
return (server);
|
|
}
|
|
|
|
static void NetworkClientInfoChangeCallback(void *this_ptr)
|
|
{
|
|
ResourceManager *this_obj = (ResourceManager *) this_ptr;
|
|
|
|
this_obj->DeviceListChanged();
|
|
}
|
|
|
|
void ResourceManager::RegisterNetworkClient(NetworkClient *new_client)
|
|
{
|
|
new_client->RegisterClientInfoChangeCallback(NetworkClientInfoChangeCallback, this);
|
|
|
|
clients.push_back(new_client);
|
|
}
|
|
|
|
void ResourceManager::UnregisterNetworkClient(NetworkClient *network_client)
|
|
{
|
|
/*-------------------------------------------------------------------------*\
|
|
| Stop the disconnecting client |
|
|
\*-------------------------------------------------------------------------*/
|
|
network_client->StopClient();
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Clear callbacks from the client before removal |
|
|
\*-------------------------------------------------------------------------*/
|
|
network_client->ClearCallbacks();
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Find the client to remove and remove it from the clients list |
|
|
\*-------------------------------------------------------------------------*/
|
|
std::vector<NetworkClient *>::iterator client_it = std::find(clients.begin(),
|
|
clients.end(),
|
|
network_client);
|
|
|
|
if (client_it != clients.end()) {
|
|
clients.erase(client_it);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
| Delete the client |
|
|
\*-------------------------------------------------------------------------*/
|
|
delete network_client;
|
|
|
|
UpdateDeviceList();
|
|
}
|
|
|
|
/******************************************************************************************\
|
|
* *
|
|
* AttemptLocalConnection *
|
|
* *
|
|
* Attempts an SDK connection to the local server. Returns true if success *
|
|
* *
|
|
\******************************************************************************************/
|
|
|
|
bool ResourceManager::AttemptLocalConnection()
|
|
{
|
|
detection_percent = 0;
|
|
detection_string = "Attempting local server connection...";
|
|
DetectionProgressChanged();
|
|
|
|
LOG_DEBUG("[ResourceManager] Attempting server connection...");
|
|
|
|
bool success = false;
|
|
|
|
NetworkClient *client = new NetworkClient(ResourceManager::get()->GetRGBControllers());
|
|
|
|
std::string titleString = "OpenRGB ";
|
|
titleString.append(VERSION_STRING);
|
|
|
|
client->SetName(titleString.c_str());
|
|
client->StartClient();
|
|
|
|
for (int timeout = 0; timeout < 10; timeout++) {
|
|
if (client->GetConnected()) {
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(5ms);
|
|
}
|
|
|
|
if (!client->GetConnected()) {
|
|
LOG_TRACE("[ResourceManager] Client failed to connect");
|
|
client->StopClient();
|
|
LOG_TRACE("[ResourceManager] Client stopped");
|
|
|
|
delete client;
|
|
|
|
client = NULL;
|
|
} else {
|
|
ResourceManager::get()->RegisterNetworkClient(client);
|
|
LOG_TRACE("[ResourceManager] Registered network client");
|
|
|
|
success = true;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Wait up to 5 seconds for the client connection to |
|
|
| retrieve all controllers |
|
|
\*-----------------------------------------------------*/
|
|
for (int timeout = 0; timeout < 1000; timeout++) {
|
|
if (client->GetOnline()) {
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(5ms);
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
std::vector<NetworkClient *> &ResourceManager::GetClients()
|
|
{
|
|
return (clients);
|
|
}
|
|
|
|
ProfileManager *ResourceManager::GetProfileManager()
|
|
{
|
|
return (profile_manager);
|
|
}
|
|
|
|
SettingsManager *ResourceManager::GetSettingsManager()
|
|
{
|
|
return (settings_manager);
|
|
}
|
|
|
|
bool ResourceManager::GetDetectionEnabled()
|
|
{
|
|
return (detection_enabled);
|
|
}
|
|
|
|
unsigned int ResourceManager::GetDetectionPercent()
|
|
{
|
|
return (detection_percent.load());
|
|
}
|
|
|
|
const char *ResourceManager::GetDetectionString()
|
|
{
|
|
return (detection_string);
|
|
}
|
|
|
|
void ResourceManager::Cleanup()
|
|
{
|
|
ResourceManager::get()->WaitForDeviceDetection();
|
|
|
|
std::vector<RGBController *> rgb_controllers_hw_copy = rgb_controllers_hw;
|
|
|
|
for (std::size_t hw_controller_idx = 0; hw_controller_idx < rgb_controllers_hw.size();
|
|
hw_controller_idx++) {
|
|
for (std::size_t controller_idx = 0; controller_idx < rgb_controllers.size();
|
|
controller_idx++) {
|
|
if (rgb_controllers[controller_idx] == rgb_controllers_hw[hw_controller_idx]) {
|
|
rgb_controllers.erase(rgb_controllers.begin() + controller_idx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Clear the hardware controllers list and set the |
|
|
| previous hardware controllers list size to zero |
|
|
\*-------------------------------------------------*/
|
|
rgb_controllers_hw.clear();
|
|
detection_prev_size = 0;
|
|
|
|
for (RGBController *rgb_controller : rgb_controllers_hw_copy) {
|
|
delete rgb_controller;
|
|
}
|
|
|
|
std::vector<i2c_smbus_interface *> busses_copy = busses;
|
|
|
|
busses.clear();
|
|
|
|
for (i2c_smbus_interface *bus : busses_copy) {
|
|
delete bus;
|
|
}
|
|
|
|
RunInBackgroundThread(std::bind(&ResourceManager::HidExitCoroutine, this));
|
|
}
|
|
|
|
void ResourceManager::ProcessPreDetectionHooks()
|
|
{
|
|
for (std::size_t hook_idx = 0; hook_idx < pre_detection_hooks.size(); hook_idx++) {
|
|
pre_detection_hooks[hook_idx]();
|
|
}
|
|
}
|
|
|
|
void ResourceManager::ProcessDynamicDetectors()
|
|
{
|
|
for (std::size_t detector_idx = 0; detector_idx < dynamic_detectors.size(); detector_idx++) {
|
|
dynamic_detectors[detector_idx]();
|
|
}
|
|
|
|
dynamic_detectors_processed = true;
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Handle ALL pre-detection routines |
|
|
| The system should be ready to start a detection thread|
|
|
| (returns false if detection can not proceed) |
|
|
\*-----------------------------------------------------*/
|
|
bool ResourceManager::ProcessPreDetection()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| Process pre-detection hooks |
|
|
\*-----------------------------------------------------*/
|
|
ProcessPreDetectionHooks();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Process Dynamic Detectors |
|
|
\*-----------------------------------------------------*/
|
|
if (!dynamic_detectors_processed) {
|
|
ProcessDynamicDetectors();
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Call detection start callbacks |
|
|
\*-----------------------------------------------------*/
|
|
LOG_TRACE("[ResourceManager] Calling detection start callbacks.");
|
|
|
|
for (std::size_t callback_idx = 0; callback_idx < DetectionStartCallbacks.size();
|
|
callback_idx++) {
|
|
DetectionStartCallbacks[callback_idx](DetectionStartCallbackArgs[callback_idx]);
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Update the detector settings |
|
|
\*-----------------------------------------------------*/
|
|
UpdateDetectorSettings();
|
|
if (detection_enabled) {
|
|
/*-------------------------------------------------*\
|
|
| Do nothing is it is already detecting devices |
|
|
\*-------------------------------------------------*/
|
|
if (detection_is_required.load()) {
|
|
return false;
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If there's anything left from the last time, |
|
|
| we shall remove it first |
|
|
\*-------------------------------------------------*/
|
|
detection_percent = 0;
|
|
detection_string = "";
|
|
|
|
DetectionProgressChanged();
|
|
|
|
Cleanup();
|
|
|
|
UpdateDeviceList();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Initialize HID interface for detection |
|
|
\*-------------------------------------------------*/
|
|
int hid_status = hid_init();
|
|
|
|
LOG_INFO("[ResourceManager] Initializing HID interfaces: %s",
|
|
((hid_status == 0) ? "Success" : "Failed"));
|
|
|
|
/*-------------------------------------------------*\
|
|
| Mark the detection as ongoing |
|
|
| So the detection thread may proceed |
|
|
\*-------------------------------------------------*/
|
|
detection_is_required = true;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ResourceManager::DetectDevices()
|
|
{
|
|
if (ProcessPreDetection()) {
|
|
// Run the detection coroutine
|
|
RunInBackgroundThread(std::bind(&ResourceManager::DetectDevicesCoroutine, this));
|
|
}
|
|
|
|
if (!detection_enabled) {
|
|
ProcessPostDetection();
|
|
}
|
|
}
|
|
|
|
void ResourceManager::ProcessPostDetection()
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| Signal that detection is complete |
|
|
\*-------------------------------------------------*/
|
|
detection_percent = 100;
|
|
DetectionProgressChanged();
|
|
|
|
LOG_INFO("[ResourceManager] Calling Post-detection callbacks");
|
|
/*-----------------------------------------------------*\
|
|
| Call detection end callbacks |
|
|
\*-----------------------------------------------------*/
|
|
for (std::size_t callback_idx = 0; callback_idx < DetectionEndCallbacks.size(); callback_idx++) {
|
|
DetectionEndCallbacks[callback_idx](DetectionEndCallbackArgs[callback_idx]);
|
|
}
|
|
|
|
detection_is_required = false;
|
|
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detection completed |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
}
|
|
|
|
void ResourceManager::DisableDetection()
|
|
{
|
|
detection_enabled = false;
|
|
}
|
|
|
|
void ResourceManager::DetectDevicesCoroutine()
|
|
{
|
|
DetectDeviceMutex.lock();
|
|
|
|
hid_device_info *current_hid_device;
|
|
float percent = 0.0f;
|
|
float percent_denominator = 0.0f;
|
|
json detector_settings;
|
|
unsigned int hid_device_count = 0;
|
|
hid_device_info *hid_devices = NULL;
|
|
bool hid_safe_mode = false;
|
|
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Start device detection |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
|
|
/*-------------------------------------------------*\
|
|
| Reset the size entry used flags vector |
|
|
\*-------------------------------------------------*/
|
|
detection_size_entry_used.resize(rgb_controllers_sizes.size());
|
|
|
|
for (std::size_t size_idx = 0; size_idx < (unsigned int) detection_size_entry_used.size();
|
|
size_idx++) {
|
|
detection_size_entry_used[size_idx] = false;
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Open device disable list and read in disabled |
|
|
| device strings |
|
|
\*-------------------------------------------------*/
|
|
detector_settings = settings_manager->GetSettings("Detectors");
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check HID safe mode setting |
|
|
\*-------------------------------------------------*/
|
|
if (detector_settings.contains("hid_safe_mode")) {
|
|
hid_safe_mode = detector_settings["hid_safe_mode"];
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Calculate the percentage denominator by adding |
|
|
| the number of I2C and miscellaneous detectors and |
|
|
| the number of enumerated HID devices |
|
|
| |
|
|
| Start by iterating through all HID devices in |
|
|
| list to get a total count |
|
|
\*-------------------------------------------------*/
|
|
if (!hid_safe_mode) {
|
|
hid_devices = hid_enumerate(0, 0);
|
|
}
|
|
|
|
current_hid_device = hid_devices;
|
|
|
|
while (current_hid_device) {
|
|
hid_device_count++;
|
|
|
|
current_hid_device = current_hid_device->next;
|
|
}
|
|
|
|
percent_denominator = (float) (i2c_device_detectors.size() + i2c_dimm_device_detectors.size()
|
|
+ i2c_pci_device_detectors.size() + device_detectors.size())
|
|
+ (float) hid_device_count;
|
|
|
|
/*-------------------------------------------------*\
|
|
| Start at 0% detection progress |
|
|
\*-------------------------------------------------*/
|
|
detection_percent = 0;
|
|
|
|
#ifdef __linux__
|
|
/*-------------------------------------------------*\
|
|
| Check if the udev rules exist |
|
|
\*-------------------------------------------------*/
|
|
bool udev_not_exist = false;
|
|
bool udev_multiple = false;
|
|
|
|
if (access("/etc/udev/rules.d/60-openrgb.rules", F_OK) != 0) {
|
|
if (access("/usr/lib/udev/rules.d/60-openrgb.rules", F_OK) != 0) {
|
|
udev_not_exist = true;
|
|
}
|
|
} else {
|
|
if (access("/usr/lib/udev/rules.d/60-openrgb.rules", F_OK) == 0) {
|
|
udev_multiple = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect i2c interfaces |
|
|
\*-------------------------------------------------*/
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting I2C interfaces |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
|
|
bool i2c_interface_fail = false;
|
|
|
|
for (unsigned int i2c_bus_detector_idx = 0;
|
|
i2c_bus_detector_idx < (unsigned int) i2c_bus_detectors.size()
|
|
&& detection_is_required.load();
|
|
i2c_bus_detector_idx++) {
|
|
if (i2c_bus_detectors[i2c_bus_detector_idx]() == false) {
|
|
i2c_interface_fail = true;
|
|
}
|
|
|
|
I2CBusListChanged();
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect i2c devices |
|
|
\*-------------------------------------------------*/
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting I2C devices |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
for (unsigned int i2c_detector_idx = 0;
|
|
i2c_detector_idx < (unsigned int) i2c_device_detectors.size()
|
|
&& detection_is_required.load();
|
|
i2c_detector_idx++) {
|
|
std::size_t controller_size = rgb_controllers_hw.size();
|
|
detection_string = i2c_device_detector_strings[i2c_detector_idx].c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
i2c_device_detectors[i2c_detector_idx](busses);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If the device list size has changed, call the |
|
|
| device list changed callbacks |
|
|
\*-------------------------------------------------*/
|
|
if (rgb_controllers_hw.size() == controller_size) {
|
|
LOG_DEBUG("[%s] no devices found", detection_string);
|
|
}
|
|
|
|
LOG_TRACE("[%s] detection end", detection_string);
|
|
|
|
/*-------------------------------------------------*\
|
|
| Update detection percent |
|
|
\*-------------------------------------------------*/
|
|
percent = ((float) i2c_detector_idx + 1.0f) / percent_denominator;
|
|
|
|
detection_percent = (unsigned int) (percent * 100.0f);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect i2c DIMM modules |
|
|
\*-------------------------------------------------*/
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting I2C DIMM modules |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
for (unsigned int bus = 0; bus < busses.size() && IsAnyDimmDetectorEnabled(detector_settings);
|
|
bus++) {
|
|
IF_DRAM_SMBUS(busses[bus]->pci_vendor, busses[bus]->pci_device)
|
|
{
|
|
std::vector<SPDWrapper> slots;
|
|
SPDMemoryType dimm_type = SPD_RESERVED;
|
|
|
|
for (uint8_t spd_addr = 0x50; spd_addr < 0x58; spd_addr++) {
|
|
SPDDetector spd(busses[bus], spd_addr, dimm_type);
|
|
if (spd.is_valid()) {
|
|
SPDWrapper accessor(spd);
|
|
dimm_type = spd.memory_type();
|
|
LOG_INFO("[ResourceManager] Detected occupied slot %d, bus %d, type %s",
|
|
spd_addr - 0x50 + 1,
|
|
bus,
|
|
spd_memory_type_name[dimm_type]);
|
|
LOG_DEBUG("[ResourceManager] Jedec ID: 0x%04x", accessor.jedec_id());
|
|
slots.push_back(accessor);
|
|
}
|
|
}
|
|
|
|
for (unsigned int i2c_detector_idx = 0;
|
|
i2c_detector_idx < i2c_dimm_device_detectors.size() && detection_is_required.load();
|
|
i2c_detector_idx++) {
|
|
if (i2c_dimm_device_detectors[i2c_detector_idx].dimm_type == dimm_type
|
|
&& is_jedec_in_slots(slots,
|
|
i2c_dimm_device_detectors[i2c_detector_idx].jedec_id)) {
|
|
detection_string = i2c_dimm_device_detectors[i2c_detector_idx].name.c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
std::vector<SPDWrapper *> matching_slots
|
|
= slots_with_jedec(slots,
|
|
i2c_dimm_device_detectors[i2c_detector_idx].jedec_id);
|
|
i2c_dimm_device_detectors[i2c_detector_idx].function(busses[bus],
|
|
matching_slots);
|
|
}
|
|
|
|
LOG_TRACE("[%s] detection end", detection_string);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Update detection percent |
|
|
\*-------------------------------------------------*/
|
|
percent = (i2c_device_detectors.size() + i2c_detector_idx + 1.0f)
|
|
/ percent_denominator;
|
|
|
|
detection_percent = (unsigned int) (percent * 100.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect i2c PCI devices |
|
|
\*-------------------------------------------------*/
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting I2C PCI devices |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
for (unsigned int i2c_detector_idx = 0;
|
|
i2c_detector_idx < (unsigned int) i2c_pci_device_detectors.size()
|
|
&& detection_is_required.load();
|
|
i2c_detector_idx++) {
|
|
detection_string = i2c_pci_device_detectors[i2c_detector_idx].name.c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
for (unsigned int bus = 0; bus < busses.size(); bus++) {
|
|
if (busses[bus]->pci_vendor == i2c_pci_device_detectors[i2c_detector_idx].ven_id
|
|
&& busses[bus]->pci_device == i2c_pci_device_detectors[i2c_detector_idx].dev_id
|
|
&& busses[bus]->pci_subsystem_vendor
|
|
== i2c_pci_device_detectors[i2c_detector_idx].subven_id
|
|
&& busses[bus]->pci_subsystem_device
|
|
== i2c_pci_device_detectors[i2c_detector_idx].subdev_id) {
|
|
i2c_pci_device_detectors[i2c_detector_idx]
|
|
.function(busses[bus],
|
|
i2c_pci_device_detectors[i2c_detector_idx].i2c_addr,
|
|
i2c_pci_device_detectors[i2c_detector_idx].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_TRACE("[%s] detection end", detection_string);
|
|
|
|
/*-------------------------------------------------*\
|
|
| Update detection percent |
|
|
\*-------------------------------------------------*/
|
|
percent = (i2c_device_detectors.size() + i2c_dimm_device_detectors.size() + i2c_detector_idx
|
|
+ 1.0f)
|
|
/ percent_denominator;
|
|
|
|
detection_percent = (unsigned int) (percent * 100.0f);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect HID devices |
|
|
| |
|
|
| Reset current device pointer to first device |
|
|
\*-------------------------------------------------*/
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting HID devices |");
|
|
if (hid_safe_mode)
|
|
LOG_INFO("| with safe mode |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
current_hid_device = hid_devices;
|
|
|
|
if (hid_safe_mode) {
|
|
/*-----------------------------------------------------------------------------*\
|
|
| Loop through all available detectors. If all required information matches, |
|
|
| run the detector |
|
|
\*-----------------------------------------------------------------------------*/
|
|
for (unsigned int hid_detector_idx = 0;
|
|
hid_detector_idx < (unsigned int) hid_device_detectors.size()
|
|
&& detection_is_required.load();
|
|
hid_detector_idx++) {
|
|
HIDDeviceDetectorBlock &detector = hid_device_detectors[hid_detector_idx];
|
|
hid_devices = hid_enumerate(detector.vid, detector.pid);
|
|
|
|
LOG_VERBOSE("[ResourceManager] Trying to run detector for [%s] (for %04x:%04x)",
|
|
detector.name.c_str(),
|
|
detector.vid,
|
|
detector.pid);
|
|
|
|
current_hid_device = hid_devices;
|
|
|
|
while (current_hid_device) {
|
|
if (detector.compare(current_hid_device)) {
|
|
detection_string = detector.name.c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled or needs to be |
|
|
| added to the settings list |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
detector.function(current_hid_device,
|
|
hid_device_detectors[hid_detector_idx].name);
|
|
|
|
LOG_TRACE("[%s] detection end", detection_string);
|
|
}
|
|
}
|
|
|
|
current_hid_device = current_hid_device->next;
|
|
}
|
|
|
|
hid_free_enumeration(hid_devices);
|
|
}
|
|
} else {
|
|
/*-------------------------------------------------*\
|
|
| Iterate through all devices in list and run |
|
|
| detectors |
|
|
\*-------------------------------------------------*/
|
|
hid_device_count = 0;
|
|
|
|
while (current_hid_device) {
|
|
if (LogManager::get()->getLoglevel() >= LL_DEBUG) {
|
|
const char *manu_name = StringUtils::wchar_to_char(
|
|
current_hid_device->manufacturer_string);
|
|
const char *prod_name = StringUtils::wchar_to_char(
|
|
current_hid_device->product_string);
|
|
LOG_DEBUG("[%04X:%04X U=%04X P=0x%04X I=%d] %-25s - %s",
|
|
current_hid_device->vendor_id,
|
|
current_hid_device->product_id,
|
|
current_hid_device->usage,
|
|
current_hid_device->usage_page,
|
|
current_hid_device->interface_number,
|
|
manu_name,
|
|
prod_name);
|
|
}
|
|
detection_string = "";
|
|
DetectionProgressChanged();
|
|
|
|
/*-----------------------------------------------------------------------------*\
|
|
| Loop through all available detectors. If all required information matches, |
|
|
| run the detector |
|
|
\*-----------------------------------------------------------------------------*/
|
|
for (unsigned int hid_detector_idx = 0;
|
|
hid_detector_idx < (unsigned int) hid_device_detectors.size()
|
|
&& detection_is_required.load();
|
|
hid_detector_idx++) {
|
|
HIDDeviceDetectorBlock &detector = hid_device_detectors[hid_detector_idx];
|
|
if (detector.compare(current_hid_device)) {
|
|
detection_string = detector.name.c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled or needs to be |
|
|
| added to the settings list |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
detector.function(current_hid_device,
|
|
hid_device_detectors[hid_detector_idx].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------*\
|
|
| Loop through all available wrapped HID detectors. If all required |
|
|
| information matches, run the detector |
|
|
\*-----------------------------------------------------------------------------*/
|
|
for (unsigned int hid_detector_idx = 0;
|
|
hid_detector_idx < (unsigned int) hid_wrapped_device_detectors.size()
|
|
&& detection_is_required.load();
|
|
hid_detector_idx++) {
|
|
HIDWrappedDeviceDetectorBlock &detector
|
|
= hid_wrapped_device_detectors[hid_detector_idx];
|
|
if (detector.compare(current_hid_device)) {
|
|
detection_string = detector.name.c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled or needs to be |
|
|
| added to the settings list |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
detector.function(default_wrapper,
|
|
current_hid_device,
|
|
hid_wrapped_device_detectors[hid_detector_idx].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Update detection percent |
|
|
\*-------------------------------------------------*/
|
|
hid_device_count++;
|
|
|
|
percent = (i2c_device_detectors.size() + i2c_dimm_device_detectors.size()
|
|
+ i2c_pci_device_detectors.size() + hid_device_count)
|
|
/ percent_denominator;
|
|
|
|
detection_percent = (unsigned int) (percent * 100.0f);
|
|
|
|
/*-------------------------------------------------*\
|
|
| Move on to the next HID device |
|
|
\*-------------------------------------------------*/
|
|
current_hid_device = current_hid_device->next;
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Done using the device list, free it |
|
|
\*-------------------------------------------------*/
|
|
hid_free_enumeration(hid_devices);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect HID devices |
|
|
| |
|
|
| Reset current device pointer to first device |
|
|
\*-------------------------------------------------*/
|
|
#ifdef __linux__
|
|
#ifdef __GLIBC__
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting libusb HID devices |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
|
|
void *dyn_handle = NULL;
|
|
hidapi_wrapper wrapper;
|
|
|
|
/*-------------------------------------------------*\
|
|
| Load the libhidapi-libusb library |
|
|
\*-------------------------------------------------*/
|
|
#ifdef __GLIBC__
|
|
if ((dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND)))
|
|
#else
|
|
if (dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE))
|
|
#endif
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| Create a wrapper with the libusb functions |
|
|
\*-------------------------------------------------*/
|
|
wrapper = {.dyn_handle = dyn_handle,
|
|
.hid_send_feature_report = (hidapi_wrapper_send_feature_report)
|
|
dlsym(dyn_handle, "hid_send_feature_report"),
|
|
.hid_get_feature_report = (hidapi_wrapper_get_feature_report)
|
|
dlsym(dyn_handle, "hid_get_feature_report"),
|
|
.hid_get_serial_number_string = (hidapi_wrapper_get_serial_number_string)
|
|
dlsym(dyn_handle, "hid_get_serial_number_string"),
|
|
.hid_open_path = (hidapi_wrapper_open_path) dlsym(dyn_handle, "hid_open_path"),
|
|
.hid_enumerate = (hidapi_wrapper_enumerate) dlsym(dyn_handle, "hid_enumerate"),
|
|
.hid_free_enumeration = (hidapi_wrapper_free_enumeration)
|
|
dlsym(dyn_handle, "hid_free_enumeration"),
|
|
.hid_close = (hidapi_wrapper_close) dlsym(dyn_handle, "hid_close"),
|
|
.hid_error = (hidapi_wrapper_error) dlsym(dyn_handle, "hid_free_enumeration")};
|
|
|
|
hid_devices = wrapper.hid_enumerate(0, 0);
|
|
|
|
current_hid_device = hid_devices;
|
|
|
|
/*-------------------------------------------------*\
|
|
| Iterate through all devices in list and run |
|
|
| detectors |
|
|
\*-------------------------------------------------*/
|
|
hid_device_count = 0;
|
|
|
|
while (current_hid_device) {
|
|
if (LogManager::get()->getLoglevel() >= LL_DEBUG) {
|
|
const char *manu_name = StringUtils::wchar_to_char(
|
|
current_hid_device->manufacturer_string);
|
|
const char *prod_name = StringUtils::wchar_to_char(
|
|
current_hid_device->product_string);
|
|
LOG_DEBUG("[%04X:%04X U=%04X P=0x%04X I=%d] %-25s - %s",
|
|
current_hid_device->vendor_id,
|
|
current_hid_device->product_id,
|
|
current_hid_device->usage,
|
|
current_hid_device->usage_page,
|
|
current_hid_device->interface_number,
|
|
manu_name,
|
|
prod_name);
|
|
}
|
|
detection_string = "";
|
|
DetectionProgressChanged();
|
|
|
|
/*-----------------------------------------------------------------------------*\
|
|
| Loop through all available wrapped HID detectors. If all required |
|
|
| information matches, run the detector |
|
|
\*-----------------------------------------------------------------------------*/
|
|
for (unsigned int hid_detector_idx = 0;
|
|
hid_detector_idx < (unsigned int) hid_wrapped_device_detectors.size()
|
|
&& detection_is_required.load();
|
|
hid_detector_idx++) {
|
|
HIDWrappedDeviceDetectorBlock &detector
|
|
= hid_wrapped_device_detectors[hid_detector_idx];
|
|
if (detector.compare(current_hid_device)) {
|
|
detection_string = detector.name.c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled or needs to be |
|
|
| added to the settings list |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
detector.function(wrapper, current_hid_device, detector.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Update detection percent |
|
|
\*-------------------------------------------------*/
|
|
hid_device_count++;
|
|
|
|
percent = (i2c_device_detectors.size() + i2c_dimm_device_detectors.size()
|
|
+ i2c_pci_device_detectors.size() + hid_device_count)
|
|
/ percent_denominator;
|
|
|
|
detection_percent = percent * 100.0f;
|
|
|
|
/*-------------------------------------------------*\
|
|
| Move on to the next HID device |
|
|
\*-------------------------------------------------*/
|
|
current_hid_device = current_hid_device->next;
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Done using the device list, free it |
|
|
\*-------------------------------------------------*/
|
|
wrapper.hid_free_enumeration(hid_devices);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*-------------------------------------------------*\
|
|
| Detect other devices |
|
|
\*-------------------------------------------------*/
|
|
LOG_INFO("------------------------------------------------------");
|
|
LOG_INFO("| Detecting other devices |");
|
|
LOG_INFO("------------------------------------------------------");
|
|
|
|
for (unsigned int detector_idx = 0;
|
|
detector_idx < (unsigned int) device_detectors.size() && detection_is_required.load();
|
|
detector_idx++) {
|
|
detection_string = device_detector_strings[detector_idx].c_str();
|
|
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled |
|
|
\*-------------------------------------------------*/
|
|
bool this_device_enabled = true;
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)) {
|
|
this_device_enabled = detector_settings["detectors"][detection_string];
|
|
}
|
|
|
|
LOG_DEBUG("[%s] is %s",
|
|
detection_string,
|
|
((this_device_enabled == true) ? "enabled" : "disabled"));
|
|
|
|
if (this_device_enabled) {
|
|
DetectionProgressChanged();
|
|
|
|
device_detectors[detector_idx]();
|
|
}
|
|
|
|
LOG_TRACE("[%s] detection end", detection_string);
|
|
|
|
/*-------------------------------------------------*\
|
|
| Update detection percent |
|
|
\*-------------------------------------------------*/
|
|
percent = (i2c_device_detectors.size() + hid_device_count + detector_idx + 1.0f)
|
|
/ percent_denominator;
|
|
|
|
detection_percent = (unsigned int) (percent * 100.0f);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Make sure that when the detection is done, |
|
|
| progress bar is set to 100% |
|
|
\*-------------------------------------------------*/
|
|
ProcessPostDetection();
|
|
|
|
DetectDeviceMutex.unlock();
|
|
|
|
#ifdef __linux__
|
|
/*-------------------------------------------------*\
|
|
| If the udev rules file is not installed, show a |
|
|
| dialog |
|
|
\*-------------------------------------------------*/
|
|
if (udev_not_exist) {
|
|
LOG_DIALOG("%s", UDEV_MISSING);
|
|
|
|
udev_multiple = false;
|
|
i2c_interface_fail = false;
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If multiple udev rules files are installed, show |
|
|
| a dialog |
|
|
\*-------------------------------------------------*/
|
|
if (udev_multiple) {
|
|
LOG_DIALOG("%s", UDEV_MUTLI);
|
|
|
|
i2c_interface_fail = false;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*-------------------------------------------------*\
|
|
| If any i2c interfaces failed to detect due to an |
|
|
| error condition, show a dialog |
|
|
\*-------------------------------------------------*/
|
|
if (i2c_interface_fail) {
|
|
#ifdef _WIN32
|
|
LOG_DIALOG("%s", I2C_ERR_WIN);
|
|
#endif
|
|
#ifdef __linux__
|
|
LOG_DIALOG("%s", I2C_ERR_LINUX);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void ResourceManager::StopDeviceDetection()
|
|
{
|
|
LOG_INFO("[ResourceManager] Detection abort requested");
|
|
detection_is_required = false;
|
|
detection_percent = 100;
|
|
detection_string = "Stopping";
|
|
}
|
|
|
|
void ResourceManager::Initialize(bool tryConnect,
|
|
bool detectDevices,
|
|
bool startServer,
|
|
bool applyPostOptions)
|
|
{
|
|
// Cache the parameters
|
|
// TODO: Possibly cache them in the CLI file somewhere
|
|
tryAutoConnect = tryConnect;
|
|
detection_enabled = detectDevices;
|
|
start_server = startServer;
|
|
apply_post_options = applyPostOptions;
|
|
|
|
RunInBackgroundThread(std::bind(&ResourceManager::InitCoroutine, this));
|
|
}
|
|
|
|
void ResourceManager::InitCoroutine()
|
|
{
|
|
if (tryAutoConnect) {
|
|
detection_percent = 0;
|
|
detection_string = "Attempting server connection...";
|
|
DetectionProgressChanged();
|
|
|
|
// Disable detection if a local server was found
|
|
if (AttemptLocalConnection()) {
|
|
DisableDetection();
|
|
} else {
|
|
LOG_DEBUG("[ResourceManager] Local OpenRGB server connected, running in client mode");
|
|
}
|
|
tryAutoConnect = false;
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Perform actual detection |
|
|
| Done in the same thread (InitThread), as we need to wait |
|
|
| for completion anyway |
|
|
\*---------------------------------------------------------*/
|
|
if (detection_enabled) {
|
|
LOG_DEBUG("[ResourceManager] Running standalone");
|
|
if (ProcessPreDetection()) {
|
|
// We are currently in a coroutine, so run detection directly with no scheduling
|
|
DetectDevicesCoroutine();
|
|
}
|
|
} else {
|
|
ProcessPostDetection();
|
|
}
|
|
|
|
if (start_server) {
|
|
detection_percent = 100;
|
|
detection_string = "Starting server";
|
|
DetectionProgressChanged();
|
|
|
|
GetServer()->StartServer();
|
|
if (!GetServer()->GetOnline()) {
|
|
LOG_DEBUG("[ResourceManager] Server failed to start");
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Process command line arguments after detection only if the|
|
|
| pre-detection parsing indicated it should be run |
|
|
\*---------------------------------------------------------*/
|
|
if (apply_post_options) {
|
|
cli_post_detection();
|
|
}
|
|
|
|
init_finished = true;
|
|
}
|
|
|
|
void ResourceManager::HidExitCoroutine()
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| Cleanup HID interface |
|
|
| WARNING: may not be ran from any other thread!!! |
|
|
\*-------------------------------------------------*/
|
|
int hid_status = hid_exit();
|
|
|
|
LOG_DEBUG("[ResourceManager] Closing HID interfaces: %s",
|
|
((hid_status == 0) ? "Success" : "Failed"));
|
|
}
|
|
|
|
void ResourceManager::RunInBackgroundThread(std::function<void()> coroutine)
|
|
{
|
|
if (std::this_thread::get_id() == DetectDevicesThread->get_id()) {
|
|
// We are already in the background thread - don't schedule the call, run it immediately
|
|
coroutine();
|
|
} else {
|
|
BackgroundThreadStateMutex.lock();
|
|
if (ScheduledBackgroundFunction != nullptr) {
|
|
LOG_WARNING("[ResourceManager] Detection coroutine: assigned a new coroutine when one "
|
|
"was already scheduled - probably two rescan events sent at once");
|
|
}
|
|
ScheduledBackgroundFunction = coroutine;
|
|
BackgroundThreadStateMutex.unlock();
|
|
BackgroundFunctionStartTrigger.notify_one();
|
|
}
|
|
}
|
|
|
|
void ResourceManager::BackgroundThreadFunction()
|
|
{
|
|
// The background thread that runs scheduled coroutines when applicable
|
|
// Stays asleep if nothing is scheduled
|
|
// NOTE: this thread owns the HIDAPI library internal objects on MacOS
|
|
// hid_init and hid_exit may not be called outside of this thread
|
|
// calling hid_exit outside of this thread WILL cause an immediate CRASH on MacOS
|
|
// BackgroundThreadStateMutex will be UNLOCKED as long as the thread is suspended
|
|
// It locks automatically when any coroutine is running
|
|
// However, it seems to be necessary to be separate from the DeviceDetectionMutex, even though their states are nearly identical
|
|
|
|
std::unique_lock lock(BackgroundThreadStateMutex);
|
|
while (background_thread_running) {
|
|
if (ScheduledBackgroundFunction) {
|
|
std::function<void()> coroutine = nullptr;
|
|
std::swap(ScheduledBackgroundFunction, coroutine);
|
|
try {
|
|
coroutine();
|
|
} catch (std::exception &e) {
|
|
LOG_ERROR("[ResourceManager] Unhandled exception in coroutine; e.what(): %s",
|
|
e.what());
|
|
} catch (...) {
|
|
LOG_ERROR("[ResourceManager] Unhandled exception in coroutine");
|
|
}
|
|
}
|
|
// This line will cause the thread to suspend until the condition variable is triggered
|
|
// NOTE: it may be subject to "spurious wakeups"
|
|
BackgroundFunctionStartTrigger.wait(lock);
|
|
}
|
|
}
|
|
|
|
void ResourceManager::UpdateDetectorSettings()
|
|
{
|
|
json detector_settings;
|
|
bool save_settings = false;
|
|
|
|
/*-------------------------------------------------*\
|
|
| Open device disable list and read in disabled |
|
|
| device strings |
|
|
\*-------------------------------------------------*/
|
|
detector_settings = settings_manager->GetSettings("Detectors");
|
|
|
|
/*-------------------------------------------------*\
|
|
| Loop through all I2C detectors and see if any |
|
|
| need to be saved to the settings |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int i2c_detector_idx = 0;
|
|
i2c_detector_idx < (unsigned int) i2c_device_detectors.size();
|
|
i2c_detector_idx++) {
|
|
detection_string = i2c_device_detector_strings[i2c_detector_idx].c_str();
|
|
|
|
if (!(detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string))) {
|
|
detector_settings["detectors"][detection_string] = true;
|
|
save_settings = true;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Loop through all I2C DIMM detectors and see |
|
|
| if any need to be saved to the settings |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int i2c_detector_idx = 0;
|
|
i2c_detector_idx < (unsigned int) i2c_dimm_device_detectors.size();
|
|
i2c_detector_idx++) {
|
|
detection_string = i2c_dimm_device_detectors[i2c_detector_idx].name.c_str();
|
|
|
|
if (!(detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string))) {
|
|
detector_settings["detectors"][detection_string] = true;
|
|
save_settings = true;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Loop through all I2C PCI detectors and see if any |
|
|
| need to be saved to the settings |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int i2c_pci_detector_idx = 0;
|
|
i2c_pci_detector_idx < (unsigned int) i2c_pci_device_detectors.size();
|
|
i2c_pci_detector_idx++) {
|
|
detection_string = i2c_pci_device_detectors[i2c_pci_detector_idx].name.c_str();
|
|
|
|
if (!(detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string))) {
|
|
detector_settings["detectors"][detection_string] = true;
|
|
save_settings = true;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Loop through all HID detectors and see if any |
|
|
| need to be saved to the settings |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int hid_detector_idx = 0;
|
|
hid_detector_idx < (unsigned int) hid_device_detectors.size();
|
|
hid_detector_idx++) {
|
|
detection_string = hid_device_detectors[hid_detector_idx].name.c_str();
|
|
|
|
if (!(detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string))) {
|
|
detector_settings["detectors"][detection_string] = true;
|
|
save_settings = true;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Loop through all HID wrapped detectors and see if |
|
|
| any need to be saved to the settings |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int hid_wrapped_detector_idx = 0;
|
|
hid_wrapped_detector_idx < (unsigned int) hid_wrapped_device_detectors.size();
|
|
hid_wrapped_detector_idx++) {
|
|
detection_string = hid_wrapped_device_detectors[hid_wrapped_detector_idx].name.c_str();
|
|
|
|
if (!(detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string))) {
|
|
detector_settings["detectors"][detection_string] = true;
|
|
save_settings = true;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| Loop through remaining detectors and see if any |
|
|
| need to be saved to the settings |
|
|
\*-------------------------------------------------*/
|
|
for (unsigned int detector_idx = 0; detector_idx < (unsigned int) device_detectors.size();
|
|
detector_idx++) {
|
|
detection_string = device_detector_strings[detector_idx].c_str();
|
|
|
|
if (!(detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string))) {
|
|
detector_settings["detectors"][detection_string] = true;
|
|
save_settings = true;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If there were any setting changes that need to be |
|
|
| saved, set the settings in the settings manager |
|
|
| and save them. |
|
|
\*-------------------------------------------------*/
|
|
if (save_settings) {
|
|
LOG_INFO("[ResourceManager] Saving detector settings");
|
|
|
|
settings_manager->SetSettings("Detectors", detector_settings);
|
|
|
|
settings_manager->SaveSettings();
|
|
}
|
|
}
|
|
|
|
void ResourceManager::WaitForInitialization()
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| A reliable sychronization of this kind is |
|
|
| impossible without the use of a `barrier` |
|
|
| implementation, which is only introduced in C++20 |
|
|
\*-------------------------------------------------*/
|
|
while (!init_finished) {
|
|
std::this_thread::sleep_for(1ms);
|
|
};
|
|
}
|
|
|
|
void ResourceManager::WaitForDeviceDetection()
|
|
{
|
|
DetectDeviceMutex.lock();
|
|
DetectDeviceMutex.unlock();
|
|
}
|
|
|
|
bool ResourceManager::IsAnyDimmDetectorEnabled(json &detector_settings)
|
|
{
|
|
for (unsigned int i2c_detector_idx = 0;
|
|
i2c_detector_idx < i2c_dimm_device_detectors.size() && detection_is_required.load();
|
|
i2c_detector_idx++) {
|
|
detection_string = i2c_dimm_device_detectors[i2c_detector_idx].name.c_str();
|
|
/*-------------------------------------------------*\
|
|
| Check if this detector is enabled |
|
|
\*-------------------------------------------------*/
|
|
if (detector_settings.contains("detectors")
|
|
&& detector_settings["detectors"].contains(detection_string)
|
|
&& detector_settings["detectors"][detection_string] == true) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|