Publish LumaOps source
This commit is contained in:
@@ -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);
|
||||
Reference in New Issue
Block a user