You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

490 lines
21 KiB

#include "ProfileManager.h"
#include "ResourceManager.h"
#include "RGBController_Dummy.h"
#include "LogManager.h"
#include "filesystem.h"
#include <fstream>
#include <iostream>
#include <cstring>
#define OPENRGB_PROFILE_HEADER "OPENRGB_PROFILE"
#define OPENRGB_PROFILE_VERSION OPENRGB_SDK_PROTOCOL_VERSION
ProfileManager::ProfileManager(std::string config_dir)
{
configuration_directory = config_dir;
UpdateProfileList();
}
ProfileManager::~ProfileManager()
{
}
bool ProfileManager::SaveProfile(std::string profile_name, bool sizes)
{
/*---------------------------------------------------------*\
| Get the list of controllers from the resource manager |
\*---------------------------------------------------------*/
std::vector<RGBController *> controllers = ResourceManager::get()->GetRGBControllers();
/*---------------------------------------------------------*\
| If a name was entered, save the profile file |
\*---------------------------------------------------------*/
if(profile_name != "")
{
/*---------------------------------------------------------*\
| Extension .orp - OpenRgb Profile |
\*---------------------------------------------------------*/
std::string filename = profile_name;
/*---------------------------------------------------------*\
| Determine file extension |
\*---------------------------------------------------------*/
if(sizes)
{
filename += ".ors";
}
else
{
filename += ".orp";
}
/*---------------------------------------------------------*\
| Open an output file in binary mode |
\*---------------------------------------------------------*/
std::ofstream controller_file(configuration_directory + filename, std::ios::out | std::ios::binary | std::ios::trunc);
/*---------------------------------------------------------*\
| Write header |
| 16 bytes - "OPENRGB_PROFILE" |
| 4 bytes - Version, unsigned int |
\*---------------------------------------------------------*/
unsigned int profile_version = OPENRGB_PROFILE_VERSION;
controller_file.write(OPENRGB_PROFILE_HEADER, 16);
controller_file.write((char *)&profile_version, sizeof(unsigned int));
/*---------------------------------------------------------*\
| Write controller data for each controller |
\*---------------------------------------------------------*/
for(std::size_t controller_index = 0; controller_index < controllers.size(); controller_index++)
{
unsigned char *controller_data = controllers[controller_index]->GetDeviceDescription(profile_version);
unsigned int controller_size;
memcpy(&controller_size, controller_data, sizeof(controller_size));
controller_file.write((const char *)controller_data, controller_size);
delete[] controller_data;
}
/*---------------------------------------------------------*\
| Close the file when done |
\*---------------------------------------------------------*/
controller_file.close();
/*---------------------------------------------------------*\
| Update the profile list |
\*---------------------------------------------------------*/
UpdateProfileList();
return(true);
}
else
{
return(false);
}
}
void ProfileManager::SetConfigurationDirectory(std::string directory)
{
configuration_directory = directory;
UpdateProfileList();
}
bool ProfileManager::LoadProfile(std::string profile_name)
{
return(LoadProfileWithOptions(profile_name, false, true));
}
bool ProfileManager::LoadSizeFromProfile(std::string profile_name)
{
return(LoadProfileWithOptions(profile_name, true, false));
}
std::vector<RGBController*> ProfileManager::LoadProfileToList
(
std::string profile_name,
bool sizes
)
{
std::vector<RGBController*> temp_controllers;
unsigned int controller_size;
unsigned int controller_offset = 0;
std::string filename = configuration_directory + profile_name;
/*---------------------------------------------------------*\
| Determine file extension |
\*---------------------------------------------------------*/
if(sizes)
{
filename += ".ors";
}
else
{
filename += ((filename.substr(filename.size() - 4)==".orp") ? "" : ".orp");
}
/*---------------------------------------------------------*\
| Open input file in binary mode |
\*---------------------------------------------------------*/
std::ifstream controller_file(filename, std::ios::in | std::ios::binary);
/*---------------------------------------------------------*\
| Read and verify file header |
\*---------------------------------------------------------*/
char profile_string[16];
unsigned int profile_version;
controller_file.read(profile_string, 16);
controller_file.read((char *)&profile_version, sizeof(unsigned int));
/*---------------------------------------------------------*\
| Profile version started at 1 and protocol version started |
| at 0. Version 1 profiles should use protocol 0, but 2 or |
| greater should be synchronized |
\*---------------------------------------------------------*/
if(profile_version == 1)
{
profile_version = 0;
}
controller_offset += 16 + sizeof(unsigned int);
controller_file.seekg(controller_offset);
if(strcmp(profile_string, OPENRGB_PROFILE_HEADER) == 0)
{
if(profile_version <= OPENRGB_PROFILE_VERSION)
{
/*---------------------------------------------------------*\
| Read controller data from file until EOF |
\*---------------------------------------------------------*/
while(!(controller_file.peek() == EOF))
{
controller_file.read((char *)&controller_size, sizeof(controller_size));
unsigned char *controller_data = new unsigned char[controller_size];
controller_file.seekg(controller_offset);
controller_file.read((char *)controller_data, controller_size);
RGBController_Dummy *temp_controller = new RGBController_Dummy();
temp_controller->ReadDeviceDescription(controller_data, profile_version);
temp_controllers.push_back(temp_controller);
delete[] controller_data;
controller_offset += controller_size;
controller_file.seekg(controller_offset);
}
}
}
return(temp_controllers);
}
bool ProfileManager::LoadDeviceFromListWithOptions
(
std::vector<RGBController*>& temp_controllers,
std::vector<bool>& temp_controller_used,
RGBController* load_controller,
bool load_size,
bool load_settings
)
{
for(std::size_t temp_index = 0; temp_index < temp_controllers.size(); temp_index++)
{
RGBController *temp_controller = temp_controllers[temp_index];
/*---------------------------------------------------------*\
| Do not compare location string for HID devices, as the |
| location string may change between runs as devices are |
| connected and disconnected |
\*---------------------------------------------------------*/
bool compare_location = true;
if(load_controller->location.find("HID: ") == 0)
{
compare_location = false;
}
/*---------------------------------------------------------*\
| Test if saved controller data matches this controller |
\*---------------------------------------------------------*/
if((temp_controller_used[temp_index] == false )
&&(temp_controller->type == load_controller->type )
&&(temp_controller->name == load_controller->name )
&&(temp_controller->description == load_controller->description )
&&(temp_controller->version == load_controller->version )
&&(temp_controller->serial == load_controller->serial )
&&((temp_controller->location == load_controller->location ) || (!compare_location)))
{
/*---------------------------------------------------------*\
| Set used flag for this temp device |
\*---------------------------------------------------------*/
temp_controller_used[temp_index] = true;
/*---------------------------------------------------------*\
| Update zone sizes if requested |
\*---------------------------------------------------------*/
if(load_size)
{
if(temp_controller->zones.size() == load_controller->zones.size())
{
for(std::size_t zone_idx = 0; zone_idx < temp_controller->zones.size(); zone_idx++)
{
if((temp_controller->zones[zone_idx].name == load_controller->zones[zone_idx].name )
&&(temp_controller->zones[zone_idx].type == load_controller->zones[zone_idx].type )
&&(temp_controller->zones[zone_idx].leds_min == load_controller->zones[zone_idx].leds_min )
&&(temp_controller->zones[zone_idx].leds_max == load_controller->zones[zone_idx].leds_max )
&&(temp_controller->zones[zone_idx].leds_count != load_controller->zones[zone_idx].leds_count))
{
load_controller->ResizeZone(zone_idx, temp_controller->zones[zone_idx].leds_count);
}
}
}
}
/*---------------------------------------------------------*\
| Update settings if requested |
\*---------------------------------------------------------*/
if(load_settings)
{
/*---------------------------------------------------------*\
| Update all modes |
\*---------------------------------------------------------*/
if(temp_controller->modes.size() == load_controller->modes.size())
{
for(std::size_t mode_index = 0; mode_index < temp_controller->modes.size(); mode_index++)
{
if((temp_controller->modes[mode_index].name == load_controller->modes[mode_index].name )
&&(temp_controller->modes[mode_index].value == load_controller->modes[mode_index].value )
&&(temp_controller->modes[mode_index].flags == load_controller->modes[mode_index].flags )
&&(temp_controller->modes[mode_index].speed_min == load_controller->modes[mode_index].speed_min )
&&(temp_controller->modes[mode_index].speed_max == load_controller->modes[mode_index].speed_max )
//&&(temp_controller->modes[mode_index].brightness_min == load_controller->modes[mode_index].brightness_min)
//&&(temp_controller->modes[mode_index].brightness_max == load_controller->modes[mode_index].brightness_max)
&&(temp_controller->modes[mode_index].colors_min == load_controller->modes[mode_index].colors_min )
&&(temp_controller->modes[mode_index].colors_max == load_controller->modes[mode_index].colors_max ))
{
load_controller->modes[mode_index].speed = temp_controller->modes[mode_index].speed;
load_controller->modes[mode_index].brightness = temp_controller->modes[mode_index].brightness;
load_controller->modes[mode_index].direction = temp_controller->modes[mode_index].direction;
load_controller->modes[mode_index].color_mode = temp_controller->modes[mode_index].color_mode;
load_controller->modes[mode_index].colors.resize(temp_controller->modes[mode_index].colors.size());
for(std::size_t mode_color_index = 0; mode_color_index < temp_controller->modes[mode_index].colors.size(); mode_color_index++)
{
load_controller->modes[mode_index].colors[mode_color_index] = temp_controller->modes[mode_index].colors[mode_color_index];
}
}
}
load_controller->active_mode = temp_controller->active_mode;
}
/*---------------------------------------------------------*\
| Update all colors |
\*---------------------------------------------------------*/
if(temp_controller->colors.size() == load_controller->colors.size())
{
for(std::size_t color_index = 0; color_index < temp_controller->colors.size(); color_index++)
{
load_controller->colors[color_index] = temp_controller->colors[color_index];
}
}
}
return(true);
}
}
return(false);
}
bool ProfileManager::LoadProfileWithOptions
(
std::string profile_name,
bool load_size,
bool load_settings
)
{
std::vector<RGBController*> temp_controllers;
std::vector<bool> temp_controller_used;
bool ret_val = false;
/*---------------------------------------------------------*\
| Get the list of controllers from the resource manager |
\*---------------------------------------------------------*/
std::vector<RGBController *> controllers = ResourceManager::get()->GetRGBControllers();
/*---------------------------------------------------------*\
| Open input file in binary mode |
\*---------------------------------------------------------*/
temp_controllers = LoadProfileToList(profile_name);
/*---------------------------------------------------------*\
| Set up used flag vector |
\*---------------------------------------------------------*/
temp_controller_used.resize(temp_controllers.size());
for(unsigned int controller_idx = 0; controller_idx < temp_controller_used.size(); controller_idx++)
{
temp_controller_used[controller_idx] = false;
}
/*---------------------------------------------------------*\
| Loop through all controllers. For each controller, search|
| all saved controllers until a match is found |
\*---------------------------------------------------------*/
for(std::size_t controller_index = 0; controller_index < controllers.size(); controller_index++)
{
ret_val = LoadDeviceFromListWithOptions(temp_controllers, temp_controller_used, controllers[controller_index], load_size, load_settings);
std::string current_name = controllers[controller_index]->name + " @ " + controllers[controller_index]->location;
LOG_INFO("Profile loading: %s for %s", ( ret_val ? "Succeeded" : "FAILED!" ), current_name.c_str());
}
/*---------------------------------------------------------*\
| Delete all temporary controllers |
\*---------------------------------------------------------*/
for(unsigned int controller_idx = 0; controller_idx < temp_controllers.size(); controller_idx++)
{
delete temp_controllers[controller_idx];
}
return(ret_val);
}
void ProfileManager::DeleteProfile(std::string profile_name)
{
remove((configuration_directory + profile_name + ".orp").c_str());
UpdateProfileList();
}
void ProfileManager::UpdateProfileList()
{
profile_list.clear();
/*---------------------------------------------------------*\
| Load profiles by looking for .orp files in current dir |
\*---------------------------------------------------------*/
for(const auto & entry : filesystem::directory_iterator(configuration_directory))
{
std::string filename = entry.path().filename().string();
if(filename.find(".orp") != std::string::npos)
{
LOG_INFO("Found file: %s attempting to validate header", filename.c_str());
/*---------------------------------------------------------*\
| Open input file in binary mode |
\*---------------------------------------------------------*/
std::ifstream profile_file(configuration_directory + filename, std::ios::in | std::ios::binary);
/*---------------------------------------------------------*\
| Read and verify file header |
\*---------------------------------------------------------*/
char profile_string[16];
unsigned int profile_version;
profile_file.read(profile_string, 16);
profile_file.read((char *)&profile_version, sizeof(unsigned int));
if(strcmp(profile_string, OPENRGB_PROFILE_HEADER) == 0)
{
if(profile_version <= OPENRGB_PROFILE_VERSION)
{
/*---------------------------------------------------------*\
| Add this profile to the list |
\*---------------------------------------------------------*/
filename.erase(filename.length() - 4);
profile_list.push_back(filename);
LOG_INFO("Valid v%i profile found for %s", profile_version, filename.c_str());
}
else
{
LOG_WARNING("Profile %s isn't valid for current version (v%i, expected v%i at most)", filename.c_str(), profile_version, OPENRGB_PROFILE_VERSION);
}
}
else
{
LOG_WARNING("Profile %s isn't valid: header is missing", filename.c_str());
}
profile_file.close();
}
}
}
unsigned char * ProfileManager::GetProfileListDescription()
{
unsigned int data_ptr = 0;
unsigned int data_size = 0;
/*---------------------------------------------------------*\
| Calculate data size |
\*---------------------------------------------------------*/
unsigned short num_profiles = profile_list.size();
data_size += sizeof(data_size);
data_size += sizeof(num_profiles);
for(unsigned int i = 0; i < num_profiles; i++)
{
data_size += sizeof (unsigned short);
data_size += strlen(profile_list[i].c_str()) + 1;
}
/*---------------------------------------------------------*\
| Create data buffer |
\*---------------------------------------------------------*/
unsigned char *data_buf = new unsigned char[data_size];
/*---------------------------------------------------------*\
| Copy in data size |
\*---------------------------------------------------------*/
memcpy(&data_buf[data_ptr], &data_size, sizeof(data_size));
data_ptr += sizeof(data_size);
/*---------------------------------------------------------*\
| Copy in num_profiles |
\*---------------------------------------------------------*/
memcpy(&data_buf[data_ptr], &num_profiles, sizeof(num_profiles));
data_ptr += sizeof(num_profiles);
/*---------------------------------------------------------*\
| Copy in profile names (size+data) |
\*---------------------------------------------------------*/
for(unsigned int i = 0; i < num_profiles; i++)
{
unsigned short name_len = strlen(profile_list[i].c_str()) + 1;
memcpy(&data_buf[data_ptr], &name_len, sizeof(name_len));
data_ptr += sizeof(name_len);
strcpy((char *)&data_buf[data_ptr], profile_list[i].c_str());
data_ptr += name_len;
}
return(data_buf);
}