Razer - Support individual LEDs and have default layout per device type

This commit is contained in:
Lord-Grey 2021-11-03 00:40:02 +01:00
parent c1178192ee
commit 545f184c50
4 changed files with 313 additions and 33 deletions

View File

@ -1,4 +1,3 @@
var ledsCustomCfgInitialized = false;
var onLedLayoutTab = false; var onLedLayoutTab = false;
var nonBlacklistLedArray = []; var nonBlacklistLedArray = [];
var ledBlacklist = []; var ledBlacklist = [];
@ -614,10 +613,7 @@ $(document).ready(function () {
var target = $(e.target).attr("href") // activated tab var target = $(e.target).attr("href") // activated tab
if (target == "#menu_gencfg") { if (target == "#menu_gencfg") {
onLedLayoutTab = true; onLedLayoutTab = true;
if (!ledsCustomCfgInitialized) {
$('#leds_custom_updsim').trigger('click'); $('#leds_custom_updsim').trigger('click');
ledsCustomCfgInitialized = true;
}
} else { } else {
onLedLayoutTab = false; onLedLayoutTab = false;
} }
@ -781,6 +777,10 @@ $(document).ready(function () {
conf_editor.getEditor("root.generalOptions").disable(); conf_editor.getEditor("root.generalOptions").disable();
hwLedCountDefault = 1; hwLedCountDefault = 1;
colorOrderDefault = "bgr"; colorOrderDefault = "bgr";
var subType = conf_editor.getEditor("root.specificOptions.subType").getValue();
params = { subType: subType };
getProperties_device(ledType, subType, params);
break; break;
default: default:
@ -1018,6 +1018,19 @@ $(document).ready(function () {
} }
}); });
conf_editor.watch('root.specificOptions.subType', () => {
var subType = conf_editor.getEditor("root.specificOptions.subType").getValue();
let params = {};
switch (ledType) {
case "razer":
params = { subType: subType };
getProperties_device(ledType, subType, params);
break;
default:
}
});
conf_editor.watch('root.specificOptions.token', () => { conf_editor.watch('root.specificOptions.token', () => {
var token = conf_editor.getEditor("root.specificOptions.token").getValue(); var token = conf_editor.getEditor("root.specificOptions.token").getValue();
@ -1295,7 +1308,6 @@ function saveLedConfig(genDefLayout = false) {
case "sk9822": case "sk9822":
case "ws2812spi": case "ws2812spi":
case "piblaster": case "piblaster":
case "razer":
default: default:
if (genDefLayout === true) { if (genDefLayout === true) {
ledConfig = { ledConfig = {
@ -1672,6 +1684,18 @@ function updateElements(ledType, key) {
} }
break; break;
case "razer":
var ledProperties = devicesProperties[ledType][key];
if (ledProperties) {
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(ledProperties.maxLedCount);
$("#ip_ma_ledshoriz").val(ledProperties.maxColumn);
$("#ip_ma_ledsvert").val(ledProperties.maxRow);
$("#ip_ma_cabling").val("parallel");
$("#ip_ma_start").val("top-left");
createMatrixLeds();
}
break;
default: default:
} }
} }

View File

@ -7,12 +7,21 @@
#include <chrono> #include <chrono>
using namespace Chroma;
using namespace Chroma::Keyboard;
using namespace Chroma::Keypad;
using namespace Chroma::Mouse;
using namespace Chroma::Mousepad;
using namespace Chroma::Headset;
using namespace Chroma::Chromalink;
// Constants // Constants
namespace { namespace {
bool verbose = false; bool verbose = true;
// Configuration settings // Configuration settings
const char RAZER_DEVICE_TYPE[] = "razerDevice"; const char CONFIG_RAZER_DEVICE_TYPE[] = "subType";
const char CONFIG_SINGLE_COLOR[] = "singleColor";
// WLED JSON-API elements // WLED JSON-API elements
const char API_DEFAULT_HOST[] = "localhost"; const char API_DEFAULT_HOST[] = "localhost";
@ -29,6 +38,9 @@ LedDeviceRazer::LedDeviceRazer(const QJsonObject& deviceConfig)
: LedDevice(deviceConfig) : LedDevice(deviceConfig)
, _restApi(nullptr) , _restApi(nullptr)
, _apiPort(API_DEFAULT_PORT) , _apiPort(API_DEFAULT_PORT)
, _maxRow(Chroma::MAX_ROW)
, _maxColumn(Chroma::MAX_COLUMN)
, _maxLeds(Chroma::MAX_LEDS)
{ {
} }
@ -43,6 +55,7 @@ LedDeviceRazer::~LedDeviceRazer()
_restApi = nullptr; _restApi = nullptr;
} }
bool LedDeviceRazer::init(const QJsonObject& deviceConfig) bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
{ {
bool isInitOK = false; bool isInitOK = false;
@ -67,15 +80,40 @@ bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
Debug(_log, "Hostname : %s", QSTRING_CSTR(_hostname)); Debug(_log, "Hostname : %s", QSTRING_CSTR(_hostname));
Debug(_log, "Port : %d", _apiPort); Debug(_log, "Port : %d", _apiPort);
_razerDeviceType = deviceConfig[RAZER_DEVICE_TYPE].toString("keyboard"); _razerDeviceType = deviceConfig[CONFIG_RAZER_DEVICE_TYPE].toString("invalid").toLower();
_isSingleColor = deviceConfig[CONFIG_SINGLE_COLOR].toBool();
Debug(_log, "Razer device : %s", QSTRING_CSTR(_razerDeviceType)); Debug(_log, "Razer Device : %s", QSTRING_CSTR(_razerDeviceType));
Debug(_log, "Single Color : %d", _isSingleColor);
if (resolveDeviceProperties(_razerDeviceType))
{
if (_isSingleColor && configuredLedCount > 1)
{
Info(_log, "In single color mode only the first LED of the configured [%d] will be used.", configuredLedCount);
}
else
{
if (_maxLeds != configuredLedCount)
{
Warning(_log, "Razer device might not work as expected. The type \"%s\" requires an LED-matrix [%d,%d] configured, i.e. %d LEDs. Currently only %d are defined via the layout.",
QSTRING_CSTR(_razerDeviceType),
_maxRow, _maxColumn, _maxLeds,
configuredLedCount
);
}
}
if (initRestAPI(_hostname, _apiPort)) if (initRestAPI(_hostname, _apiPort))
{ {
isInitOK = true; isInitOK = true;
} }
} }
else
{
Error(_log, "Razer devicetype \"%s\" not supported", QSTRING_CSTR(_razerDeviceType));
}
}
return isInitOK; return isInitOK;
} }
@ -109,7 +147,7 @@ bool LedDeviceRazer::checkApiError(const httpResponse& response)
QString errorReason; QString errorReason;
QString strJson(response.getBody().toJson(QJsonDocument::Compact)); QString strJson(response.getBody().toJson(QJsonDocument::Compact));
DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData()); //DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData());
QJsonObject jsonObj = response.getBody().object(); QJsonObject jsonObj = response.getBody().object();
@ -145,9 +183,7 @@ int LedDeviceRazer::open()
authorDetails.insert("contact", "https://github.com/hyperion-project/hyperion.ng"); authorDetails.insert("contact", "https://github.com/hyperion-project/hyperion.ng");
obj.insert("author", authorDetails); obj.insert("author", authorDetails);
obj.insert("device_supported", QJsonArray::fromStringList(Chroma::SupportedDevices));
QJsonArray deviceList = { "keyboard","mouse","headset","mousepad","keypad","chromalink" };
obj.insert("device_supported", deviceList);
obj.insert("category", "application"); obj.insert("category", "application");
@ -217,6 +253,10 @@ int LedDeviceRazer::write(const std::vector<ColorRgb>& ledValues)
int retval = -1; int retval = -1;
QJsonObject effectObj; QJsonObject effectObj;
if (_isSingleColor)
{
//Static effect
effectObj.insert("effect", "CHROMA_STATIC"); effectObj.insert("effect", "CHROMA_STATIC");
ColorRgb color = ledValues[0]; ColorRgb color = ledValues[0];
@ -225,6 +265,46 @@ int LedDeviceRazer::write(const std::vector<ColorRgb>& ledValues)
QJsonObject param; QJsonObject param;
param.insert("color", colorParam); param.insert("color", colorParam);
effectObj.insert("param", param); effectObj.insert("param", param);
}
else
{
//Custom effect
if (_customEffectType == Chroma::CHROMA_CUSTOM2)
{
effectObj.insert("effect", "CHROMA_CUSTOM2");
}
else {
effectObj.insert("effect", "CHROMA_CUSTOM");
}
QJsonArray rowParams;
for (int row = 0; row < _maxRow; row++) {
QJsonArray columnParams;
for (int col = 0; col < _maxColumn; col++) {
int pos = row * _maxColumn + col;
int bgrColor;
if (pos < ledValues.size())
{
bgrColor = (ledValues[pos].red * 65536) + (ledValues[pos].green * 256) + ledValues[pos].blue;
}
else
{
bgrColor = 0;
}
columnParams.append(bgrColor);
}
if (_maxRow == 1)
{
rowParams = columnParams;
}
else
{
rowParams.append(columnParams);
}
}
effectObj.insert("param", rowParams);
}
_restApi->setPath(_razerDeviceType); _restApi->setPath(_razerDeviceType);
httpResponse response = _restApi->put(effectObj); httpResponse response = _restApi->put(effectObj);
@ -247,3 +327,73 @@ int LedDeviceRazer::rewriteLEDs()
} }
return retval; return retval;
} }
bool LedDeviceRazer::resolveDeviceProperties(const QString& deviceType)
{
bool rc = true;
int typeID = Chroma::SupportedDevices.indexOf(deviceType);
switch (typeID)
{
case Chroma::DEVICE_KEYBOARD:
_maxRow = Chroma::Keyboard::MAX_ROW;
_maxColumn = Chroma::Keyboard::MAX_COLUMN;
_customEffectType = Chroma::Keyboard::CUSTOM_EFFECT_TYPE;
break;
case Chroma::DEVICE_MOUSE:
_maxRow = Chroma::Mouse::MAX_ROW;
_maxColumn = Chroma::Mouse::MAX_COLUMN;
_customEffectType = Chroma::Mouse::CUSTOM_EFFECT_TYPE;
break;
case Chroma::DEVICE_HEADSET:
_maxRow = Chroma::Headset::MAX_ROW;
_maxColumn = Chroma::Headset::MAX_COLUMN;
_customEffectType = Chroma::Headset::CUSTOM_EFFECT_TYPE;
break;
case Chroma::DEVICE_MOUSEPAD:
_maxRow = Chroma::Mousepad::MAX_ROW;
_maxColumn = Chroma::Mousepad::MAX_COLUMN;
_customEffectType = Chroma::Mousepad::CUSTOM_EFFECT_TYPE;
break;
case Chroma::DEVICE_KEYPAD:
_maxRow = Chroma::Keypad::MAX_ROW;
_maxColumn = Chroma::Keypad::MAX_COLUMN;
_customEffectType = Chroma::Keypad::CUSTOM_EFFECT_TYPE;
break;
case Chroma::DEVICE_CHROMALINK:
_maxRow = Chroma::Chromalink::MAX_ROW;
_maxColumn = Chroma::Chromalink::MAX_COLUMN;
_customEffectType = Chroma::Chromalink::CUSTOM_EFFECT_TYPE;
break;
default:
rc = false;
break;
}
if (rc)
{
_maxLeds = _maxRow * _maxColumn;
}
return rc;
}
QJsonObject LedDeviceRazer::getProperties(const QJsonObject& params)
{
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
QJsonObject properties;
_razerDeviceType = params[CONFIG_RAZER_DEVICE_TYPE].toString("invalid").toLower();
if (resolveDeviceProperties(_razerDeviceType))
{
QJsonObject propertiesDetails;
propertiesDetails.insert("maxRow", _maxRow);
propertiesDetails.insert("maxColumn", _maxColumn);
propertiesDetails.insert("maxLedCount", _maxLeds);
properties.insert("properties", propertiesDetails);
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
}
return properties;
}

View File

@ -5,6 +5,84 @@
#include <leddevice/LedDevice.h> #include <leddevice/LedDevice.h>
#include "ProviderRestApi.h" #include "ProviderRestApi.h"
namespace Chroma
{
typedef enum DeviceType
{
DEVICE_KEYBOARD = 0,
DEVICE_MOUSE = 1,
DEVICE_HEADSET = 2,
DEVICE_MOUSEPAD = 3,
DEVICE_KEYPAD = 4,
DEVICE_CHROMALINK = 5,
DEVICE_SYSTEM = 6,
DEVICE_SPEAKERS = 7,
DEVICE_INVALID
} DEVICETYPE;
typedef enum CustomEffectType
{
CHROMA_CUSTOM = 1,
CHROMA_CUSTOM2 = 2,
} CUSTOM_EFFECT_TYPE;
const int MAX_ROW = 30; //!< Maximum rows for custom effects.
const int MAX_COLUMN = 30; //!< Maximum columns for custom effects.
const int MAX_LEDS = MAX_ROW * MAX_COLUMN;
namespace Keyboard
{
const char TYPE_NAME[] = "keyboard";
const int MAX_ROW = 6;
const int MAX_COLUMN = 22;
const CustomEffectType CUSTOM_EFFECT_TYPE = CHROMA_CUSTOM;
}
namespace Mouse
{
const char TYPE_NAME[] = "mouse";
const int MAX_ROW = 9;
const int MAX_COLUMN = 7;
const CustomEffectType CUSTOM_EFFECT_TYPE = CHROMA_CUSTOM2;
}
namespace Headset
{
const char TYPE_NAME[] = "headset";
const int MAX_ROW = 1;
const int MAX_COLUMN = 5;
const CustomEffectType CUSTOM_EFFECT_TYPE = CHROMA_CUSTOM;
}
namespace Mousepad
{
const char TYPE_NAME[] = "mousepad";
const int MAX_ROW = 1;
const int MAX_COLUMN = 15;
const CustomEffectType CUSTOM_EFFECT_TYPE = CHROMA_CUSTOM;
}
namespace Keypad
{
const char TYPE_NAME[] = "keypad";
const int MAX_ROW = 4;
const int MAX_COLUMN = 5;
const CustomEffectType CUSTOM_EFFECT_TYPE = CHROMA_CUSTOM;
}
namespace Chromalink
{
const char TYPE_NAME[] = "chromalink";
const int MAX_ROW = 1;
const int MAX_COLUMN = 5;
const CustomEffectType CUSTOM_EFFECT_TYPE = CHROMA_CUSTOM;
}
const QStringList SupportedDevices{
Keyboard::TYPE_NAME,
Mouse::TYPE_NAME,
Headset::TYPE_NAME,
Mousepad::TYPE_NAME,
Keypad::TYPE_NAME,
Chromalink::TYPE_NAME
};
}
/// ///
/// Implementation of a Razer Chroma LedDevice /// Implementation of a Razer Chroma LedDevice
/// Supported Razer Chroma device types: Keyboard, Mouse, Headset, Mousepad, Keypad, Chromalink /// Supported Razer Chroma device types: Keyboard, Mouse, Headset, Mousepad, Keypad, Chromalink
@ -28,6 +106,20 @@ public:
/// ///
static LedDevice* construct(const QJsonObject& deviceConfig); static LedDevice* construct(const QJsonObject& deviceConfig);
///
/// @brief Get a Razer device's resource properties
///
/// Following parameters are required
/// @code
/// {
/// "subType" : "razer_device_type",
/// }
/// @endcode
/// @param[in] params Parameters to query device
/// @return A JSON structure holding the device's properties
///
QJsonObject getProperties(const QJsonObject& params) override;
/// ///
/// @brief Destructor of the LED-device /// @brief Destructor of the LED-device
/// ///
@ -93,6 +185,14 @@ private:
/// ///
bool checkApiError(const httpResponse& response); bool checkApiError(const httpResponse& response);
///
/// @brief Update object with properties for a given device
///
/// @param[in] deviceType
/// return True, if success
///
bool resolveDeviceProperties(const QString& deviceType);
///REST-API wrapper ///REST-API wrapper
ProviderRestApi* _restApi; ProviderRestApi* _restApi;
@ -101,6 +201,12 @@ private:
QUrl _uri; QUrl _uri;
QString _razerDeviceType; QString _razerDeviceType;
int _maxRow;
int _maxColumn;
int _maxLeds;
Chroma::CustomEffectType _customEffectType;
bool _isSingleColor;
}; };
#endif // LEDEVICERAZER_H #endif // LEDEVICERAZER_H

View File

@ -2,7 +2,7 @@
"type": "object", "type": "object",
"required": true, "required": true,
"properties": { "properties": {
"razerDevice": { "subType": {
"type": "string", "type": "string",
"title": "edt_dev_spec_razer_device_title", "title": "edt_dev_spec_razer_device_title",
"enum": [ "keyboard", "mouse", "headset", "mousepad", "keypad", "chromalink" ], "enum": [ "keyboard", "mouse", "headset", "mousepad", "keypad", "chromalink" ],