Adalight - HyperSerial Support (#1515)

* HyperSerial support

* Migrate Adalight records to new structure

* Serial Devices - Select baud rate and allow providing a custom one
This commit is contained in:
LordGrey 2022-09-30 17:02:40 +02:00 committed by GitHub
parent e8fc8a9855
commit 9df21b9ddd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 539 additions and 113 deletions

View File

@ -542,6 +542,8 @@
"edt_dev_general_heading_title": "General Settings", "edt_dev_general_heading_title": "General Settings",
"edt_dev_general_name_title": "Configuration name", "edt_dev_general_name_title": "Configuration name",
"edt_dev_general_rewriteTime_title": "Refresh time", "edt_dev_general_rewriteTime_title": "Refresh time",
"edt_dev_spec_ada_mode_title": "Adalight - Standard",
"edt_dev_spec_awa_mode_title": "HyperSerial - High speed",
"edt_dev_spec_FCledToOn_title": "Fadecandy LED set to on", "edt_dev_spec_FCledToOn_title": "Fadecandy LED set to on",
"edt_dev_spec_FCmanualControl_title": "Manual control of fadecandy LED", "edt_dev_spec_FCmanualControl_title": "Manual control of fadecandy LED",
"edt_dev_spec_FCsetConfig_title": "Set fadecandy configuration", "edt_dev_spec_FCsetConfig_title": "Set fadecandy configuration",
@ -612,6 +614,11 @@
"edt_dev_spec_razer_device_title": "Razer Chroma Device", "edt_dev_spec_razer_device_title": "Razer Chroma Device",
"edt_dev_spec_restoreOriginalState_title": "Restore lights' state", "edt_dev_spec_restoreOriginalState_title": "Restore lights' state",
"edt_dev_spec_restoreOriginalState_title_info": "Restore the device's original state when device is disabled", "edt_dev_spec_restoreOriginalState_title_info": "Restore the device's original state when device is disabled",
"edt_dev_spec_rgbw_calibration_enable" : "White channel calibration (RGBW only)",
"edt_dev_spec_rgbw_calibration_limit" : "White channel limit",
"edt_dev_spec_rgbw_calibration_red" : "Red/White channel aspect",
"edt_dev_spec_rgbw_calibration_green" : "Green/White channel aspect",
"edt_dev_spec_rgbw_calibration_blue" : "Blue/White channel aspect",
"edt_dev_spec_serial_title": "Serial number", "edt_dev_spec_serial_title": "Serial number",
"edt_dev_spec_spipath_title": "SPI Device", "edt_dev_spec_spipath_title": "SPI Device",
"edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum", "edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum",

View File

@ -62,7 +62,7 @@ function createLedPreview(leds) {
$('#image_preview').css({ "width": canvas_width, "height": canvas_height }); $('#image_preview').css({ "width": canvas_width, "height": canvas_height });
var leds_html = ""; var leds_html = "";
for (var idx = leds.length-1; idx >= 0; idx--) { for (var idx = leds.length - 1; idx >= 0; idx--) {
var led = leds[idx]; var led = leds[idx];
var led_id = 'ledc_' + [idx]; var led_id = 'ledc_' + [idx];
var bgcolor = "background-color:hsla(" + (idx * 360 / leds.length) + ",100%,50%,0.75);"; var bgcolor = "background-color:hsla(" + (idx * 360 / leds.length) + ",100%,50%,0.75);";
@ -112,7 +112,7 @@ function createLedPreview(leds) {
width: parseInt(maxWidth + $('#top_left_point').outerWidth()), width: parseInt(maxWidth + $('#top_left_point').outerWidth()),
height: parseInt(maxHeight + $('#top_left_point').outerHeight()), height: parseInt(maxHeight + $('#top_left_point').outerHeight()),
}, },
onMove: function(newPosition) { onMove: function (newPosition) {
var keystone_correction_area_offsets = $('#keystone_correction_area').offset(); var keystone_correction_area_offsets = $('#keystone_correction_area').offset();
var left = newPosition.left - keystone_correction_area_offsets.left + size / 2; var left = newPosition.left - keystone_correction_area_offsets.left + size / 2;
var top = newPosition.top - keystone_correction_area_offsets.top + size / 2; var top = newPosition.top - keystone_correction_area_offsets.top + size / 2;
@ -137,7 +137,7 @@ function createLedPreview(leds) {
width: parseInt(maxWidth + $('#top_right_point').outerWidth()), width: parseInt(maxWidth + $('#top_right_point').outerWidth()),
height: parseInt(maxHeight + $('#top_right_point').outerHeight()) height: parseInt(maxHeight + $('#top_right_point').outerHeight())
}, },
onMove: function(newPosition) { onMove: function (newPosition) {
var keystone_correction_area_offsets = $('#keystone_correction_area').offset(); var keystone_correction_area_offsets = $('#keystone_correction_area').offset();
var left = newPosition.left - keystone_correction_area_offsets.left + $('#top_right_point').outerWidth() - size / 2; var left = newPosition.left - keystone_correction_area_offsets.left + $('#top_right_point').outerWidth() - size / 2;
var top = newPosition.top - keystone_correction_area_offsets.top + size / 2; var top = newPosition.top - keystone_correction_area_offsets.top + size / 2;
@ -162,7 +162,7 @@ function createLedPreview(leds) {
width: parseInt(maxWidth + $('#bottom_right_point').outerWidth()), width: parseInt(maxWidth + $('#bottom_right_point').outerWidth()),
height: parseInt(maxHeight + $('#bottom_right_point').outerHeight()) height: parseInt(maxHeight + $('#bottom_right_point').outerHeight())
}, },
onMove: function(newPosition) { onMove: function (newPosition) {
var keystone_correction_area_offsets = $('#keystone_correction_area').offset(); var keystone_correction_area_offsets = $('#keystone_correction_area').offset();
var left = newPosition.left - keystone_correction_area_offsets.left + $('#bottom_right_point').outerWidth() - size / 2; var left = newPosition.left - keystone_correction_area_offsets.left + $('#bottom_right_point').outerWidth() - size / 2;
var top = newPosition.top - keystone_correction_area_offsets.top + $('#bottom_right_point').outerHeight() - size / 2; var top = newPosition.top - keystone_correction_area_offsets.top + $('#bottom_right_point').outerHeight() - size / 2;
@ -187,7 +187,7 @@ function createLedPreview(leds) {
width: parseInt(maxWidth + $('#bottom_left_point').outerWidth()), width: parseInt(maxWidth + $('#bottom_left_point').outerWidth()),
height: parseInt(maxHeight + $('#bottom_left_point').outerHeight()) height: parseInt(maxHeight + $('#bottom_left_point').outerHeight())
}, },
onMove: function(newPosition) { onMove: function (newPosition) {
var keystone_correction_area_offsets = $('#keystone_correction_area').offset(); var keystone_correction_area_offsets = $('#keystone_correction_area').offset();
var left = newPosition.left - keystone_correction_area_offsets.left + size / 2; var left = newPosition.left - keystone_correction_area_offsets.left + size / 2;
var top = newPosition.top - keystone_correction_area_offsets.top + $('#bottom_left_point').outerHeight() - size / 2; var top = newPosition.top - keystone_correction_area_offsets.top + $('#bottom_left_point').outerHeight() - size / 2;
@ -225,12 +225,12 @@ function createLedPreview(leds) {
var lineColor = $(".keystone_correction_corners").css("border-color"); var lineColor = $(".keystone_correction_corners").css("border-color");
// Add lines // Add lines
topLeft2topRight = new LeaderLine(LeaderLine.pointAnchor(top_left_point, {x: '50%', y: '50%'}), LeaderLine.pointAnchor(top_right_point, {x: '50%', y: '50%'}), {path: 'straight', size: 1, color: lineColor, endPlug: 'behind'}); topLeft2topRight = new LeaderLine(LeaderLine.pointAnchor(top_left_point, { x: '50%', y: '50%' }), LeaderLine.pointAnchor(top_right_point, { x: '50%', y: '50%' }), { path: 'straight', size: 1, color: lineColor, endPlug: 'behind' });
topRight2bottomRight = new LeaderLine(LeaderLine.pointAnchor(top_right_point, {x: '50%', y: '50%'}), LeaderLine.pointAnchor(bottom_right_point, {x: '50%', y: '50%'}), {path: 'straight', size: 1, color: lineColor, endPlug: 'behind'}); topRight2bottomRight = new LeaderLine(LeaderLine.pointAnchor(top_right_point, { x: '50%', y: '50%' }), LeaderLine.pointAnchor(bottom_right_point, { x: '50%', y: '50%' }), { path: 'straight', size: 1, color: lineColor, endPlug: 'behind' });
bottomRight2bottomLeft = new LeaderLine(LeaderLine.pointAnchor(bottom_right_point, {x: '50%', y: '50%'}), LeaderLine.pointAnchor(bottom_left_point, {x: '50%', y: '50%'}), {path: 'straight', size: 1, color: lineColor, endPlug: 'behind'}); bottomRight2bottomLeft = new LeaderLine(LeaderLine.pointAnchor(bottom_right_point, { x: '50%', y: '50%' }), LeaderLine.pointAnchor(bottom_left_point, { x: '50%', y: '50%' }), { path: 'straight', size: 1, color: lineColor, endPlug: 'behind' });
bottomLeft2topLeft = new LeaderLine(LeaderLine.pointAnchor(bottom_left_point, {x: '50%', y: '50%'}), LeaderLine.pointAnchor(top_left_point, {x: '50%', y: '50%'}), {path: 'straight', size: 1, color: lineColor, endPlug: 'behind'}); bottomLeft2topLeft = new LeaderLine(LeaderLine.pointAnchor(bottom_left_point, { x: '50%', y: '50%' }), LeaderLine.pointAnchor(top_left_point, { x: '50%', y: '50%' }), { path: 'straight', size: 1, color: lineColor, endPlug: 'behind' });
} else { } else {
$('#keystone_correction_area').html("").css({ "width" : 0, "height" : 0 }); $('#keystone_correction_area').html("").css({ "width": 0, "height": 0 });
// Remove existing lines // Remove existing lines
if (topLeft2topRight != null) { if (topLeft2topRight != null) {
@ -256,7 +256,7 @@ function createLedPreview(leds) {
// Change on window resize. Is this correct? // Change on window resize. Is this correct?
$(window).off("resize.createLedPreview"); $(window).off("resize.createLedPreview");
$(window).on("resize.createLedPreview",(function() { $(window).on("resize.createLedPreview", (function () {
createLedPreview(leds); createLedPreview(leds);
})); }));
} }
@ -776,16 +776,16 @@ $(document).ready(function () {
var maxLEDs = ledstop + ledsbottom + ledsleft + ledsright; var maxLEDs = ledstop + ledsbottom + ledsleft + ledsright;
var gpos = parseInt($("#ip_cl_gpos").val()); var gpos = parseInt($("#ip_cl_gpos").val());
$("#ip_cl_gpos").attr({'max':maxLEDs-1}); $("#ip_cl_gpos").attr({ 'max': maxLEDs - 1 });
var max = maxLEDs-gpos; var max = maxLEDs - gpos;
if (gpos == 0) { if (gpos == 0) {
--max; --max;
} }
$("#ip_cl_glength").attr({'max':max}); $("#ip_cl_glength").attr({ 'max': max });
var glength = parseInt($("#ip_cl_glength").val()); var glength = parseInt($("#ip_cl_glength").val());
if (glength+gpos >= maxLEDs) { if (glength + gpos >= maxLEDs) {
$("#ip_cl_glength").val($("#ip_cl_glength").attr('max')); $("#ip_cl_glength").val($("#ip_cl_glength").attr('max'));
} }
break; break;
@ -804,20 +804,20 @@ $(document).ready(function () {
configPanel = "classic"; configPanel = "classic";
$("#leds_prev_toggle_keystone_correction_area").show(); $("#leds_prev_toggle_keystone_correction_area").show();
createClassicLeds(); createClassicLeds();
}); });
$('#collapse2').on('shown.bs.collapse', function () { $('#collapse2').on('shown.bs.collapse', function () {
configPanel = "matrix"; configPanel = "matrix";
$("#leds_prev_toggle_keystone_correction_area").hide(); $("#leds_prev_toggle_keystone_correction_area").hide();
createMatrixLeds(); createMatrixLeds();
}); });
$('#collapse5').on('shown.bs.collapse', function () { $('#collapse5').on('shown.bs.collapse', function () {
configPanel = "text"; configPanel = "text";
$("#leds_prev_toggle_keystone_correction_area").hide(); $("#leds_prev_toggle_keystone_correction_area").hide();
createLedPreview(finalLedArray); createLedPreview(finalLedArray);
aceEdt.set(finalLedArray); aceEdt.set(finalLedArray);
}); });
// Initialise from config and apply blacklist rules // Initialise from config and apply blacklist rules
nonBlacklistLedArray = window.serverConfig.leds; nonBlacklistLedArray = window.serverConfig.leds;
@ -891,20 +891,20 @@ $(document).ready(function () {
}); });
// toggle right icon on "Advanced Settings" click // toggle right icon on "Advanced Settings" click
$('#advanced_settings').on('click', function(e) { $('#advanced_settings').on('click', function (e) {
$('#advanced_settings_right_icon').toggleClass('fa-angle-down fa-angle-up'); $('#advanced_settings_right_icon').toggleClass('fa-angle-down fa-angle-up');
}); });
// toggle fullscreen button in led preview // toggle fullscreen button in led preview
$(".fullscreen-btn").mousedown(function(e) { $(".fullscreen-btn").mousedown(function (e) {
e.preventDefault(); e.preventDefault();
}); });
$(".fullscreen-btn").click(function(e) { $(".fullscreen-btn").click(function (e) {
e.preventDefault(); e.preventDefault();
$(this).children('i') $(this).children('i')
.toggleClass('fa-expand') .toggleClass('fa-expand')
.toggleClass('fa-compress'); .toggleClass('fa-compress');
$('#layout_type').toggle(); $('#layout_type').toggle();
$('#layout_preview').toggleClass('col-lg-6 col-lg-12'); $('#layout_preview').toggleClass('col-lg-6 col-lg-12');
window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('resize'));
@ -1084,7 +1084,7 @@ $(document).ready(function () {
case "wled": case "wled":
case "nanoleaf": case "nanoleaf":
showAllDeviceInputOptions("hostList", false); showAllDeviceInputOptions("hostList", false);
case "apa102": case "apa102":
case "apa104": case "apa104":
case "ws2801": case "ws2801":
case "lpd6803": case "lpd6803":
@ -1187,6 +1187,18 @@ $(document).ready(function () {
} }
break; break;
case "adalight":
case "atmo":
case "karate":
case "dmx":
case "sedu":
case "tpm2":
var rate = conf_editor.getEditor("root.specificOptions.rate").getValue();
if (rate > 0) {
canSave = true;
}
break;
case "philipshue": case "philipshue":
var host = conf_editor.getEditor("root.specificOptions.host").getValue(); var host = conf_editor.getEditor("root.specificOptions.host").getValue();
var username = conf_editor.getEditor("root.specificOptions.username").getValue(); var username = conf_editor.getEditor("root.specificOptions.username").getValue();
@ -1264,7 +1276,7 @@ $(document).ready(function () {
var val = hostList.getValue(); var val = hostList.getValue();
var host = conf_editor.getEditor("root.specificOptions.host"); var host = conf_editor.getEditor("root.specificOptions.host");
var showOptions = true; var showOptions = true;
switch (val) { switch (val) {
case 'CUSTOM': case 'CUSTOM':
case '': case '':
@ -1381,6 +1393,15 @@ $(document).ready(function () {
default: default:
} }
if ($.inArray(ledType, devSerial) != -1) {
var rateList = conf_editor.getEditor("root.specificOptions.rateList").getValue();
var showRate = false;
if (rateList == "CUSTOM") {
showRate = true;
}
showInputOptionForItem(conf_editor, 'specificOptions', 'rate', showRate);
}
if (!conf_editor.validate().length) { if (!conf_editor.validate().length) {
if (canIdentify) { if (canIdentify) {
$("#btn_test_controller").show(); $("#btn_test_controller").show();
@ -1409,6 +1430,61 @@ $(document).ready(function () {
} }
}); });
conf_editor.watch('root.specificOptions.streamProtocol', () => {
var streamProtocol = conf_editor.getEditor("root.specificOptions.streamProtocol").getValue();
switch (ledType) {
case "adalight":
var rate;
if (streamProtocol === window.serverConfig.device.streamProtocol) {
rate = window.serverConfig.device.rate.toString();
} else {
// Set default rates per protocol type
switch (streamProtocol) {
case "2":
rate = "2000000";
break;
case "0":
case "1":
default:
rate = "115200";
}
}
conf_editor.getEditor("root.specificOptions.rateList").setValue(rate);
break;
default:
}
});
conf_editor.watch('root.specificOptions.rateList', () => {
var specOptPath = 'root.specificOptions.';
var rateList = conf_editor.getEditor("root.specificOptions.rateList");
if (rateList) {
var val = rateList.getValue();
var rate = conf_editor.getEditor("root.specificOptions.rate");
switch (val) {
case 'CUSTOM':
case '':
rate.enable();
//Populate existing rate for current custom config
if (ledType === window.serverConfig.device.type) {
rate.setValue(window.serverConfig.device.rate);
} else {
rate.setValue("");
}
break;
default:
rate.disable();
rate.setValue(val);
//Trigger getProperties via rate value
conf_editor.notifyWatchers(specOptPath + "rate");
break;
}
}
showInputOptionForItem(conf_editor, 'specificOptions', 'rate', rate.isEnabled());
});
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();
@ -1852,8 +1928,13 @@ var updateSelectList = function (ledType, discoveryInfo) {
// Select configured device // Select configured device
var configuredDeviceType = window.serverConfig.device.type; var configuredDeviceType = window.serverConfig.device.type;
var configuredOutput = window.serverConfig.device.output; var configuredOutput = window.serverConfig.device.output;
if (ledType === configuredDeviceType && $.inArray(configuredOutput, enumVals) != -1) { if (ledType === configuredDeviceType) {
enumDefaultVal = configuredOutput; if ($.inArray(configuredOutput, enumVals) != -1) {
enumDefaultVal = configuredOutput;
} else {
enumVals.push(window.serverConfig.device.output);
enumDefaultVal = configuredOutput;
}
} }
else { else {
addSelect = true; addSelect = true;
@ -2108,3 +2189,4 @@ function disableAutoResolvedGeneralOptions() {
conf_editor.getEditor("root.generalOptions.hardwareLedCount").disable(); conf_editor.getEditor("root.generalOptions.hardwareLedCount").disable();
conf_editor.getEditor("root.generalOptions.colorOrder").disable(); conf_editor.getEditor("root.generalOptions.colorOrder").disable();
} }

View File

@ -699,6 +699,59 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
} }
} }
} }
//Migration steps for versions <= 2.0.13
targetVersion.setVersion("2.0.13");
if (_previousVersion <= targetVersion)
{
Info(_log, "Instance [%u]: Migrate from version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
// Have Hostname/IP-address separate from port for LED-Devices
if (config.contains("device"))
{
QJsonObject newDeviceConfig = config["device"].toObject();
if (newDeviceConfig.contains("type"))
{
QString type = newDeviceConfig["type"].toString();
const QStringList serialDevices {"adalight", "dmx", "atmo", "sedu", "tpm2", "karate"};
if ( serialDevices.contains(type ))
{
if (!newDeviceConfig.contains("rateList"))
{
newDeviceConfig["rateList"] = "CUSTOM";
migrated = true;
}
}
if (type == "adalight")
{
if (newDeviceConfig.contains("lightberry_apa102_mode"))
{
bool lightberry_apa102_mode = newDeviceConfig["lightberry_apa102_mode"].toBool();
if (lightberry_apa102_mode)
{
newDeviceConfig["streamProtocol"] = "1";
}
else
{
newDeviceConfig["streamProtocol"] = "0";
}
newDeviceConfig.remove("lightberry_apa102_mode");
migrated = true;
}
}
}
if (migrated)
{
config["device"] = newDeviceConfig;
Debug(_log, "LED-Device records migrated");
}
}
}
} }
} }
return migrated; return migrated;

View File

@ -2,12 +2,23 @@
#include <QtEndian> #include <QtEndian>
#include <cassert> // Constants
namespace {
// Configuration settings
const char CONFIG_STREAM_PROTOCOL[] = "streamProtocol";
const char CONFIG_WHITE_CHANNEL_CALLIBRATION[] = "white_channel_calibration";
const char CONFIG_WHITE_CHANNEL_LIMIT[] = "white_channel_limit";
const char CONFIG_WHITE_CHANNEL_RED[] = "white_channel_red";
const char CONFIG_WHITE_CHANNEL_GREEN[] = "white_channel_green";
const char CONFIG_WHITE_CHANNEL_BLUE[] = "white_channel_blue";
constexpr int HEADER_SIZE {6};
} //End of constants
LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig) LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
: ProviderRs232(deviceConfig) : ProviderRs232(deviceConfig)
, _headerSize(6)
, _ligthBerryAPA102Mode(false)
{ {
} }
@ -23,66 +34,158 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
// Initialise sub-class // Initialise sub-class
if ( ProviderRs232::init(deviceConfig) ) if ( ProviderRs232::init(deviceConfig) )
{ {
_streamProtocol = static_cast<Adalight::PROTOCOLTYPE>(deviceConfig[CONFIG_STREAM_PROTOCOL].toString().toInt());
switch (_streamProtocol) {
_ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false); case Adalight::AWA:
// create ledBuffer
unsigned int totalLedCount = _ledCount;
if (_ligthBerryAPA102Mode)
{ {
const unsigned int startFrameSize = 4; Debug( _log, "Adalight driver uses Hyperserial protocol");
const unsigned int bytesPerRGBLed = 4; _white_channel_calibration = deviceConfig[CONFIG_WHITE_CHANNEL_CALLIBRATION].toBool(false);
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed); double _white_channel_limit_percent = deviceConfig[CONFIG_WHITE_CHANNEL_LIMIT].toDouble(1);
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00); _white_channel_limit = static_cast<uint8_t>(qMin(qRound(_white_channel_limit_percent * 255.0 / 100.0), 255));
_white_channel_red = static_cast<uint8_t>(qMin(deviceConfig[CONFIG_WHITE_CHANNEL_RED].toInt(255), 255));
_white_channel_green = static_cast<uint8_t>(qMin(deviceConfig[CONFIG_WHITE_CHANNEL_GREEN].toInt(255), 255));
_white_channel_blue = static_cast<uint8_t>(qMin(deviceConfig[CONFIG_WHITE_CHANNEL_BLUE].toInt(255), 255));
// init constant data values DebugIf(_white_channel_calibration, _log, "White channel limit: %i (%.2f%), red: %i, green: %i, blue: %i", _white_channel_limit, _white_channel_limit_percent, _white_channel_red, _white_channel_green, _white_channel_blue);
for (signed iLed=1; iLed<= static_cast<int>( _ledCount); iLed++)
{
_ledBuffer[iLed*4+_headerSize] = 0xFF;
}
Debug( _log, "Adalight driver with activated LightBerry APA102 mode");
} }
else break;
{
totalLedCount -= 1; case Adalight::LBAPA:
_ledBuffer.resize(_headerSize + _ledRGBCount, 0x00); Debug( _log, "Adalight driver uses LightBerry APA102 protocol");
break;
case Adalight::ADA:
Debug( _log, "Adalight driver uses standard Adalight protocol");
break;
default:
Error( _log, "Adalight driver - unsupported protocol");
return false;
} }
_ledBuffer[0] = 'A'; prepareHeader();
_ledBuffer[1] = 'd';
_ledBuffer[2] = 'a';
qToBigEndian<quint16>(static_cast<quint16>(totalLedCount), &_ledBuffer[3]);
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
isInitOK = true; isInitOK = true;
} }
return isInitOK; return isInitOK;
} }
void LedDeviceAdalight::prepareHeader()
{
// create ledBuffer
uint totalLedCount = _ledCount;
_bufferLength = static_cast<qint64>(HEADER_SIZE + _ledRGBCount);
switch (_streamProtocol) {
case Adalight::LBAPA:
{
const unsigned int startFrameSize = 4;
const unsigned int bytesPerRGBLed = 4;
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed);
_bufferLength = HEADER_SIZE + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize;
_ledBuffer.resize(static_cast<size_t>(_bufferLength), 0x00);
// init constant data values
for (uint iLed=1; iLed <= _ledCount; iLed++)
{
_ledBuffer[iLed*4+HEADER_SIZE] = 0xFF;
}
}
break;
case Adalight::AWA:
_bufferLength += 7;
[[clang::fallthrough]];
case Adalight::ADA:
[[clang::fallthrough]];
default:
totalLedCount -= 1;
_ledBuffer.resize(static_cast<size_t>(_bufferLength), 0x00);
break;
}
_ledBuffer[0] = 'A';
if (_streamProtocol == Adalight::AWA )
{
_ledBuffer[1] = 'w';
_ledBuffer[2] = _white_channel_calibration ? 'A' : 'a';
}
else
{
_ledBuffer[1] = 'd';
_ledBuffer[2] = 'a';
}
qToBigEndian<quint16>(static_cast<quint16>(totalLedCount), &_ledBuffer[3]);
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
}
int LedDeviceAdalight::write(const std::vector<ColorRgb> & ledValues) int LedDeviceAdalight::write(const std::vector<ColorRgb> & ledValues)
{ {
if(_ligthBerryAPA102Mode) if (_ledCount != ledValues.size())
{
Warning(_log, "Adalight LED count has changed (old: %d, new: %d). Rebuilding header.", _ledCount, ledValues.size());
_ledCount = static_cast<uint>(ledValues.size());
_ledRGBCount = _ledCount * 3;
prepareHeader();
}
if (_bufferLength > static_cast<qint64>(_ledBuffer.size()))
{
Warning(_log, "Adalight buffer's size has changed. Skipping refresh.");
return 0;
}
if (_streamProtocol == Adalight::LBAPA )
{ {
for (signed iLed=1; iLed<=static_cast<int>( _ledCount); iLed++) for (signed iLed=1; iLed<=static_cast<int>( _ledCount); iLed++)
{ {
const ColorRgb& rgb = ledValues[iLed-1]; const ColorRgb& rgb = ledValues[static_cast<size_t>(iLed-1)];
_ledBuffer[iLed*4+7] = rgb.red; _ledBuffer[static_cast<size_t>(iLed*4+7)] = rgb.red;
_ledBuffer[iLed*4+8] = rgb.green; _ledBuffer[static_cast<size_t>(iLed*4+8)] = rgb.green;
_ledBuffer[iLed*4+9] = rgb.blue; _ledBuffer[static_cast<size_t>(iLed*4+9)] = rgb.blue;
} }
} }
else else
{ {
assert(_headerSize + ledValues.size() * sizeof(ColorRgb) <= _ledBuffer.size()); uint8_t* writer = _ledBuffer.data() + HEADER_SIZE;
uint8_t* hasher = writer;
memcpy(_headerSize + _ledBuffer.data(), ledValues.data(), ledValues.size() * sizeof(ColorRgb)); memcpy(writer, ledValues.data(), ledValues.size() * sizeof(ColorRgb));
writer += ledValues.size() * sizeof(ColorRgb);
if (_streamProtocol == Adalight::AWA)
{
whiteChannelExtension(writer);
uint16_t fletcher1 = 0, fletcher2 = 0;
while (hasher < writer)
{
fletcher1 = (fletcher1 + *(hasher++)) % 255;
fletcher2 = (fletcher2 + fletcher1) % 255;
}
*(writer++) = static_cast<uint8_t>(fletcher1);
*(writer++) = static_cast<uint8_t>(fletcher2);
}
_bufferLength = writer - _ledBuffer.data();
} }
int rc = writeBytes(_ledBuffer.size(), _ledBuffer.data()); int rc = writeBytes(_bufferLength, _ledBuffer.data());
return rc; return rc;
} }
void LedDeviceAdalight::whiteChannelExtension(uint8_t*& writer)
{
if (_streamProtocol == Adalight::AWA && _white_channel_calibration)
{
*(writer++) = _white_channel_limit;
*(writer++) = _white_channel_red;
*(writer++) = _white_channel_green;
*(writer++) = _white_channel_blue;
}
}

View File

@ -4,6 +4,16 @@
// hyperion includes // hyperion includes
#include "ProviderRs232.h" #include "ProviderRs232.h"
namespace Adalight
{
typedef enum ProtocolType
{
ADA = 0,
LBAPA,
AWA
} PROTOCOLTYPE;
}
/// ///
/// Implementation of the LedDevice interface for writing to an Adalight LED-device. /// Implementation of the LedDevice interface for writing to an Adalight LED-device.
/// ///
@ -37,6 +47,11 @@ private:
/// ///
bool init(const QJsonObject &deviceConfig) override; bool init(const QJsonObject &deviceConfig) override;
///
/// @brief Prepare the protocol's header
///
void prepareHeader();
/// ///
/// @brief Writes the RGB-Color values to the LEDs. /// @brief Writes the RGB-Color values to the LEDs.
/// ///
@ -45,8 +60,17 @@ private:
/// ///
int write(const std::vector<ColorRgb> & ledValues) override; int write(const std::vector<ColorRgb> & ledValues) override;
const short _headerSize; void whiteChannelExtension(uint8_t*& writer);
bool _ligthBerryAPA102Mode;
qint64 _bufferLength;
Adalight::PROTOCOLTYPE _streamProtocol;
bool _white_channel_calibration;
uint8_t _white_channel_limit;
uint8_t _white_channel_red;
uint8_t _white_channel_green;
uint8_t _white_channel_blue;
}; };
#endif // LEDEVICETADALIGHT_H #endif // LEDEVICETADALIGHT_H

View File

@ -60,7 +60,7 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
_deviceName = _deviceName.mid(5); _deviceName = _deviceName.mid(5);
} }
_baudRate_Hz = deviceConfig["rate"].toInt(); _baudRate_Hz = deviceConfig["rate"].toInt();
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500); _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
Debug(_log, "DeviceName : %s", QSTRING_CSTR(_deviceName)); Debug(_log, "DeviceName : %s", QSTRING_CSTR(_deviceName));

View File

@ -8,12 +8,112 @@
"default":"auto", "default":"auto",
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"streamProtocol": {
"type": "string",
"title": "edt_dev_spec_stream_protocol_title",
"enum": [ "0", "1", "2" ],
"default": "0",
"options": {
"enum_titles": [ "edt_dev_spec_ada_mode_title", "edt_dev_spec_LBap102Mode_title","edt_dev_spec_awa_mode_title" ]
},
"propertyOrder": 2
},
"rateList": {
"type": "string",
"title":"edt_dev_spec_baudrate_title",
"enum": [ "CUSTOM","9600","14400","19200","28800","33600","38400","56000","57600","76800","115200","128000","153600","230400","256000","307200","460800","921600","1000000","1500000","2000000","3000000","4000000" ],
"options": {
"enum_titles": [ "edt_conf_enum_custom" ]
},
"default": "115200",
"access": "advanced",
"propertyOrder" : 3
},
"rate": { "rate": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_baudrate_title", "title":"",
"default": 115200, "default": 115200,
"access" : "advanced", "access": "advanced",
"propertyOrder" : 2 "propertyOrder" : 4
},
"white_channel_calibration": {
"type": "boolean",
"format": "checkbox",
"title":"edt_dev_spec_rgbw_calibration_enable",
"required" : true,
"default": false,
"options": {
"dependencies": {
"streamProtocol": "2"
}
},
"access": "advanced",
"propertyOrder" : 5
},
"white_channel_limit": {
"type": "number",
"title":"edt_dev_spec_rgbw_calibration_limit",
"required" : true,
"default" : 100,
"step": 0.25,
"minimum" : 0,
"maximum" : 100,
"append" : "edt_append_percent",
"options": {
"dependencies": {
"white_channel_calibration": true
}
},
"access": "advanced",
"propertyOrder" : 6
},
"white_channel_red": {
"type": "integer",
"title":"edt_dev_spec_rgbw_calibration_red",
"required" : true,
"default" : 255,
"step": 1,
"minimum" : 0,
"maximum" : 255,
"options": {
"dependencies": {
"white_channel_calibration": true
}
},
"access": "advanced",
"propertyOrder" : 7
},
"white_channel_green": {
"type": "integer",
"title":"edt_dev_spec_rgbw_calibration_green",
"required" : true,
"default" : 255,
"step": 1,
"minimum" : 0,
"maximum" : 255,
"options": {
"dependencies": {
"white_channel_calibration": true
}
},
"access": "advanced",
"propertyOrder" : 8
},
"white_channel_blue": {
"type": "integer",
"title":"edt_dev_spec_rgbw_calibration_blue",
"required" : true,
"default" : 255,
"step": 1,
"minimum" : 0,
"maximum" : 255,
"options": {
"dependencies": {
"white_channel_calibration": true
}
},
"access": "advanced",
"propertyOrder" : 9
}, },
"delayAfterConnect": { "delayAfterConnect": {
"type": "integer", "type": "integer",
@ -21,15 +121,7 @@
"default": 0, "default": 0,
"append" : "ms", "append" : "ms",
"access" : "expert", "access" : "expert",
"propertyOrder" : 3 "propertyOrder" : 10
},
"lightberry_apa102_mode": {
"type": "boolean",
"title": "edt_dev_spec_LBap102Mode_title",
"default": false,
"required": true,
"access": "advanced",
"propertyOrder": 4
}, },
"latchTime": { "latchTime": {
"type": "integer", "type": "integer",
@ -42,7 +134,7 @@
"options": { "options": {
"infoText": "edt_dev_spec_latchtime_title_info" "infoText": "edt_dev_spec_latchtime_title_info"
}, },
"propertyOrder": 5 "propertyOrder": 11
}, },
"rewriteTime": { "rewriteTime": {
"type": "integer", "type": "integer",
@ -51,7 +143,7 @@
"append" : "edt_append_ms", "append" : "edt_append_ms",
"minimum": 0, "minimum": 0,
"access" : "expert", "access" : "expert",
"propertyOrder" : 5 "propertyOrder" : 12
} }
}, },
"additionalProperties": true "additionalProperties": true

View File

@ -8,18 +8,31 @@
"default":"ttyUSB0", "default":"ttyUSB0",
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"rate": { "rateList": {
"type": "integer", "type": "string",
"title":"edt_dev_spec_baudrate_title", "title":"edt_dev_spec_baudrate_title",
"default": 1000000, "enum": [ "CUSTOM","9600","14400","19200","28800","33600","38400","56000","57600","76800","115200","128000","153600","230400","256000","307200","460800","921600","1000000","1500000","2000000","3000000","4000000" ],
"options": {
"enum_titles": [ "edt_conf_enum_custom" ]
},
"default": "1000000",
"access": "advanced",
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"rate": {
"type": "integer",
"title":"",
"default": 1000000,
"access": "advanced",
"propertyOrder" : 3
},
"delayAfterConnect": { "delayAfterConnect": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_delayAfterConnect_title", "title":"edt_dev_spec_delayAfterConnect_title",
"default": 250, "default": 250,
"append" : "ms", "append" : "ms",
"propertyOrder" : 3 "access" : "expert",
"propertyOrder" : 4
}, },
"latchTime": { "latchTime": {
"type": "integer", "type": "integer",
@ -29,7 +42,7 @@
"minimum": 0, "minimum": 0,
"maximum": 1000, "maximum": 1000,
"access" : "expert", "access" : "expert",
"propertyOrder" : 4 "propertyOrder" : 5
}, },
"rewriteTime": { "rewriteTime": {
"type": "integer", "type": "integer",
@ -38,7 +51,7 @@
"append" : "edt_append_ms", "append" : "edt_append_ms",
"minimum": 0, "minimum": 0,
"access" : "expert", "access" : "expert",
"propertyOrder" : 5 "propertyOrder" : 6
} }
}, },
"additionalProperties": true "additionalProperties": true

View File

@ -20,17 +20,30 @@
"default":"ttyUSB0", "default":"ttyUSB0",
"propertyOrder" : 2 "propertyOrder" : 2
}, },
"rate": { "rateList": {
"type": "integer", "type": "string",
"title":"edt_dev_spec_baudrate_title", "title":"edt_dev_spec_baudrate_title",
"default": 250000, "enum": [ "CUSTOM","9600","14400","19200","28800","33600","38400","56000","57600","76800","115200","128000","153600","230400","250000","256000","307200","460800","921600","1000000","1500000","2000000","3000000","4000000" ],
"options": {
"enum_titles": [ "edt_conf_enum_custom" ]
},
"default": "250000",
"access": "advanced",
"propertyOrder" : 3 "propertyOrder" : 3
}, },
"rate": {
"type": "integer",
"title":"",
"default": 250000,
"access": "advanced",
"propertyOrder" : 4
},
"delayAfterConnect": { "delayAfterConnect": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_delayAfterConnect_title", "title":"edt_dev_spec_delayAfterConnect_title",
"default": 250, "default": 250,
"propertyOrder" : 4 "access" : "expert",
"propertyOrder" : 5
}, },
"latchTime": { "latchTime": {
"type": "integer", "type": "integer",
@ -40,7 +53,7 @@
"minimum": 0, "minimum": 0,
"maximum": 1000, "maximum": 1000,
"access" : "expert", "access" : "expert",
"propertyOrder" : 5 "propertyOrder" : 6
}, },
"rewriteTime": { "rewriteTime": {
"type": "integer", "type": "integer",
@ -49,7 +62,7 @@
"append" : "edt_append_ms", "append" : "edt_append_ms",
"minimum": 0, "minimum": 0,
"access" : "expert", "access" : "expert",
"propertyOrder" : 6 "propertyOrder" : 7
} }
}, },
"additionalProperties": true "additionalProperties": true

View File

@ -8,18 +8,31 @@
"default":"ttyACM0", "default":"ttyACM0",
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"rateList": {
"type": "string",
"title":"edt_dev_spec_baudrate_title",
"enum": [ "CUSTOM","9600","14400","19200","28800","33600","38400","56000","57600","76800","115200","128000","153600","230400","256000","307200","460800","921600","1000000","1500000","2000000","3000000","4000000" ],
"options": {
"enum_titles": [ "edt_conf_enum_custom" ]
},
"default": "1000000",
"access": "advanced",
"propertyOrder" : 2
},
"rate": { "rate": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_baudrate_title", "title":"",
"default": 1000000, "default": 1000000,
"propertyOrder" : 2 "access": "advanced",
"propertyOrder" : 3
}, },
"delayAfterConnect": { "delayAfterConnect": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_delayAfterConnect_title", "title":"edt_dev_spec_delayAfterConnect_title",
"default": 1500, "default": 1500,
"append" : "ms", "append" : "ms",
"propertyOrder" : 3 "access" : "expert",
"propertyOrder" : 4
}, },
"latchTime": { "latchTime": {
"type": "integer", "type": "integer",
@ -29,7 +42,7 @@
"minimum": 0, "minimum": 0,
"maximum": 1000, "maximum": 1000,
"access" : "expert", "access" : "expert",
"propertyOrder" : 4 "propertyOrder" : 5
}, },
"rewriteTime": { "rewriteTime": {
"type": "integer", "type": "integer",
@ -38,7 +51,7 @@
"append" : "edt_append_ms", "append" : "edt_append_ms",
"minimum": 0, "minimum": 0,
"access" : "expert", "access" : "expert",
"propertyOrder" : 5 "propertyOrder" : 6
} }
}, },
"additionalProperties": true "additionalProperties": true

View File

@ -8,17 +8,30 @@
"default":"ttyACM0", "default":"ttyACM0",
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"rateList": {
"type": "string",
"title":"edt_dev_spec_baudrate_title",
"enum": [ "CUSTOM","9600","14400","19200","28800","33600","38400","56000","57600","76800","115200","128000","153600","230400","256000","307200","460800","921600","1000000","1500000","2000000","3000000","4000000" ],
"options": {
"enum_titles": [ "edt_conf_enum_custom" ]
},
"default": "1000000",
"access": "advanced",
"propertyOrder" : 2
},
"rate": { "rate": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_baudrate_title", "title":"",
"default": 1000000, "default": 1000000,
"propertyOrder" : 2 "access": "advanced",
"propertyOrder" : 3
}, },
"delayAfterConnect": { "delayAfterConnect": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_delayAfterConnect_title", "title":"edt_dev_spec_delayAfterConnect_title",
"default": 250, "default": 250,
"propertyOrder" : 3 "access" : "expert",
"propertyOrder" : 4
}, },
"latchTime": { "latchTime": {
"type": "integer", "type": "integer",
@ -28,7 +41,7 @@
"minimum": 0, "minimum": 0,
"maximum": 1000, "maximum": 1000,
"access" : "expert", "access" : "expert",
"propertyOrder" : 4 "propertyOrder" : 5
}, },
"rewriteTime": { "rewriteTime": {
"type": "integer", "type": "integer",
@ -37,7 +50,7 @@
"append" : "edt_append_ms", "append" : "edt_append_ms",
"minimum": 0, "minimum": 0,
"access" : "expert", "access" : "expert",
"propertyOrder" : 5 "propertyOrder" : 6
} }
}, },
"additionalProperties": true "additionalProperties": true

View File

@ -8,17 +8,30 @@
"default":"ttyACM0", "default":"ttyACM0",
"propertyOrder" : 1 "propertyOrder" : 1
}, },
"rateList": {
"type": "string",
"title":"edt_dev_spec_baudrate_title",
"enum": [ "CUSTOM","9600","14400","19200","28800","33600","38400","56000","57600","76800","115200","128000","153600","230400","256000","307200","460800","921600","1000000","1500000","2000000","3000000","4000000" ],
"options": {
"enum_titles": [ "edt_conf_enum_custom" ]
},
"default": "1000000",
"access": "advanced",
"propertyOrder" : 2
},
"rate": { "rate": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_baudrate_title", "title":"",
"default": 1000000, "default": 1000000,
"propertyOrder" : 2 "access": "advanced",
"propertyOrder" : 3
}, },
"delayAfterConnect": { "delayAfterConnect": {
"type": "integer", "type": "integer",
"title":"edt_dev_spec_delayAfterConnect_title", "title":"edt_dev_spec_delayAfterConnect_title",
"default": 250, "default": 250,
"propertyOrder" : 3 "access" : "expert",
"propertyOrder" : 4
}, },
"latchTime": { "latchTime": {
"type": "integer", "type": "integer",
@ -28,7 +41,7 @@
"minimum": 0, "minimum": 0,
"maximum": 1000, "maximum": 1000,
"access" : "expert", "access" : "expert",
"propertyOrder" : 4 "propertyOrder" : 5
}, },
"rewriteTime": { "rewriteTime": {
"type": "integer", "type": "integer",
@ -37,7 +50,7 @@
"append" : "edt_append_ms", "append" : "edt_append_ms",
"minimum": 0, "minimum": 0,
"access" : "expert", "access" : "expert",
"propertyOrder" : 5 "propertyOrder" : 6
} }, } },
"additionalProperties": true "additionalProperties": true
} }