mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-07-29 14:36:06 -04:00
Added all Skydimo Serial and HID devices
This commit is contained in:
118
Controllers/SkydimoHIDController/RGBController_SkydimoHID.cpp
Normal file
118
Controllers/SkydimoHIDController/RGBController_SkydimoHID.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_SkydimoHID.cpp |
|
||||
| |
|
||||
| RGBController for Skydimo HID devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 09 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "RGBController_SkydimoHID.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Skydimo SK0902
|
||||
@category HeadsetStand
|
||||
@type USB
|
||||
@save :x:
|
||||
@direct :white_check_mark:
|
||||
@effects :x:
|
||||
@detectors DetectSkydimoHIDControllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
static const unsigned int skydimo_hid_led_positions[SKYDIMO_HID_LED_COUNT][2] =
|
||||
{
|
||||
{0, 6}, {0, 5}, {0, 4}, {0, 3}, {0, 2}, {0, 1}, {0, 0},
|
||||
{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6},
|
||||
{2, 6}, {2, 5}, {2, 4}, {2, 3}, {2, 2}, {2, 1}, {2, 0},
|
||||
{3, 0}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6},
|
||||
{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0},
|
||||
{5, 0}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {5, 6},
|
||||
{6, 6}, {6, 5}, {6, 4}, {6, 3}, {6, 2}, {6, 1}, {6, 0}
|
||||
};
|
||||
|
||||
RGBController_SkydimoHID::RGBController_SkydimoHID(SkydimoHIDController* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = controller->GetDeviceName();
|
||||
vendor = "Skydimo";
|
||||
type = DEVICE_TYPE_HEADSET_STAND;
|
||||
description = "Skydimo HID Device";
|
||||
serial = controller->GetSerial();
|
||||
location = controller->GetLocation();
|
||||
|
||||
mode direct_mode;
|
||||
direct_mode.name = "Direct";
|
||||
direct_mode.value = 0;
|
||||
direct_mode.flags = MODE_FLAG_HAS_PER_LED_COLOR;
|
||||
direct_mode.color_mode = MODE_COLORS_PER_LED;
|
||||
modes.push_back(direct_mode);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_SkydimoHID::~RGBController_SkydimoHID()
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_SkydimoHID::SetupZones()
|
||||
{
|
||||
zone led_zone;
|
||||
led_zone.name = "Matrix";
|
||||
led_zone.type = ZONE_TYPE_MATRIX;
|
||||
led_zone.leds_min = SKYDIMO_HID_LED_COUNT;
|
||||
led_zone.leds_max = SKYDIMO_HID_LED_COUNT;
|
||||
led_zone.leds_count = SKYDIMO_HID_LED_COUNT;
|
||||
|
||||
led_zone.matrix_map.height = SKYDIMO_HID_MATRIX_SIZE;
|
||||
led_zone.matrix_map.width = SKYDIMO_HID_MATRIX_SIZE;
|
||||
led_zone.matrix_map.map.assign(SKYDIMO_HID_MATRIX_SIZE * SKYDIMO_HID_MATRIX_SIZE, SKYDIMO_HID_MATRIX_NA);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Construct the matrix map |
|
||||
\*-----------------------------------------------------*/
|
||||
for(unsigned int led_idx = 0; led_idx < SKYDIMO_HID_LED_COUNT; led_idx++)
|
||||
{
|
||||
unsigned int column = skydimo_hid_led_positions[led_idx][0];
|
||||
unsigned int row = skydimo_hid_led_positions[led_idx][1];
|
||||
|
||||
led_zone.matrix_map.map[(row * SKYDIMO_HID_MATRIX_SIZE) + column] = led_idx;
|
||||
}
|
||||
|
||||
zones.push_back(led_zone);
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < SKYDIMO_HID_LED_COUNT; led_idx++)
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = "LED " + std::to_string(led_idx + 1);
|
||||
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_SkydimoHID::DeviceUpdateLEDs()
|
||||
{
|
||||
controller->SetLEDs(colors);
|
||||
}
|
||||
|
||||
void RGBController_SkydimoHID::DeviceUpdateZoneLEDs(int)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_SkydimoHID::DeviceUpdateSingleLED(int)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_SkydimoHID::DeviceUpdateMode()
|
||||
{
|
||||
}
|
||||
32
Controllers/SkydimoHIDController/RGBController_SkydimoHID.h
Normal file
32
Controllers/SkydimoHIDController/RGBController_SkydimoHID.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_SkydimoHID.h |
|
||||
| |
|
||||
| RGBController for Skydimo HID devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 09 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "SkydimoHIDController.h"
|
||||
|
||||
class RGBController_SkydimoHID : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_SkydimoHID(SkydimoHIDController* controller_ptr);
|
||||
~RGBController_SkydimoHID();
|
||||
|
||||
void SetupZones();
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void DeviceUpdateZoneLEDs(int zone);
|
||||
void DeviceUpdateSingleLED(int led);
|
||||
void DeviceUpdateMode();
|
||||
|
||||
private:
|
||||
SkydimoHIDController* controller;
|
||||
};
|
||||
195
Controllers/SkydimoHIDController/SkydimoHIDController.cpp
Normal file
195
Controllers/SkydimoHIDController/SkydimoHIDController.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SkydimoHIDController.cpp |
|
||||
| |
|
||||
| Driver for Skydimo HID devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 09 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include "LogManager.h"
|
||||
#include "SkydimoHIDController.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
static unsigned char CalculateCRC8(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
unsigned char crc = 0x00;
|
||||
|
||||
for(unsigned int byte_idx = 0; byte_idx < length; byte_idx++)
|
||||
{
|
||||
crc ^= data[byte_idx];
|
||||
|
||||
for(unsigned int bit_idx = 0; bit_idx < SKYDIMO_HID_CRC_BIT_COUNT; bit_idx++)
|
||||
{
|
||||
if(crc & SKYDIMO_HID_CRC_HIGH_BIT)
|
||||
{
|
||||
crc = (unsigned char)((crc << 1) ^ SKYDIMO_HID_CRC_POLYNOMIAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = (unsigned char)(crc << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(crc);
|
||||
}
|
||||
|
||||
SkydimoHIDController::SkydimoHIDController(hid_device* dev_handle, const char* path)
|
||||
{
|
||||
dev = dev_handle;
|
||||
location = path;
|
||||
|
||||
wchar_t name_string[SKYDIMO_HID_NAME_BUFFER_SIZE];
|
||||
int result;
|
||||
|
||||
result = hid_get_manufacturer_string(dev, name_string, SKYDIMO_HID_NAME_BUFFER_SIZE);
|
||||
if(result == 0)
|
||||
{
|
||||
device_name = StringUtils::wstring_to_string(name_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
device_name = "Skydimo";
|
||||
LOG_WARNING("[SkydimoHIDController] Failed to read manufacturer string for %s", path);
|
||||
}
|
||||
|
||||
result = hid_get_product_string(dev, name_string, SKYDIMO_HID_NAME_BUFFER_SIZE);
|
||||
if(result == 0)
|
||||
{
|
||||
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
|
||||
}
|
||||
else
|
||||
{
|
||||
device_name.append(" HID Device");
|
||||
LOG_WARNING("[SkydimoHIDController] Failed to read product string for %s", path);
|
||||
}
|
||||
|
||||
wchar_t serial_string[SKYDIMO_HID_SERIAL_BUFFER_SIZE];
|
||||
result = hid_get_serial_number_string(dev, serial_string, SKYDIMO_HID_SERIAL_BUFFER_SIZE);
|
||||
if(result == 0)
|
||||
{
|
||||
serial = StringUtils::wstring_to_string(serial_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
serial = "";
|
||||
LOG_DEBUG("[SkydimoHIDController] No serial number available for %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
SkydimoHIDController::~SkydimoHIDController()
|
||||
{
|
||||
if(dev)
|
||||
{
|
||||
hid_close(dev);
|
||||
}
|
||||
}
|
||||
|
||||
std::string SkydimoHIDController::GetDeviceName() const
|
||||
{
|
||||
return(device_name);
|
||||
}
|
||||
|
||||
std::string SkydimoHIDController::GetSerial() const
|
||||
{
|
||||
return(serial);
|
||||
}
|
||||
|
||||
std::string SkydimoHIDController::GetLocation() const
|
||||
{
|
||||
return("HID: " + location);
|
||||
}
|
||||
|
||||
bool SkydimoHIDController::SendPacket(unsigned char start_led, const unsigned char* chunk, unsigned int chunk_length)
|
||||
{
|
||||
unsigned char packet[SKYDIMO_HID_PACKET_SIZE];
|
||||
memset(packet, 0x00, sizeof(packet));
|
||||
|
||||
packet[0] = SKYDIMO_HID_REPORT_ID;
|
||||
packet[SKYDIMO_HID_PACKET_START_LED_INDEX] = start_led;
|
||||
packet[SKYDIMO_HID_PACKET_RESERVED_INDEX] = 0x00;
|
||||
|
||||
if(chunk_length > SKYDIMO_HID_PACKET_DATA_SIZE)
|
||||
{
|
||||
chunk_length = SKYDIMO_HID_PACKET_DATA_SIZE;
|
||||
}
|
||||
|
||||
memcpy(&packet[SKYDIMO_HID_PACKET_DATA_OFFSET], chunk, chunk_length);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Calculate CRC8 over all bytes before the checksum |
|
||||
\*-----------------------------------------------------*/
|
||||
packet[SKYDIMO_HID_PACKET_SIZE - 1] = CalculateCRC8(packet, SKYDIMO_HID_PACKET_SIZE - 1);
|
||||
|
||||
int bytes_written = hid_write(dev, packet, SKYDIMO_HID_PACKET_SIZE);
|
||||
|
||||
if(bytes_written != SKYDIMO_HID_PACKET_SIZE)
|
||||
{
|
||||
LOG_ERROR("[SkydimoHIDController] Failed to write RGB packet at LED %u (%d/%u bytes): %ls",
|
||||
(unsigned int)start_led, bytes_written, (unsigned int)SKYDIMO_HID_PACKET_SIZE, hid_error(dev));
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void SkydimoHIDController::SetLEDs(const std::vector<RGBColor>& colors)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(device_mutex);
|
||||
|
||||
unsigned char frame_data[SKYDIMO_HID_FRAME_SIZE];
|
||||
memset(frame_data, 0, sizeof(frame_data));
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Convert colors to GRB format |
|
||||
\*-----------------------------------------------------*/
|
||||
for(unsigned int led_idx = 0; (led_idx < colors.size()) && (led_idx < SKYDIMO_HID_LED_COUNT); led_idx++)
|
||||
{
|
||||
unsigned int color_offset = led_idx * SKYDIMO_HID_BYTES_PER_LED;
|
||||
|
||||
frame_data[color_offset + 0] = RGBGetGValue(colors[led_idx]);
|
||||
frame_data[color_offset + 1] = RGBGetRValue(colors[led_idx]);
|
||||
frame_data[color_offset + 2] = RGBGetBValue(colors[led_idx]);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Send the frame in packet-sized chunks |
|
||||
\*-----------------------------------------------------*/
|
||||
for(unsigned int frame_offset = 0; frame_offset < SKYDIMO_HID_FRAME_SIZE; frame_offset += SKYDIMO_HID_PACKET_DATA_SIZE)
|
||||
{
|
||||
unsigned int bytes_remaining = SKYDIMO_HID_FRAME_SIZE - frame_offset;
|
||||
unsigned int chunk_length = (bytes_remaining < SKYDIMO_HID_PACKET_DATA_SIZE)
|
||||
? bytes_remaining
|
||||
: SKYDIMO_HID_PACKET_DATA_SIZE;
|
||||
unsigned char start_led = (unsigned char)(frame_offset / SKYDIMO_HID_BYTES_PER_LED);
|
||||
|
||||
if(!SendPacket(start_led, &frame_data[frame_offset], chunk_length))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Send the frame-end packet |
|
||||
\*-----------------------------------------------------*/
|
||||
unsigned char end_packet[SKYDIMO_HID_PACKET_SIZE];
|
||||
memset(end_packet, 0x00, sizeof(end_packet));
|
||||
|
||||
end_packet[0] = SKYDIMO_HID_REPORT_ID;
|
||||
end_packet[SKYDIMO_HID_END_COMMAND_INDEX] = SKYDIMO_HID_END_COMMAND_VALUE;
|
||||
end_packet[SKYDIMO_HID_END_SUBCOMMAND_INDEX] = SKYDIMO_HID_END_SUBCOMMAND_VALUE;
|
||||
end_packet[SKYDIMO_HID_END_LED_COUNT_INDEX] = SKYDIMO_HID_LED_COUNT;
|
||||
end_packet[SKYDIMO_HID_END_MARKER_INDEX] = SKYDIMO_HID_END_MARKER_VALUE;
|
||||
|
||||
int bytes_written = hid_write(dev, end_packet, SKYDIMO_HID_PACKET_SIZE);
|
||||
|
||||
if(bytes_written != SKYDIMO_HID_PACKET_SIZE)
|
||||
{
|
||||
LOG_ERROR("[SkydimoHIDController] Failed to write frame-end packet (%d/%u bytes): %ls",
|
||||
bytes_written, (unsigned int)SKYDIMO_HID_PACKET_SIZE, hid_error(dev));
|
||||
}
|
||||
}
|
||||
64
Controllers/SkydimoHIDController/SkydimoHIDController.h
Normal file
64
Controllers/SkydimoHIDController/SkydimoHIDController.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SkydimoHIDController.h |
|
||||
| |
|
||||
| Driver for Skydimo HID devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 09 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <hidapi.h>
|
||||
#include "RGBControllerInterface.h"
|
||||
|
||||
#define SKYDIMO_HID_LED_COUNT 49
|
||||
#define SKYDIMO_HID_MATRIX_SIZE 7
|
||||
#define SKYDIMO_HID_BYTES_PER_LED 3
|
||||
#define SKYDIMO_HID_FRAME_SIZE (SKYDIMO_HID_LED_COUNT * SKYDIMO_HID_BYTES_PER_LED)
|
||||
#define SKYDIMO_HID_PACKET_SIZE 64
|
||||
#define SKYDIMO_HID_PACKET_DATA_SIZE 60
|
||||
#define SKYDIMO_HID_PACKET_DATA_OFFSET 3
|
||||
#define SKYDIMO_HID_REPORT_ID 0x01
|
||||
#define SKYDIMO_HID_PACKET_START_LED_INDEX 1
|
||||
#define SKYDIMO_HID_PACKET_RESERVED_INDEX 2
|
||||
#define SKYDIMO_HID_MATRIX_NA 0xFFFFFFFF
|
||||
#define SKYDIMO_HID_CRC_POLYNOMIAL 0x07
|
||||
#define SKYDIMO_HID_CRC_HIGH_BIT 0x80
|
||||
#define SKYDIMO_HID_CRC_BIT_COUNT 8
|
||||
#define SKYDIMO_HID_NAME_BUFFER_SIZE 255
|
||||
#define SKYDIMO_HID_SERIAL_BUFFER_SIZE 128
|
||||
#define SKYDIMO_HID_END_MARKER_INDEX 60
|
||||
#define SKYDIMO_HID_END_MARKER_VALUE 0x1E
|
||||
#define SKYDIMO_HID_END_COMMAND_INDEX 1
|
||||
#define SKYDIMO_HID_END_COMMAND_VALUE 0xFF
|
||||
#define SKYDIMO_HID_END_SUBCOMMAND_INDEX 2
|
||||
#define SKYDIMO_HID_END_SUBCOMMAND_VALUE 0xFF
|
||||
#define SKYDIMO_HID_END_LED_COUNT_INDEX 3
|
||||
|
||||
class SkydimoHIDController
|
||||
{
|
||||
public:
|
||||
SkydimoHIDController(hid_device* dev_handle, const char* path);
|
||||
~SkydimoHIDController();
|
||||
|
||||
std::string GetDeviceName() const;
|
||||
std::string GetSerial() const;
|
||||
std::string GetLocation() const;
|
||||
|
||||
void SetLEDs(const std::vector<RGBColor>& colors);
|
||||
|
||||
private:
|
||||
hid_device* dev;
|
||||
std::string device_name;
|
||||
std::string serial;
|
||||
std::string location;
|
||||
std::mutex device_mutex;
|
||||
|
||||
bool SendPacket(unsigned char start_led, const unsigned char* chunk, unsigned int chunk_length);
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SkydimoHIDControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for Skydimo HID devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 09 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <hidapi.h>
|
||||
#include "DetectionManager.h"
|
||||
#include "LogManager.h"
|
||||
#include "RGBController_SkydimoHID.h"
|
||||
#include "SkydimoHIDController.h"
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Skydimo HID vendor and product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define SKYDIMO_VID 0x1A86
|
||||
#define SKYDIMO_SK0902_PID 0xE316
|
||||
#define SKYDIMO_SK0902_INTERFACE 0
|
||||
#define SKYDIMO_SK0902_USAGE_PAGE 0xFF00
|
||||
#define SKYDIMO_SK0902_USAGE 0x01
|
||||
|
||||
DetectedControllers DetectSkydimoHIDControllers(hid_device_info* info, const std::string&)
|
||||
{
|
||||
DetectedControllers detected_controllers;
|
||||
hid_device* dev;
|
||||
|
||||
dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
SkydimoHIDController* controller = new SkydimoHIDController(dev, info->path);
|
||||
RGBController_SkydimoHID* rgb_controller = new RGBController_SkydimoHID(controller);
|
||||
|
||||
detected_controllers.push_back(rgb_controller);
|
||||
LOG_INFO("[SkydimoHIDControllerDetect] Detected Skydimo SK0902 at %s", info->path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("[SkydimoHIDControllerDetect] Failed to open Skydimo SK0902 at %s", info->path);
|
||||
}
|
||||
|
||||
return(detected_controllers);
|
||||
}
|
||||
|
||||
REGISTER_HID_DETECTOR_IPU("Skydimo SK0902", DetectSkydimoHIDControllers, SKYDIMO_VID, SKYDIMO_SK0902_PID, SKYDIMO_SK0902_INTERFACE, SKYDIMO_SK0902_USAGE_PAGE, SKYDIMO_SK0902_USAGE);
|
||||
@@ -0,0 +1,147 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_SkydimoSerial.cpp |
|
||||
| |
|
||||
| RGBController for Skydimo serial devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 30 Jun 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "RGBController_SkydimoSerial.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Skydimo Serial
|
||||
@category LEDStrip
|
||||
@type Serial
|
||||
@save :x:
|
||||
@direct :white_check_mark:
|
||||
@effects :x:
|
||||
@detectors DetectSkydimoSerialControllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_SkydimoSerial::RGBController_SkydimoSerial(SkydimoSerialController* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = controller->GetName();
|
||||
vendor = "Skydimo";
|
||||
type = DEVICE_TYPE_LEDSTRIP;
|
||||
description = "Skydimo Serial Device";
|
||||
serial = controller->GetSerial();
|
||||
location = controller->GetLocation();
|
||||
|
||||
mode direct_mode;
|
||||
direct_mode.name = "Direct";
|
||||
direct_mode.value = 0;
|
||||
direct_mode.flags = MODE_FLAG_HAS_PER_LED_COLOR;
|
||||
direct_mode.color_mode = MODE_COLORS_PER_LED;
|
||||
modes.push_back(direct_mode);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_SkydimoSerial::~RGBController_SkydimoSerial()
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
controller->SetBlack();
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_SkydimoSerial::SetupZones()
|
||||
{
|
||||
bool first_run = zones.empty();
|
||||
|
||||
leds.clear();
|
||||
colors.clear();
|
||||
zones.resize(1);
|
||||
|
||||
zones[0].leds_min = controller->GetMinLEDCount();
|
||||
zones[0].leds_max = controller->GetMaxLEDCount();
|
||||
|
||||
if(first_run)
|
||||
{
|
||||
if(controller->IsResizable())
|
||||
{
|
||||
zones[0].flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_SIZE
|
||||
| ZONE_FLAG_MANUALLY_CONFIGURABLE_NAME
|
||||
| ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE
|
||||
| ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP
|
||||
| ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS;
|
||||
}
|
||||
}
|
||||
|
||||
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_NAME))
|
||||
{
|
||||
zones[0].name = "Output 1";
|
||||
}
|
||||
|
||||
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_SIZE))
|
||||
{
|
||||
zones[0].leds_count = controller->GetLEDCount();
|
||||
}
|
||||
|
||||
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_TYPE))
|
||||
{
|
||||
zones[0].type = controller->GetMatrixMap().empty() ? ZONE_TYPE_LINEAR : ZONE_TYPE_MATRIX;
|
||||
}
|
||||
|
||||
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP))
|
||||
{
|
||||
zones[0].matrix_map.height = controller->GetMatrixHeight();
|
||||
zones[0].matrix_map.width = controller->GetMatrixWidth();
|
||||
zones[0].matrix_map.map = controller->GetMatrixMap();
|
||||
}
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < zones[0].leds_count; led_idx++)
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = zones[0].name + ", LED " + std::to_string(led_idx + 1);
|
||||
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_SkydimoSerial::DeviceConfigureZone(int zone_idx)
|
||||
{
|
||||
unsigned int zone_index = (unsigned int)zone_idx;
|
||||
|
||||
if(zone_index < zones.size())
|
||||
{
|
||||
if(zones[zone_index].flags & ZONE_FLAG_MANUALLY_CONFIGURED_SIZE)
|
||||
{
|
||||
controller->SetLEDCount(zones[zone_index].leds_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
controller->SetLEDCount(controller->GetMinLEDCount());
|
||||
}
|
||||
|
||||
zones[zone_index].leds_count = controller->GetLEDCount();
|
||||
SetupZones();
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_SkydimoSerial::DeviceUpdateLEDs()
|
||||
{
|
||||
controller->SetLEDs(colors);
|
||||
}
|
||||
|
||||
void RGBController_SkydimoSerial::DeviceUpdateZoneLEDs(int)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_SkydimoSerial::DeviceUpdateSingleLED(int)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_SkydimoSerial::DeviceUpdateMode()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_SkydimoSerial.h |
|
||||
| |
|
||||
| RGBController for Skydimo serial devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 30 Jun 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "SkydimoSerialController.h"
|
||||
|
||||
class RGBController_SkydimoSerial : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_SkydimoSerial(SkydimoSerialController* controller_ptr);
|
||||
~RGBController_SkydimoSerial();
|
||||
|
||||
void SetupZones();
|
||||
void DeviceConfigureZone(int zone_idx);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void DeviceUpdateZoneLEDs(int zone);
|
||||
void DeviceUpdateSingleLED(int led);
|
||||
void DeviceUpdateMode();
|
||||
|
||||
private:
|
||||
SkydimoSerialController* controller;
|
||||
};
|
||||
548
Controllers/SkydimoSerialController/SkydimoSerialController.cpp
Normal file
548
Controllers/SkydimoSerialController/SkydimoSerialController.cpp
Normal file
@@ -0,0 +1,548 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SkydimoSerialController.cpp |
|
||||
| |
|
||||
| Driver for Skydimo serial devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 30 Jun 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include "LogManager.h"
|
||||
#include "SkydimoSerialController.h"
|
||||
|
||||
enum SkydimoLayoutKind
|
||||
{
|
||||
SKYDIMO_LAYOUT_NONE,
|
||||
SKYDIMO_LAYOUT_STRIP_1,
|
||||
SKYDIMO_LAYOUT_PERIMETER_3,
|
||||
SKYDIMO_LAYOUT_PERIMETER_4,
|
||||
SKYDIMO_LAYOUT_SIDES_2
|
||||
};
|
||||
|
||||
struct SkydimoModelEntry
|
||||
{
|
||||
const char* model;
|
||||
SkydimoLayoutKind layout;
|
||||
unsigned int zone_leds[4];
|
||||
unsigned int total_leds;
|
||||
unsigned int max_leds;
|
||||
};
|
||||
|
||||
static const SkydimoModelEntry skydimo_model_entries[] =
|
||||
{
|
||||
{ "SK0121", SKYDIMO_LAYOUT_PERIMETER_3, { 13, 25, 13, 0 }, 51, 0 },
|
||||
{ "SK0124", SKYDIMO_LAYOUT_PERIMETER_3, { 14, 26, 14, 0 }, 54, 0 },
|
||||
{ "SK0127", SKYDIMO_LAYOUT_PERIMETER_3, { 17, 31, 17, 0 }, 65, 0 },
|
||||
{ "SK0132", SKYDIMO_LAYOUT_PERIMETER_3, { 20, 37, 20, 0 }, 77, 0 },
|
||||
{ "SK0134", SKYDIMO_LAYOUT_PERIMETER_3, { 15, 41, 15, 0 }, 71, 0 },
|
||||
{ "SK0149", SKYDIMO_LAYOUT_PERIMETER_3, { 19, 69, 19, 0 }, 107, 0 },
|
||||
{ "SK0201", SKYDIMO_LAYOUT_SIDES_2, { 20, 20, 0, 0 }, 40, 0 },
|
||||
{ "SK0202", SKYDIMO_LAYOUT_SIDES_2, { 30, 30, 0, 0 }, 60, 0 },
|
||||
{ "SK0204", SKYDIMO_LAYOUT_SIDES_2, { 25, 25, 0, 0 }, 50, 0 },
|
||||
{ "SK0402", SKYDIMO_LAYOUT_STRIP_1, { 72, 0, 0, 0 }, 72, 0 },
|
||||
{ "SK0403", SKYDIMO_LAYOUT_STRIP_1, { 96, 0, 0, 0 }, 96, 0 },
|
||||
{ "SK0404", SKYDIMO_LAYOUT_STRIP_1, { 144, 0, 0, 0 }, 144, 0 },
|
||||
{ "SK0410", SKYDIMO_LAYOUT_NONE, { 0, 0, 0, 0 }, 0, 300 },
|
||||
{ "SK0801", SKYDIMO_LAYOUT_STRIP_1, { 2, 0, 0, 0 }, 2, 0 },
|
||||
{ "SK0802", SKYDIMO_LAYOUT_STRIP_1, { 18, 0, 0, 0 }, 18, 0 },
|
||||
{ "SK0803", SKYDIMO_LAYOUT_STRIP_1, { 10, 0, 0, 0 }, 10, 0 },
|
||||
{ "SK0901", SKYDIMO_LAYOUT_STRIP_1, { 14, 0, 0, 0 }, 14, 0 },
|
||||
{ "SK0E01", SKYDIMO_LAYOUT_STRIP_1, { 16, 0, 0, 0 }, 16, 0 },
|
||||
{ "SK0F01", SKYDIMO_LAYOUT_SIDES_2, { 29, 29, 0, 0 }, 58, 0 },
|
||||
{ "SK0F02", SKYDIMO_LAYOUT_SIDES_2, { 25, 25, 0, 0 }, 50, 0 },
|
||||
{ "SK0H01", SKYDIMO_LAYOUT_STRIP_1, { 2, 0, 0, 0 }, 2, 0 },
|
||||
{ "SK0H02", SKYDIMO_LAYOUT_STRIP_1, { 4, 0, 0, 0 }, 4, 0 },
|
||||
{ "SK0K01", SKYDIMO_LAYOUT_STRIP_1, { 120, 0, 0, 0 }, 120, 0 },
|
||||
{ "SK0K02", SKYDIMO_LAYOUT_STRIP_1, { 15, 0, 0, 0 }, 15, 0 },
|
||||
{ "SK0L21", SKYDIMO_LAYOUT_PERIMETER_4, { 13, 25, 13, 25 }, 76, 0 },
|
||||
{ "SK0L24", SKYDIMO_LAYOUT_PERIMETER_4, { 14, 26, 14, 26 }, 80, 0 },
|
||||
{ "SK0L27", SKYDIMO_LAYOUT_PERIMETER_4, { 17, 31, 17, 31 }, 96, 0 },
|
||||
{ "SK0L32", SKYDIMO_LAYOUT_PERIMETER_4, { 20, 37, 20, 37 }, 114, 0 },
|
||||
{ "SK0L34", SKYDIMO_LAYOUT_PERIMETER_4, { 15, 41, 15, 41 }, 112, 0 },
|
||||
{ "SK0M01", SKYDIMO_LAYOUT_STRIP_1, { 24, 0, 0, 0 }, 24, 0 },
|
||||
{ "SK0N01", SKYDIMO_LAYOUT_STRIP_1, { 256, 0, 0, 0 }, 256, 0 },
|
||||
{ "SK0N02", SKYDIMO_LAYOUT_STRIP_1, { 1024, 0, 0, 0 }, 1024, 0 },
|
||||
{ "SK0N03", SKYDIMO_LAYOUT_STRIP_1, { 253, 0, 0, 0 }, 253, 0 },
|
||||
{ "SK0S01", SKYDIMO_LAYOUT_STRIP_1, { 32, 0, 0, 0 }, 32, 0 },
|
||||
{ "SKA124", SKYDIMO_LAYOUT_PERIMETER_3, { 18, 34, 18, 0 }, 70, 0 },
|
||||
{ "SKA127", SKYDIMO_LAYOUT_PERIMETER_3, { 20, 41, 20, 0 }, 81, 0 },
|
||||
{ "SKA132", SKYDIMO_LAYOUT_PERIMETER_3, { 25, 45, 25, 0 }, 95, 0 },
|
||||
{ "SKA134", SKYDIMO_LAYOUT_PERIMETER_3, { 21, 51, 21, 0 }, 93, 0 },
|
||||
{ "SKB124", SKYDIMO_LAYOUT_PERIMETER_4, { 18, 34, 18, 34 }, 104, 0 },
|
||||
{ "SKB127", SKYDIMO_LAYOUT_PERIMETER_4, { 20, 41, 20, 41 }, 122, 0 },
|
||||
{ "SKB132", SKYDIMO_LAYOUT_PERIMETER_4, { 25, 44, 25, 44 }, 138, 0 },
|
||||
{ "SKB134", SKYDIMO_LAYOUT_PERIMETER_4, { 21, 50, 21, 50 }, 142, 0 }
|
||||
};
|
||||
|
||||
#define SKYDIMO_MODEL_ENTRY_COUNT (sizeof(skydimo_model_entries) / sizeof(skydimo_model_entries[0]))
|
||||
|
||||
static const unsigned char skydimo_serial_frame_header[] =
|
||||
{
|
||||
0x41, 0x64, 0x61, 0x00
|
||||
};
|
||||
|
||||
static std::string StringToUpper(const std::string& value)
|
||||
{
|
||||
std::string result = value;
|
||||
|
||||
for(unsigned int char_idx = 0; char_idx < result.size(); char_idx++)
|
||||
{
|
||||
result[char_idx] = (char)std::toupper((unsigned char)result[char_idx]);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
static const SkydimoModelEntry* FindModelEntry(const std::string& model)
|
||||
{
|
||||
for(unsigned int entry_idx = 0; entry_idx < SKYDIMO_MODEL_ENTRY_COUNT; entry_idx++)
|
||||
{
|
||||
if(model == skydimo_model_entries[entry_idx].model)
|
||||
{
|
||||
return(&skydimo_model_entries[entry_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
static std::string BytesToHex(const std::vector<unsigned char>& bytes, unsigned int offset)
|
||||
{
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
std::string result;
|
||||
|
||||
result.reserve((bytes.size() - offset) * 2);
|
||||
|
||||
for(unsigned int byte_idx = offset; byte_idx < bytes.size(); byte_idx++)
|
||||
{
|
||||
result.push_back(hex[(bytes[byte_idx] >> 4) & 0x0F]);
|
||||
result.push_back(hex[bytes[byte_idx] & 0x0F]);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
SkydimoSerialController::SkydimoSerialController(const std::string& port_name_arg)
|
||||
{
|
||||
port_name = port_name_arg;
|
||||
model_name = "Skydimo UNKNOWN";
|
||||
model_id = "UNKNOWN";
|
||||
serial_id = "000000";
|
||||
port_open = serial_port_interface.serial_open(port_name.c_str(), SKYDIMO_SERIAL_BAUD_RATE);
|
||||
present = false;
|
||||
resizable = true;
|
||||
leds_count = SKYDIMO_SERIAL_DEFAULT_LED_COUNT;
|
||||
leds_min = SKYDIMO_SERIAL_DEFAULT_LED_COUNT;
|
||||
leds_max = SKYDIMO_SERIAL_DEFAULT_MAX_LED_COUNT;
|
||||
matrix_width = 0;
|
||||
matrix_height = 0;
|
||||
|
||||
if(!port_open)
|
||||
{
|
||||
LOG_DEBUG("[SkydimoSerialController] Failed to open serial port %s", port_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
SkydimoSerialController::~SkydimoSerialController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SkydimoSerialController::IsPresent()
|
||||
{
|
||||
if(present)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
present = QueryInfo();
|
||||
return(present);
|
||||
}
|
||||
|
||||
bool SkydimoSerialController::QueryInfo()
|
||||
{
|
||||
if(!port_open)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
serial_port_interface.serial_flush_rx();
|
||||
|
||||
char query[] = SKYDIMO_SERIAL_QUERY;
|
||||
int bytes_written = serial_port_interface.serial_write(query, SKYDIMO_SERIAL_QUERY_LENGTH);
|
||||
|
||||
if(bytes_written != SKYDIMO_SERIAL_QUERY_LENGTH)
|
||||
{
|
||||
LOG_DEBUG("[SkydimoSerialController] Failed to send identification query to %s (%d/%u bytes)",
|
||||
port_name.c_str(), bytes_written, (unsigned int)SKYDIMO_SERIAL_QUERY_LENGTH);
|
||||
return(false);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> response;
|
||||
|
||||
for(unsigned int attempt = 0; attempt < SKYDIMO_SERIAL_QUERY_ATTEMPTS; attempt++)
|
||||
{
|
||||
char buffer[SKYDIMO_SERIAL_READ_BUFFER_SIZE];
|
||||
int bytes_read = serial_port_interface.serial_read(buffer, SKYDIMO_SERIAL_READ_BUFFER_SIZE);
|
||||
|
||||
if(bytes_read < 0)
|
||||
{
|
||||
LOG_DEBUG("[SkydimoSerialController] Failed to read identification response from %s", port_name.c_str());
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(bytes_read > 0)
|
||||
{
|
||||
response.insert(response.end(), buffer, buffer + bytes_read);
|
||||
}
|
||||
|
||||
if(response.size() >= SKYDIMO_SERIAL_MAX_RESPONSE_SIZE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(!response.empty())
|
||||
{
|
||||
unsigned char last = response[response.size() - 1];
|
||||
unsigned char prev = response.size() >= 2 ? response[response.size() - 2] : 0;
|
||||
|
||||
if((last == '\r') || (last == '\n') || (prev == '\r'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(!response.empty() && ((response.back() == '\r') || (response.back() == '\n')))
|
||||
{
|
||||
response.pop_back();
|
||||
}
|
||||
|
||||
if(response.size() < SKYDIMO_SERIAL_MODEL_ID_LENGTH)
|
||||
{
|
||||
LOG_TRACE("[SkydimoSerialController] No Skydimo identification response from %s", port_name.c_str());
|
||||
return(false);
|
||||
}
|
||||
|
||||
if((std::toupper(response[0]) != 'S') || (std::toupper(response[1]) != 'K'))
|
||||
{
|
||||
LOG_TRACE("[SkydimoSerialController] Ignoring non-Skydimo serial device at %s", port_name.c_str());
|
||||
return(false);
|
||||
}
|
||||
|
||||
model_id = StringToUpper(std::string(response.begin(), response.begin() + SKYDIMO_SERIAL_MODEL_ID_LENGTH));
|
||||
model_name = "Skydimo " + model_id;
|
||||
serial_id = "000000";
|
||||
|
||||
unsigned int comma_offset = (unsigned int)response.size();
|
||||
|
||||
for(unsigned int byte_idx = 0; byte_idx < response.size(); byte_idx++)
|
||||
{
|
||||
if(response[byte_idx] == ',')
|
||||
{
|
||||
comma_offset = byte_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(comma_offset < response.size())
|
||||
{
|
||||
if(comma_offset < SKYDIMO_SERIAL_MODEL_ID_LENGTH)
|
||||
{
|
||||
LOG_DEBUG("[SkydimoSerialController] Invalid identification response from %s", port_name.c_str());
|
||||
return(false);
|
||||
}
|
||||
|
||||
if((comma_offset + 1) < response.size())
|
||||
{
|
||||
serial_id = BytesToHex(response, comma_offset + 1);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigureOutput();
|
||||
return(true);
|
||||
}
|
||||
|
||||
void SkydimoSerialController::ConfigureOutput()
|
||||
{
|
||||
const SkydimoModelEntry* entry = FindModelEntry(model_id);
|
||||
|
||||
resizable = true;
|
||||
leds_count = SKYDIMO_SERIAL_DEFAULT_LED_COUNT;
|
||||
leds_min = SKYDIMO_SERIAL_DEFAULT_LED_COUNT;
|
||||
leds_max = SKYDIMO_SERIAL_DEFAULT_MAX_LED_COUNT;
|
||||
matrix_width = 0;
|
||||
matrix_height = 0;
|
||||
matrix_map.clear();
|
||||
|
||||
if((entry != nullptr) && (entry->max_leds != 0))
|
||||
{
|
||||
leds_max = entry->max_leds;
|
||||
}
|
||||
|
||||
if((entry == nullptr) || (entry->layout == SKYDIMO_LAYOUT_NONE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
resizable = false;
|
||||
leds_count = entry->total_leds;
|
||||
leds_min = entry->total_leds;
|
||||
leds_max = entry->total_leds;
|
||||
|
||||
if(entry->layout == SKYDIMO_LAYOUT_STRIP_1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int zone_1_leds = entry->zone_leds[0];
|
||||
const unsigned int zone_2_leds = entry->zone_leds[1];
|
||||
const unsigned int zone_3_leds = entry->zone_leds[2];
|
||||
const unsigned int zone_4_leds = entry->zone_leds[3];
|
||||
|
||||
if(entry->layout == SKYDIMO_LAYOUT_PERIMETER_4)
|
||||
{
|
||||
matrix_height = std::max(zone_1_leds, zone_3_leds) + 2;
|
||||
matrix_width = std::max(zone_2_leds, zone_4_leds) + 2;
|
||||
}
|
||||
else if(entry->layout == SKYDIMO_LAYOUT_PERIMETER_3)
|
||||
{
|
||||
matrix_height = std::max(zone_1_leds, zone_3_leds) + 1;
|
||||
matrix_width = zone_2_leds + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix_height = std::max(zone_1_leds, zone_2_leds) + 2;
|
||||
matrix_width = std::max(3U, ((16 * matrix_height) + 4) / 9);
|
||||
}
|
||||
|
||||
matrix_map.assign(matrix_width * matrix_height, SKYDIMO_SERIAL_MATRIX_NA);
|
||||
|
||||
unsigned int led_index = 0;
|
||||
|
||||
if(entry->layout == SKYDIMO_LAYOUT_SIDES_2)
|
||||
{
|
||||
unsigned int placed = 0;
|
||||
int y = (int)matrix_height - 2;
|
||||
|
||||
while((placed < zone_1_leds) && (y >= 1))
|
||||
{
|
||||
SetMatrixCell((unsigned int)y, 0, led_index);
|
||||
placed++;
|
||||
y--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int placed = 0;
|
||||
int y = entry->layout == SKYDIMO_LAYOUT_PERIMETER_3 ? (int)matrix_height - 1
|
||||
: (int)matrix_height - 2;
|
||||
|
||||
while((placed < zone_1_leds) && (y >= 1))
|
||||
{
|
||||
SetMatrixCell((unsigned int)y, matrix_width - 1, led_index);
|
||||
placed++;
|
||||
y--;
|
||||
}
|
||||
}
|
||||
|
||||
if((entry->layout == SKYDIMO_LAYOUT_PERIMETER_3) || (entry->layout == SKYDIMO_LAYOUT_PERIMETER_4))
|
||||
{
|
||||
unsigned int placed = 0;
|
||||
int x = (int)matrix_width - 2;
|
||||
|
||||
while((placed < zone_2_leds) && (x >= 1))
|
||||
{
|
||||
SetMatrixCell(0, (unsigned int)x, led_index);
|
||||
placed++;
|
||||
x--;
|
||||
}
|
||||
}
|
||||
else if(entry->layout == SKYDIMO_LAYOUT_SIDES_2)
|
||||
{
|
||||
unsigned int placed = 0;
|
||||
unsigned int y = 1;
|
||||
|
||||
while((placed < zone_2_leds) && (y <= (matrix_height - 2)))
|
||||
{
|
||||
SetMatrixCell(y, matrix_width - 1, led_index);
|
||||
placed++;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int end_y = entry->layout == SKYDIMO_LAYOUT_PERIMETER_3 ? matrix_height - 1 : matrix_height - 2;
|
||||
unsigned int placed = 0;
|
||||
unsigned int y = 1;
|
||||
|
||||
while((placed < zone_3_leds) && (y <= end_y))
|
||||
{
|
||||
SetMatrixCell(y, 0, led_index);
|
||||
placed++;
|
||||
y++;
|
||||
}
|
||||
|
||||
if(entry->layout == SKYDIMO_LAYOUT_PERIMETER_4)
|
||||
{
|
||||
placed = 0;
|
||||
unsigned int x = 1;
|
||||
|
||||
while((placed < zone_4_leds) && (x <= (matrix_width - 2)))
|
||||
{
|
||||
SetMatrixCell(matrix_height - 1, x, led_index);
|
||||
placed++;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
if(led_index != entry->total_leds)
|
||||
{
|
||||
LOG_ERROR("[SkydimoSerialController] Invalid matrix map for %s (%u/%u LEDs placed)",
|
||||
model_id.c_str(), led_index, entry->total_leds);
|
||||
}
|
||||
}
|
||||
|
||||
void SkydimoSerialController::SetMatrixCell(unsigned int y, unsigned int x, unsigned int& led_index)
|
||||
{
|
||||
if((y < matrix_height) && (x < matrix_width))
|
||||
{
|
||||
matrix_map[(y * matrix_width) + x] = led_index++;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkydimoSerialController::WriteFrame(const std::vector<RGBColor>& colors, unsigned int count)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(device_mutex);
|
||||
|
||||
if(!port_open)
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(count > colors.size())
|
||||
{
|
||||
count = (unsigned int)colors.size();
|
||||
}
|
||||
|
||||
std::vector<unsigned char> packet;
|
||||
packet.reserve(sizeof(skydimo_serial_frame_header) + SKYDIMO_SERIAL_FRAME_COUNT_SIZE + (count * SKYDIMO_SERIAL_BYTES_PER_LED));
|
||||
|
||||
for(unsigned int header_idx = 0; header_idx < sizeof(skydimo_serial_frame_header); header_idx++)
|
||||
{
|
||||
packet.push_back(skydimo_serial_frame_header[header_idx]);
|
||||
}
|
||||
|
||||
packet.push_back((unsigned char)((count >> 8) & 0xFF));
|
||||
packet.push_back((unsigned char)(count & 0xFF));
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < count; led_idx++)
|
||||
{
|
||||
packet.push_back(RGBGetRValue(colors[led_idx]));
|
||||
packet.push_back(RGBGetGValue(colors[led_idx]));
|
||||
packet.push_back(RGBGetBValue(colors[led_idx]));
|
||||
}
|
||||
|
||||
int packet_size = (int)packet.size();
|
||||
int total_bytes_written = 0;
|
||||
|
||||
while(total_bytes_written < packet_size)
|
||||
{
|
||||
int bytes_written = serial_port_interface.serial_write((char*)packet.data() + total_bytes_written,
|
||||
packet_size - total_bytes_written);
|
||||
|
||||
if(bytes_written <= 0)
|
||||
{
|
||||
LOG_ERROR("[SkydimoSerialController] Failed to write RGB frame to %s (%d/%d bytes)",
|
||||
port_name.c_str(), total_bytes_written, packet_size);
|
||||
return(false);
|
||||
}
|
||||
|
||||
total_bytes_written += bytes_written;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void SkydimoSerialController::SetLEDs(const std::vector<RGBColor>& colors)
|
||||
{
|
||||
WriteFrame(colors, leds_count);
|
||||
}
|
||||
|
||||
void SkydimoSerialController::SetBlack()
|
||||
{
|
||||
std::vector<RGBColor> black_colors;
|
||||
|
||||
black_colors.resize(leds_count, ToRGBColor(0, 0, 0));
|
||||
WriteFrame(black_colors, leds_count);
|
||||
}
|
||||
|
||||
void SkydimoSerialController::SetLEDCount(unsigned int led_count)
|
||||
{
|
||||
if(!resizable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if((led_count < leds_min) || (led_count > leds_max))
|
||||
{
|
||||
LOG_WARNING("[SkydimoSerialController] Ignoring invalid LED count %u for %s (valid range %u-%u)",
|
||||
led_count, model_id.c_str(), leds_min, leds_max);
|
||||
return;
|
||||
}
|
||||
|
||||
leds_count = led_count;
|
||||
}
|
||||
|
||||
std::string SkydimoSerialController::GetName() const
|
||||
{
|
||||
return(model_name);
|
||||
}
|
||||
|
||||
std::string SkydimoSerialController::GetSerial() const
|
||||
{
|
||||
return(serial_id);
|
||||
}
|
||||
|
||||
std::string SkydimoSerialController::GetLocation() const
|
||||
{
|
||||
return("Serial: " + port_name);
|
||||
}
|
||||
|
||||
bool SkydimoSerialController::IsResizable() const
|
||||
{
|
||||
return(resizable);
|
||||
}
|
||||
|
||||
unsigned int SkydimoSerialController::GetLEDCount() const
|
||||
{
|
||||
return(leds_count);
|
||||
}
|
||||
|
||||
unsigned int SkydimoSerialController::GetMinLEDCount() const
|
||||
{
|
||||
return(leds_min);
|
||||
}
|
||||
|
||||
unsigned int SkydimoSerialController::GetMaxLEDCount() const
|
||||
{
|
||||
return(leds_max);
|
||||
}
|
||||
|
||||
unsigned int SkydimoSerialController::GetMatrixWidth() const
|
||||
{
|
||||
return(matrix_width);
|
||||
}
|
||||
|
||||
unsigned int SkydimoSerialController::GetMatrixHeight() const
|
||||
{
|
||||
return(matrix_height);
|
||||
}
|
||||
|
||||
const std::vector<unsigned int>& SkydimoSerialController::GetMatrixMap() const
|
||||
{
|
||||
return(matrix_map);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SkydimoSerialController.h |
|
||||
| |
|
||||
| Driver for Skydimo serial devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 30 Jun 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "RGBController.h"
|
||||
#include "serial_port.h"
|
||||
|
||||
#define SKYDIMO_SERIAL_BAUD_RATE 115200
|
||||
#define SKYDIMO_SERIAL_QUERY "Moni-A"
|
||||
#define SKYDIMO_SERIAL_QUERY_LENGTH 6
|
||||
#define SKYDIMO_SERIAL_MODEL_ID_LENGTH 6
|
||||
#define SKYDIMO_SERIAL_READ_BUFFER_SIZE 64
|
||||
#define SKYDIMO_SERIAL_MAX_RESPONSE_SIZE 63
|
||||
#define SKYDIMO_SERIAL_QUERY_ATTEMPTS 10
|
||||
#define SKYDIMO_SERIAL_DEFAULT_LED_COUNT 0
|
||||
#define SKYDIMO_SERIAL_DEFAULT_MAX_LED_COUNT 150
|
||||
#define SKYDIMO_SERIAL_BYTES_PER_LED 3
|
||||
#define SKYDIMO_SERIAL_FRAME_COUNT_SIZE 2
|
||||
#define SKYDIMO_SERIAL_MATRIX_NA 0xFFFFFFFF
|
||||
|
||||
class SkydimoSerialController
|
||||
{
|
||||
public:
|
||||
SkydimoSerialController(const std::string& port_name_arg);
|
||||
~SkydimoSerialController();
|
||||
|
||||
bool IsPresent();
|
||||
|
||||
void SetLEDs(const std::vector<RGBColor>& colors);
|
||||
void SetBlack();
|
||||
void SetLEDCount(unsigned int led_count);
|
||||
|
||||
std::string GetName() const;
|
||||
std::string GetSerial() const;
|
||||
std::string GetLocation() const;
|
||||
|
||||
bool IsResizable() const;
|
||||
unsigned int GetLEDCount() const;
|
||||
unsigned int GetMinLEDCount() const;
|
||||
unsigned int GetMaxLEDCount() const;
|
||||
|
||||
unsigned int GetMatrixWidth() const;
|
||||
unsigned int GetMatrixHeight() const;
|
||||
const std::vector<unsigned int>& GetMatrixMap() const;
|
||||
|
||||
private:
|
||||
bool QueryInfo();
|
||||
void ConfigureOutput();
|
||||
void SetMatrixCell(unsigned int y, unsigned int x, unsigned int& led_index);
|
||||
bool WriteFrame(const std::vector<RGBColor>& colors, unsigned int count);
|
||||
|
||||
std::string port_name;
|
||||
std::string model_name;
|
||||
std::string model_id;
|
||||
std::string serial_id;
|
||||
|
||||
bool port_open;
|
||||
bool present;
|
||||
bool resizable;
|
||||
|
||||
unsigned int leds_count;
|
||||
unsigned int leds_min;
|
||||
unsigned int leds_max;
|
||||
unsigned int matrix_width;
|
||||
unsigned int matrix_height;
|
||||
|
||||
std::vector<unsigned int> matrix_map;
|
||||
serial_port serial_port_interface;
|
||||
std::mutex device_mutex;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| SkydimoSerialControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for Skydimo serial devices |
|
||||
| |
|
||||
| Bartholomew Ho <qiangqiang101@hotmail.com> 30 Jun 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <vector>
|
||||
#include "DetectionManager.h"
|
||||
#include "LogManager.h"
|
||||
#include "RGBController_SkydimoSerial.h"
|
||||
#include "SkydimoSerialController.h"
|
||||
#include "find_usb_serial_port.h"
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Skydimo serial vendor and product IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define SKYDIMO_SERIAL_VID 0x1A86
|
||||
#define SKYDIMO_SERIAL_PID 0x7523
|
||||
|
||||
DetectedControllers DetectSkydimoSerialControllers()
|
||||
{
|
||||
DetectedControllers detected_controllers;
|
||||
std::vector<std::string> ports = find_usb_serial_port(SKYDIMO_SERIAL_VID, SKYDIMO_SERIAL_PID);
|
||||
|
||||
for(unsigned int port_idx = 0; port_idx < ports.size(); port_idx++)
|
||||
{
|
||||
SkydimoSerialController* controller = new SkydimoSerialController(ports[port_idx]);
|
||||
|
||||
if(controller->IsPresent())
|
||||
{
|
||||
RGBController_SkydimoSerial* rgb_controller = new RGBController_SkydimoSerial(controller);
|
||||
detected_controllers.push_back(rgb_controller);
|
||||
LOG_INFO("[SkydimoSerialControllerDetect] Detected %s at %s",
|
||||
controller->GetName().c_str(), ports[port_idx].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
}
|
||||
|
||||
return(detected_controllers);
|
||||
}
|
||||
|
||||
REGISTER_DETECTOR("Skydimo Serial", DetectSkydimoSerialControllers);
|
||||
/*---------------------------------------------------------------------------------------------------------*\
|
||||
| Entries for dynamic UDEV rules |
|
||||
| |
|
||||
| DUMMY_DEVICE_DETECTOR("Skydimo Serial", DetectSkydimoSerialControllers, 0x1A86, 0x7523 ) |
|
||||
\*---------------------------------------------------------------------------------------------------------*/
|
||||
Reference in New Issue
Block a user