Publish LumaOps source

This commit is contained in:
LumaOps release export
2026-09-03 01:18:36 +02:00
commit 7f1c0e5f71
2363 changed files with 501543 additions and 0 deletions
@@ -0,0 +1,169 @@
/*---------------------------------------------------------*\
| RGBController_SayoDevice.cpp |
| |
| Controller for Sayo Devices |
| |
| Richard Harris 24 Jun 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_SayoDevice.h"
#include "SayoDeviceController.h"
#include "LogManager.h"
/**--------------------------------------------------------------------*\
@name SayoDevice E1
@category Keyboard
@type USB
@save :white_check_mark:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectSayoDeviceController
@comment
\*---------------------------------------------------------------------*/
RGBController_SayoDevice::RGBController_SayoDevice(SayoDeviceController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
vendor = "SayoDevice";
description = "SayoDevice E1 Knob";
type = DEVICE_TYPE_KEYBOARD;
location = controller->GetDeviceLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = SAYO_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
/*-----------------------------------------------------*\
| Breathing - pulses a single color |
\*-----------------------------------------------------*/
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = SAYO_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE | MODE_FLAG_HAS_RANDOM_COLOR;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.speed_min = 0;
Breathing.speed_max = 3;
Breathing.speed = 1;
modes.push_back(Breathing);
/*-----------------------------------------------------*\
| Wave - fades through multiple colors |
\*-----------------------------------------------------*/
mode Wave;
Wave.name = "Wave";
Wave.value = SAYO_MODE_WAVE;
Wave.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE | MODE_FLAG_HAS_RANDOM_COLOR;
Wave.color_mode = MODE_COLORS_NONE;
Wave.speed_min = 0;
Wave.speed_max = 3;
Wave.speed = 1;
modes.push_back(Wave);
/*-----------------------------------------------------*\
| Switch - alternates multiple colors |
\*-----------------------------------------------------*/
mode Switch;
Switch.name = "Switch";
Switch.value = SAYO_MODE_SWITCH;
Switch.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE | MODE_FLAG_HAS_RANDOM_COLOR;
Switch.color_mode = MODE_COLORS_NONE;
Switch.speed_min = 0;
Switch.speed_max = 3;
Switch.speed = 1;
modes.push_back(Switch);
/*-----------------------------------------------------*\
| Blink - blinks on and off |
\*-----------------------------------------------------*/
mode Blink;
Blink.name = "Blink";
Blink.value = SAYO_MODE_BLINK;
Blink.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE | MODE_FLAG_HAS_RANDOM_COLOR;
Blink.color_mode = MODE_COLORS_PER_LED;
Blink.speed_min = 0;
Blink.speed_max = 3;
Blink.speed = 1;
modes.push_back(Blink);
SetupZones();
};
RGBController_SayoDevice::~RGBController_SayoDevice()
{
delete controller;
}
void RGBController_SayoDevice::SetupZones()
{
const int led_count = 1;
zone zone;
zone.name = "Underglow";
zone.type = ZONE_TYPE_SINGLE;
zone.leds_count = led_count;
zone.leds_min = led_count;
zone.leds_max = led_count;
zone.matrix_map = NULL;
zones.clear();
zones.push_back(zone);
leds.clear();
leds.resize(led_count);
for(int i = 0; i < led_count; i++)
{
led& new_led = leds[i];
new_led.name = "LED " + std::to_string(i + 1);
new_led.value = i;
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_SayoDevice::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*-----------------------------------------------------*\
| This device does not support resizing zones |
\*-----------------------------------------------------*/
}
void RGBController_SayoDevice::DeviceUpdateLEDs()
{
unsigned int hw_mode = (modes[active_mode].value == SAYO_MODE_DIRECT) ? SAYO_MODE_STATIC : modes[active_mode].value;
bool random = (modes[active_mode].color_mode == MODE_COLORS_RANDOM);
unsigned int speed = 3 - modes[active_mode].speed;
controller->SetMode(hw_mode, speed, colors[0], random);
}
void RGBController_SayoDevice::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_SayoDevice::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_SayoDevice::DeviceUpdateMode()
{
/*-----------------------------------------------------*\
| Mode and color are always set together. |
\*-----------------------------------------------------*/
DeviceUpdateLEDs();
}
void RGBController_SayoDevice::DeviceSaveMode()
{
controller->Save();
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------*\
| RGBController_SayoDevice.h |
| |
| Controller for Sayo Devices |
| |
| Richard Harris 24 Jun 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "SayoDeviceController.h"
class RGBController_SayoDevice : public RGBController
{
public:
RGBController_SayoDevice(SayoDeviceController* controller_ptr);
~RGBController_SayoDevice();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
void DeviceSaveMode();
private:
SayoDeviceController* controller;
};
@@ -0,0 +1,128 @@
/*---------------------------------------------------------*\
| SayoDeviceController.cpp |
| |
| Controller for Sayo Devices (USB HID) |
| |
| Richard Harris 24 Jun 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <vector>
#include "LogManager.h"
#include "SayoDeviceController.h"
#include "RGBController.h"
#include "Colors.h"
SayoDeviceController::SayoDeviceController(hid_device* dev_handle, const char* path, std::string dev_name)
{
dev = dev_handle;
location = path;
name = dev_name;
}
SayoDeviceController::~SayoDeviceController()
{
hid_close(dev);
}
std::string SayoDeviceController::GetDeviceLocation()
{
return location;
}
std::string SayoDeviceController::GetDeviceName()
{
return name;
}
void SayoDeviceController::SetMode(unsigned int mode, unsigned int speed, RGBColor color, bool random)
{
/*-----------------------------------------------------*\
| Loop color table creates a rainbow effect which looks |
| better than truly random colors, so use that. |
\*-----------------------------------------------------*/
unsigned int color_mode = random ? SAYO_COLOR_LOOP_TABLE : SAYO_COLOR_STATIC;
unsigned char mode_byte = SAYO_MODE_PACK(speed, color_mode, mode);
/*-----------------------------------------------------*\
| 0x1C (0x00) is potentially length (28) as the payload |
| is 27 bytes in size. Could include a zero as many |
| fields seem to be 2-byte. |
| Other fields have not been mapped out at this time. |
\*-----------------------------------------------------*/
std::vector<unsigned char> payload =
{
0x1C, 0x00, SAYO_CMD_LIGHTING_SET, 0x00, 0x01, 0x00, 0x00, 0x00,
0x15, 0x00, 0x28, 0x00, 0x26, 0x00, 0x4C, 0x00,
0x26, 0x00, 0x00, 0x00, mode_byte, 0x00, 0x80, 0x80,
(unsigned char)RGBGetRValue(color),
(unsigned char)RGBGetGValue(color),
(unsigned char)RGBGetBValue(color),
};
SendPacket(payload, true);
}
/*---------------------------------------------------------*\
| Persist LED settings to flash memory. |
\*---------------------------------------------------------*/
void SayoDeviceController::Save()
{
/*-----------------------------------------------------*\
| 0x06 0x00 feels like a length too - 6 bytes |
\*-----------------------------------------------------*/
std::vector<unsigned char> payload = { 0x06, 0x00, 0x0d, 0x00, 0x96, 0x72 };
SendPacket(payload, true);
}
void SayoDeviceController::SendPacket(const std::vector<unsigned char>& command, bool flush)
{
unsigned char length = (unsigned char)(command.size() + 4);
if(length > 64)
{
LOG_ERROR("[SayoDevice] SendPacket: command size (%d) is too large, rejecting", (int)command.size());
return;
}
std::vector<unsigned char> packet = {0x21, 0x12};
/*-----------------------------------------------------*\
| Checksum of header + command, as little endian 2-byte |
| pairs. Checksum is in same format. |
\*-----------------------------------------------------*/
unsigned short checksum = (unsigned short)(packet[0] | (packet[1] << 8));
for(std::size_t i = 0; i < command.size(); i += 2)
{
unsigned short word = command[i];
if(i + 1 < command.size())
{
word |= (unsigned short)(command[i + 1] << 8);
}
checksum = (checksum + word) & 0xFFFF;
}
packet.push_back(checksum & 0xFF);
packet.push_back(checksum >> 8);
packet.insert(packet.end(), command.begin(), command.end());
packet.resize(64, 0u);
hid_write(dev, packet.data(), packet.size());
if(flush)
{
/*-------------------------------------------------*\
| Flush away any awaiting IN packets |
\*-------------------------------------------------*/
unsigned char buf[64];
int res = 1;
while(res > 0)
{
res = hid_read_timeout(dev, buf, 64, 0);
}
}
}
@@ -0,0 +1,103 @@
/*---------------------------------------------------------*\
| SayoDeviceController.h |
| |
| Controller for Sayo Devices |
| |
| Richard Harris 24 Jun 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <vector>
#include <hidapi.h>
#include "RGBController.h"
/*-----------------------------------------*\
| Lighting modes |
\*-----------------------------------------*/
enum
{
SAYO_MODE_STATIC = 0x00,
SAYO_MODE_INDICATOR = 0x01,
SAYO_MODE_BREATHING = 0x02,
SAYO_MODE_BREATHING_ONCE = 0x03,
SAYO_MODE_WAVE = 0x04,
SAYO_MODE_SWITCH = 0x06,
SAYO_MODE_SWITCH_ONCE = 0x07,
SAYO_MODE_BLINK = 0x08,
SAYO_MODE_BLINK_ONCE = 0x09,
SAYO_MODE_FADE_OUT = 0x0E,
SAYO_MODE_FADE_IN = 0x0F,
/*-------------------------------------*\
| Virtual modes |
\*-------------------------------------*/
SAYO_MODE_DIRECT = 0xFF,
};
/*-----------------------------------------*\
| Animation speeds |
\*-----------------------------------------*/
enum
{
SAYO_SPEED_1X = 3,
SAYO_SPEED_2X = 2,
SAYO_SPEED_4X = 1,
SAYO_SPEED_8X = 0,
};
/*-----------------------------------------*\
| Animation color mode |
| TABLE modes either loop through or pick |
| randomly from a palette of colors. |
| RANDOM is truly random. |
\*-----------------------------------------*/
enum
{
SAYO_COLOR_STATIC = 0,
SAYO_COLOR_LOOP_TABLE = 1,
SAYO_COLOR_RANDOM_TABLE = 2,
SAYO_COLOR_RANDOM = 3,
};
#define SAYO_MODE_PACK(speed, color_mode, mode) \
((unsigned char)((((speed) & 0x3) << 6) | \
(((color_mode) & 0x3) << 4) | \
((mode) & 0xF)))
/*-----------------------------------------*\
| Commands |
\*-----------------------------------------*/
enum
{
SAYO_CMD_API_LIST = 0x00,
SAYO_CMD_KEY_GET = 0x02, // maybe?
SAYO_CMD_SETTINGS = 0x03,
SAYO_CMD_KEY_SET = 0x10,
SAYO_CMD_LIGHTING_SET = 0x11,
SAYO_CMD_REBOOT = 0x0E,
};
class SayoDeviceController
{
public:
SayoDeviceController(hid_device* dev_handle, const char* path, std::string dev_name);
~SayoDeviceController();
std::string GetDeviceLocation();
std::string GetDeviceName();
void SetMode(unsigned int mode, unsigned int speed, RGBColor color, bool random);
void Save();
private:
hid_device* dev;
std::string name;
std::string location;
void SendPacket(const std::vector<unsigned char>& command, bool flush = true);
};
@@ -0,0 +1,42 @@
/*---------------------------------------------------------*\
| SayoDeviceControllerDetect.cpp |
| |
| Detector for Sayo Devices |
| |
| Richard Harris 24 Jun 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "Detector.h"
#include "SayoDeviceController.h"
#include "RGBController_SayoDevice.h"
#define SAYO_USB_VID 0x8089
#define SAYO_USB_PID_E1 0x0007
/*----------------------------------------------------------*\
| |
| DetectSayoDevice Controller |
| |
| Detect Sayo Devices |
| |
\*----------------------------------------------------------*/
void DetectSayoDeviceController
(
hid_device_info* info,
const std::string& name
)
{
hid_device* dev = hid_open_path(info->path);
if(dev != nullptr)
{
SayoDeviceController* controller = new SayoDeviceController(dev, info->path, name);
RGBController_SayoDevice *rgb_controller = new RGBController_SayoDevice(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_HID_DETECTOR_PU("SayoDevice E1", DetectSayoDeviceController, SAYO_USB_VID, SAYO_USB_PID_E1, 0xFF11, 0x0002);