mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2025-12-23 23:37:48 -05:00
Add DDP (Distributed Display Protocol) controller support
This commit is contained in:
committed by
Adam Honse
parent
570cc16c98
commit
a31c4f5254
309
Controllers/DDPController/DDPController.cpp
Normal file
309
Controllers/DDPController/DDPController.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| DDPController.cpp |
|
||||
| |
|
||||
| Driver for DDP protocol devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "DDPController.h"
|
||||
#include "LogManager.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
DDPController::DDPController(const std::vector<DDPDevice>& device_list)
|
||||
{
|
||||
devices = device_list;
|
||||
unique_endpoints = NULL;
|
||||
num_endpoints = 0;
|
||||
sequence_number = 0;
|
||||
keepalive_time_ms = 1000;
|
||||
keepalive_thread_run = false;
|
||||
|
||||
InitializeNetPorts();
|
||||
|
||||
if(!devices.empty())
|
||||
{
|
||||
keepalive_thread_run = true;
|
||||
keepalive_thread = std::thread(&DDPController::KeepaliveThreadFunction, this);
|
||||
}
|
||||
}
|
||||
|
||||
DDPController::~DDPController()
|
||||
{
|
||||
keepalive_thread_run = false;
|
||||
if(keepalive_thread.joinable())
|
||||
{
|
||||
keepalive_thread.join();
|
||||
}
|
||||
|
||||
CloseNetPorts();
|
||||
if(unique_endpoints != NULL)
|
||||
{
|
||||
delete[] unique_endpoints;
|
||||
}
|
||||
}
|
||||
|
||||
bool DDPController::InitializeNetPorts()
|
||||
{
|
||||
if(devices.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
num_endpoints = 0;
|
||||
|
||||
for(unsigned int dev_idx = 0; dev_idx < devices.size(); dev_idx++)
|
||||
{
|
||||
bool found = false;
|
||||
for(unsigned int ep_idx = 0; ep_idx < num_endpoints; ep_idx++)
|
||||
{
|
||||
if(strcmp(unique_endpoints[ep_idx].ip, devices[dev_idx].ip.c_str()) == 0 &&
|
||||
unique_endpoints[ep_idx].port == devices[dev_idx].port)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
num_endpoints++;
|
||||
}
|
||||
}
|
||||
|
||||
unique_endpoints = new DDPEndpoint[num_endpoints];
|
||||
unsigned int endpoint_count = 0;
|
||||
|
||||
for(unsigned int dev_idx = 0; dev_idx < devices.size(); dev_idx++)
|
||||
{
|
||||
bool found = false;
|
||||
for(unsigned int ep_idx = 0; ep_idx < endpoint_count; ep_idx++)
|
||||
{
|
||||
if(strcmp(unique_endpoints[ep_idx].ip, devices[dev_idx].ip.c_str()) == 0 &&
|
||||
unique_endpoints[ep_idx].port == devices[dev_idx].port)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
strncpy(unique_endpoints[endpoint_count].ip, devices[dev_idx].ip.c_str(), 15);
|
||||
unique_endpoints[endpoint_count].ip[15] = '\0';
|
||||
unique_endpoints[endpoint_count].port = devices[dev_idx].port;
|
||||
endpoint_count++;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int ep_idx = 0; ep_idx < num_endpoints; ep_idx++)
|
||||
{
|
||||
net_port* port = new net_port();
|
||||
char port_str[16];
|
||||
snprintf(port_str, 16, "%d", unique_endpoints[ep_idx].port);
|
||||
|
||||
if(port->udp_client(unique_endpoints[ep_idx].ip, port_str))
|
||||
{
|
||||
udp_ports.push_back(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
udp_ports.push_back(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DDPController::CloseNetPorts()
|
||||
{
|
||||
for(unsigned int port_idx = 0; port_idx < udp_ports.size(); port_idx++)
|
||||
{
|
||||
if(udp_ports[port_idx] != NULL)
|
||||
{
|
||||
delete udp_ports[port_idx];
|
||||
}
|
||||
}
|
||||
udp_ports.clear();
|
||||
}
|
||||
|
||||
int DDPController::GetPortIndex(const DDPDevice& device)
|
||||
{
|
||||
for(unsigned int ep_idx = 0; ep_idx < num_endpoints; ep_idx++)
|
||||
{
|
||||
if(strcmp(unique_endpoints[ep_idx].ip, device.ip.c_str()) == 0 &&
|
||||
unique_endpoints[ep_idx].port == device.port)
|
||||
{
|
||||
return (int)ep_idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DDPController::UpdateLEDs(const std::vector<unsigned int>& colors)
|
||||
{
|
||||
if(udp_ports.empty()) return;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(last_update_mutex);
|
||||
last_colors = colors;
|
||||
last_update_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
unsigned int color_index = 0;
|
||||
|
||||
for(unsigned int dev_idx = 0; dev_idx < devices.size(); dev_idx++)
|
||||
{
|
||||
if(color_index >= colors.size()) break;
|
||||
|
||||
unsigned int bytes_per_pixel = 3;
|
||||
unsigned int total_bytes = devices[dev_idx].num_leds * bytes_per_pixel;
|
||||
std::vector<unsigned char> device_data(total_bytes);
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < devices[dev_idx].num_leds && (color_index + led_idx) < colors.size(); led_idx++)
|
||||
{
|
||||
unsigned int color = colors[color_index + led_idx];
|
||||
unsigned char r = color & 0xFF;
|
||||
unsigned char g = (color >> 8) & 0xFF;
|
||||
unsigned char b = (color >> 16) & 0xFF;
|
||||
unsigned int pixel_offset = led_idx * bytes_per_pixel;
|
||||
|
||||
device_data[pixel_offset + 0] = r;
|
||||
device_data[pixel_offset + 1] = g;
|
||||
device_data[pixel_offset + 2] = b;
|
||||
}
|
||||
|
||||
unsigned int max_data_per_packet = DDP_MAX_DATA_SIZE;
|
||||
unsigned int bytes_sent = 0;
|
||||
|
||||
while(bytes_sent < total_bytes)
|
||||
{
|
||||
unsigned int chunk_size = (max_data_per_packet < (total_bytes - bytes_sent)) ? max_data_per_packet : (total_bytes - bytes_sent);
|
||||
|
||||
if(!SendDDPPacket(devices[dev_idx], device_data.data() + bytes_sent, (unsigned short)chunk_size, bytes_sent))
|
||||
break;
|
||||
|
||||
bytes_sent += chunk_size;
|
||||
}
|
||||
|
||||
color_index += devices[dev_idx].num_leds;
|
||||
}
|
||||
|
||||
sequence_number++;
|
||||
}
|
||||
|
||||
bool DDPController::SendDDPPacket(const DDPDevice& device, const unsigned char* data, unsigned short length, unsigned int offset)
|
||||
{
|
||||
int port_index = GetPortIndex(device);
|
||||
if(port_index < 0 || port_index >= (int)udp_ports.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(udp_ports[port_index] == NULL)
|
||||
{
|
||||
net_port* port = new net_port();
|
||||
char port_str[16];
|
||||
snprintf(port_str, 16, "%d", unique_endpoints[port_index].port);
|
||||
|
||||
if(port->udp_client(unique_endpoints[port_index].ip, port_str))
|
||||
{
|
||||
udp_ports[port_index] = port;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete port;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> packet(DDP_HEADER_SIZE + length);
|
||||
ddp_header* header = (ddp_header*)packet.data();
|
||||
|
||||
header->flags = DDP_FLAG_VER_1 | DDP_FLAG_PUSH;
|
||||
header->sequence = sequence_number & 0x0F;
|
||||
header->data_type = 1;
|
||||
header->dest_id = 1;
|
||||
header->data_offset = htonl(offset);
|
||||
header->data_length = htons(length);
|
||||
|
||||
memcpy(packet.data() + DDP_HEADER_SIZE, data, length);
|
||||
|
||||
int bytes_sent = udp_ports[port_index]->udp_write((char*)packet.data(), (int)packet.size());
|
||||
|
||||
return bytes_sent == (int)packet.size();
|
||||
}
|
||||
|
||||
void DDPController::SetKeepaliveTime(unsigned int time_ms)
|
||||
{
|
||||
keepalive_time_ms = time_ms;
|
||||
}
|
||||
|
||||
void DDPController::KeepaliveThreadFunction()
|
||||
{
|
||||
while(keepalive_thread_run)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
if(keepalive_time_ms == 0)
|
||||
continue;
|
||||
|
||||
std::vector<unsigned int> colors_to_send;
|
||||
bool should_send = false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(last_update_mutex);
|
||||
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||
long long time_since_update = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update_time).count();
|
||||
|
||||
if(time_since_update >= keepalive_time_ms && !last_colors.empty())
|
||||
{
|
||||
colors_to_send = last_colors;
|
||||
should_send = true;
|
||||
last_update_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
if(should_send)
|
||||
{
|
||||
unsigned int color_index = 0;
|
||||
|
||||
for(unsigned int dev_idx = 0; dev_idx < devices.size(); dev_idx++)
|
||||
{
|
||||
if(color_index >= colors_to_send.size()) break;
|
||||
|
||||
unsigned int bytes_per_pixel = 3;
|
||||
unsigned int total_bytes = devices[dev_idx].num_leds * bytes_per_pixel;
|
||||
std::vector<unsigned char> device_data(total_bytes);
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < devices[dev_idx].num_leds && (color_index + led_idx) < colors_to_send.size(); led_idx++)
|
||||
{
|
||||
unsigned int color = colors_to_send[color_index + led_idx];
|
||||
unsigned char r = color & 0xFF;
|
||||
unsigned char g = (color >> 8) & 0xFF;
|
||||
unsigned char b = (color >> 16) & 0xFF;
|
||||
unsigned int pixel_offset = led_idx * bytes_per_pixel;
|
||||
|
||||
device_data[pixel_offset + 0] = r;
|
||||
device_data[pixel_offset + 1] = g;
|
||||
device_data[pixel_offset + 2] = b;
|
||||
}
|
||||
|
||||
unsigned int max_data_per_packet = DDP_MAX_DATA_SIZE;
|
||||
unsigned int bytes_sent = 0;
|
||||
|
||||
while(bytes_sent < total_bytes)
|
||||
{
|
||||
unsigned int chunk_size = (max_data_per_packet < (total_bytes - bytes_sent)) ? max_data_per_packet : (total_bytes - bytes_sent);
|
||||
|
||||
if(!SendDDPPacket(devices[dev_idx], device_data.data() + bytes_sent, (unsigned short)chunk_size, bytes_sent))
|
||||
break;
|
||||
|
||||
bytes_sent += chunk_size;
|
||||
}
|
||||
|
||||
color_index += devices[dev_idx].num_leds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
Controllers/DDPController/DDPController.h
Normal file
97
Controllers/DDPController/DDPController.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| DDPController.h |
|
||||
| |
|
||||
| Driver for DDP protocol devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include "net_port.h"
|
||||
|
||||
#define DDP_DEFAULT_PORT 4048
|
||||
#define DDP_HEADER_SIZE 10
|
||||
#define DDP_HEADER_SIZE_TC 14
|
||||
#define DDP_VERSION 1
|
||||
#define DDP_MAX_PACKET_SIZE 1450
|
||||
#define DDP_MAX_DATA_SIZE 1440
|
||||
|
||||
#define DDP_FLAG_VER_MASK 0xC0
|
||||
#define DDP_FLAG_VER_1 0x40
|
||||
#define DDP_FLAG_TIMECODE 0x10
|
||||
#define DDP_FLAG_STORAGE 0x08
|
||||
#define DDP_FLAG_REPLY 0x04
|
||||
#define DDP_FLAG_QUERY 0x02
|
||||
#define DDP_FLAG_PUSH 0x01
|
||||
|
||||
#define DDP_TYPE_RGB8 0x0B
|
||||
#define DDP_TYPE_RGB_SIMPLE 1
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ddp_header
|
||||
{
|
||||
unsigned char flags;
|
||||
unsigned char sequence;
|
||||
unsigned char data_type;
|
||||
unsigned char dest_id;
|
||||
unsigned int data_offset;
|
||||
unsigned short data_length;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct DDPDevice
|
||||
{
|
||||
std::string name;
|
||||
std::string ip;
|
||||
unsigned short port;
|
||||
unsigned int num_leds;
|
||||
};
|
||||
|
||||
struct DDPEndpoint
|
||||
{
|
||||
char ip[16];
|
||||
unsigned short port;
|
||||
};
|
||||
|
||||
class DDPController
|
||||
{
|
||||
public:
|
||||
DDPController(const std::vector<DDPDevice>& devices);
|
||||
~DDPController();
|
||||
|
||||
void UpdateLEDs(const std::vector<unsigned int>& colors);
|
||||
void SetKeepaliveTime(unsigned int time_ms);
|
||||
|
||||
private:
|
||||
std::vector<DDPDevice> devices;
|
||||
std::vector<net_port*> udp_ports;
|
||||
DDPEndpoint* unique_endpoints;
|
||||
unsigned int num_endpoints;
|
||||
unsigned char sequence_number;
|
||||
|
||||
|
||||
std::atomic<bool> keepalive_thread_run;
|
||||
std::thread keepalive_thread;
|
||||
std::mutex last_update_mutex;
|
||||
std::chrono::steady_clock::time_point last_update_time;
|
||||
std::vector<unsigned int> last_colors;
|
||||
unsigned int keepalive_time_ms;
|
||||
|
||||
bool InitializeNetPorts();
|
||||
void CloseNetPorts();
|
||||
int GetPortIndex(const DDPDevice& device);
|
||||
bool SendDDPPacket(const DDPDevice& device,
|
||||
const unsigned char* data,
|
||||
unsigned short length,
|
||||
unsigned int offset = 0);
|
||||
void KeepaliveThreadFunction();
|
||||
};
|
||||
92
Controllers/DDPController/DDPControllerDetect.cpp
Normal file
92
Controllers/DDPController/DDPControllerDetect.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| DDPControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for DDP devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Detector.h"
|
||||
#include "RGBController.h"
|
||||
#include "RGBController_DDP.h"
|
||||
#include "SettingsManager.h"
|
||||
#include "LogManager.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void DetectDDPControllers()
|
||||
{
|
||||
json ddp_settings;
|
||||
std::vector<std::vector<DDPDevice>> device_lists;
|
||||
DDPDevice dev;
|
||||
|
||||
ddp_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("DDPDevices");
|
||||
|
||||
if(ddp_settings.contains("devices"))
|
||||
{
|
||||
for(unsigned int device_idx = 0; device_idx < ddp_settings["devices"].size(); device_idx++)
|
||||
{
|
||||
dev.name = "";
|
||||
dev.ip = "";
|
||||
dev.port = DDP_DEFAULT_PORT;
|
||||
dev.num_leds = 0;
|
||||
|
||||
if(ddp_settings["devices"][device_idx].contains("name"))
|
||||
dev.name = ddp_settings["devices"][device_idx]["name"];
|
||||
if(ddp_settings["devices"][device_idx].contains("ip"))
|
||||
dev.ip = ddp_settings["devices"][device_idx]["ip"];
|
||||
if(ddp_settings["devices"][device_idx].contains("port"))
|
||||
dev.port = ddp_settings["devices"][device_idx]["port"];
|
||||
if(ddp_settings["devices"][device_idx].contains("num_leds"))
|
||||
dev.num_leds = ddp_settings["devices"][device_idx]["num_leds"];
|
||||
|
||||
if(dev.name.empty())
|
||||
dev.name = "DDP Device " + std::to_string(device_idx + 1);
|
||||
if(dev.ip.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(dev.num_leds == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool device_added_to_existing_list = false;
|
||||
|
||||
for(unsigned int list_idx = 0; list_idx < device_lists.size(); list_idx++)
|
||||
{
|
||||
for(unsigned int existing_device_idx = 0; existing_device_idx < device_lists[list_idx].size(); existing_device_idx++)
|
||||
{
|
||||
if(dev.ip == device_lists[list_idx][existing_device_idx].ip &&
|
||||
dev.port == device_lists[list_idx][existing_device_idx].port)
|
||||
{
|
||||
device_lists[list_idx].push_back(dev);
|
||||
device_added_to_existing_list = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(device_added_to_existing_list)
|
||||
break;
|
||||
}
|
||||
|
||||
if(!device_added_to_existing_list)
|
||||
{
|
||||
std::vector<DDPDevice> new_list;
|
||||
new_list.push_back(dev);
|
||||
device_lists.push_back(new_list);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int list_idx = 0; list_idx < device_lists.size(); list_idx++)
|
||||
{
|
||||
RGBController_DDP* rgb_controller = new RGBController_DDP(device_lists[list_idx]);
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_DETECTOR("DDP", DetectDDPControllers);
|
||||
136
Controllers/DDPController/RGBController_DDP.cpp
Normal file
136
Controllers/DDPController/RGBController_DDP.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_DDP.cpp |
|
||||
| |
|
||||
| RGBController for DDP devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "RGBController_DDP.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name DDP Devices
|
||||
@category LEDStrip
|
||||
@type Network
|
||||
@save :x:
|
||||
@direct :white_check_mark:
|
||||
@effects :x:
|
||||
@detectors DetectDDPControllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_DDP::RGBController_DDP(std::vector<DDPDevice> device_list)
|
||||
{
|
||||
devices = device_list;
|
||||
name = "DDP Device Group";
|
||||
type = DEVICE_TYPE_LEDSTRIP;
|
||||
description = "Distributed Display Protocol Device";
|
||||
location = "DDP: ";
|
||||
|
||||
if(devices.size() == 1)
|
||||
name = devices[0].name;
|
||||
else if(!devices[0].ip.empty())
|
||||
name += " (" + devices[0].ip + ")";
|
||||
|
||||
if(!devices[0].ip.empty())
|
||||
location += devices[0].ip + ":" + std::to_string(devices[0].port);
|
||||
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = 0;
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
Direct.brightness_min = 0;
|
||||
Direct.brightness_max = 100;
|
||||
Direct.brightness = 100;
|
||||
modes.push_back(Direct);
|
||||
|
||||
controller = new DDPController(devices);
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_DDP::~RGBController_DDP()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_DDP::SetupZones()
|
||||
{
|
||||
for(unsigned int zone_idx = 0; zone_idx < devices.size(); zone_idx++)
|
||||
{
|
||||
zone led_zone;
|
||||
led_zone.name = devices[zone_idx].name;
|
||||
led_zone.type = ZONE_TYPE_LINEAR;
|
||||
led_zone.leds_min = devices[zone_idx].num_leds;
|
||||
led_zone.leds_max = devices[zone_idx].num_leds;
|
||||
led_zone.leds_count = devices[zone_idx].num_leds;
|
||||
led_zone.matrix_map = NULL;
|
||||
zones.push_back(led_zone);
|
||||
}
|
||||
|
||||
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
|
||||
{
|
||||
for(unsigned int led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = zones[zone_idx].name + " LED " + std::to_string(led_idx + 1);
|
||||
new_led.value = 0;
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
}
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_DDP::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
}
|
||||
|
||||
void RGBController_DDP::DeviceUpdateLEDs()
|
||||
{
|
||||
std::vector<unsigned int> brightness_adjusted_colors;
|
||||
brightness_adjusted_colors.reserve(colors.size());
|
||||
float brightness_scale = (float)modes[active_mode].brightness / 100.0f;
|
||||
|
||||
for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++)
|
||||
{
|
||||
unsigned int color = colors[color_idx];
|
||||
unsigned char r = color & 0xFF;
|
||||
unsigned char g = (color >> 8) & 0xFF;
|
||||
unsigned char b = (color >> 16) & 0xFF;
|
||||
r = (unsigned char)(r * brightness_scale);
|
||||
g = (unsigned char)(g * brightness_scale);
|
||||
b = (unsigned char)(b * brightness_scale);
|
||||
unsigned int adjusted_color = r | (g << 8) | (b << 16);
|
||||
brightness_adjusted_colors.push_back(adjusted_color);
|
||||
}
|
||||
|
||||
controller->UpdateLEDs(brightness_adjusted_colors);
|
||||
}
|
||||
|
||||
void RGBController_DDP::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_DDP::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_DDP::DeviceUpdateMode()
|
||||
{
|
||||
}
|
||||
|
||||
void RGBController_DDP::SetCustomMode()
|
||||
{
|
||||
active_mode = 0;
|
||||
}
|
||||
|
||||
void RGBController_DDP::SetKeepaliveTime(unsigned int time_ms)
|
||||
{
|
||||
if(controller != nullptr)
|
||||
{
|
||||
controller->SetKeepaliveTime(time_ms);
|
||||
}
|
||||
}
|
||||
34
Controllers/DDPController/RGBController_DDP.h
Normal file
34
Controllers/DDPController/RGBController_DDP.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_DDP.h |
|
||||
| |
|
||||
| RGBController for DDP devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "RGBController.h"
|
||||
#include "DDPController.h"
|
||||
|
||||
class RGBController_DDP : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_DDP(std::vector<DDPDevice> device_list);
|
||||
~RGBController_DDP();
|
||||
|
||||
void SetupZones();
|
||||
void ResizeZone(int zone, int new_size);
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
void DeviceUpdateMode();
|
||||
void SetCustomMode();
|
||||
void SetKeepaliveTime(unsigned int time_ms);
|
||||
|
||||
private:
|
||||
std::vector<DDPDevice> devices;
|
||||
DDPController* controller;
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| DDPSettingsEntry.cpp |
|
||||
| |
|
||||
| User interface for OpenRGB DDP settings entry |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "DDPSettingsEntry.h"
|
||||
#include "ui_DDPSettingsEntry.h"
|
||||
#include "ManualDevicesTypeManager.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
DDPSettingsEntry::DDPSettingsEntry(QWidget *parent) :
|
||||
BaseManualDeviceEntry(parent),
|
||||
ui(new Ui::DDPSettingsEntry)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
DDPSettingsEntry::~DDPSettingsEntry()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DDPSettingsEntry::changeEvent(QEvent *event)
|
||||
{
|
||||
if(event->type() == QEvent::LanguageChange)
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
}
|
||||
|
||||
void DDPSettingsEntry::loadFromSettings(const json& data)
|
||||
{
|
||||
if(data.contains("name"))
|
||||
{
|
||||
ui->NameEdit->setText(QString::fromStdString(data["name"]));
|
||||
}
|
||||
|
||||
if(data.contains("ip"))
|
||||
{
|
||||
ui->IPEdit->setText(QString::fromStdString(data["ip"]));
|
||||
}
|
||||
|
||||
if(data.contains("port"))
|
||||
{
|
||||
ui->PortSpinBox->setValue(data["port"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->PortSpinBox->setValue(4048);
|
||||
}
|
||||
|
||||
if(data.contains("num_leds"))
|
||||
{
|
||||
ui->NumLedsSpinBox->setValue(data["num_leds"]);
|
||||
}
|
||||
|
||||
if(data.contains("keepalive_time"))
|
||||
{
|
||||
ui->KeepaliveTimeSpinBox->setValue(data["keepalive_time"]);
|
||||
}
|
||||
}
|
||||
|
||||
json DDPSettingsEntry::saveSettings()
|
||||
{
|
||||
json result;
|
||||
|
||||
result["name"] = ui->NameEdit->text().toStdString();
|
||||
result["ip"] = ui->IPEdit->text().toStdString();
|
||||
result["port"] = ui->PortSpinBox->value();
|
||||
result["num_leds"] = ui->NumLedsSpinBox->value();
|
||||
|
||||
if(ui->KeepaliveTimeSpinBox->value() > 0)
|
||||
{
|
||||
result["keepalive_time"] = ui->KeepaliveTimeSpinBox->value();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DDPSettingsEntry::isDataValid()
|
||||
{
|
||||
return !ui->IPEdit->text().isEmpty() && ui->NumLedsSpinBox->value() > 0;
|
||||
}
|
||||
|
||||
static BaseManualDeviceEntry* SpawnDDPEntry(const json& data)
|
||||
{
|
||||
DDPSettingsEntry* entry = new DDPSettingsEntry;
|
||||
entry->loadFromSettings(data);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static const char* DDPDeviceName = QT_TRANSLATE_NOOP("ManualDevice", "DDP (Distributed Display Protocol)");
|
||||
|
||||
REGISTER_MANUAL_DEVICE_TYPE(DDPDeviceName, "DDPDevices", SpawnDDPEntry);
|
||||
@@ -0,0 +1,35 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| DDPSettingsEntry.h |
|
||||
| |
|
||||
| User interface for OpenRGB DDP settings entry |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseManualDeviceEntry.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class DDPSettingsEntry;
|
||||
}
|
||||
|
||||
class DDPSettingsEntry : public BaseManualDeviceEntry
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DDPSettingsEntry(QWidget *parent = nullptr);
|
||||
~DDPSettingsEntry();
|
||||
void loadFromSettings(const json& data);
|
||||
json saveSettings() override;
|
||||
bool isDataValid() override;
|
||||
|
||||
private:
|
||||
Ui::DDPSettingsEntry *ui;
|
||||
|
||||
private slots:
|
||||
void changeEvent(QEvent *event) override;
|
||||
};
|
||||
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DDPSettingsEntry</class>
|
||||
<widget class="QWidget" name="DDPSettingsEntry">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>200</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">DDP Settings Entry</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>DDP Device</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="IPLabel">
|
||||
<property name="text">
|
||||
<string>IP Address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="IPEdit">
|
||||
<property name="placeholderText">
|
||||
<string>192.168.1.100</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="NameLabel">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="NameEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Device Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="PortLabel">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="PortSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4048</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="NumLedsLabel">
|
||||
<property name="text">
|
||||
<string>Number of LEDs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="NumLedsSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="KeepaliveTimeLabel">
|
||||
<property name="text">
|
||||
<string>Keepalive Time (ms):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="KeepaliveTimeSpinBox">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="specialValueText">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user