Skip to content

Commit

Permalink
Add support for HD108 led strip (16bits colors) (#527)
Browse files Browse the repository at this point in the history
* Add support for HD108 led strip (16bits colors)

* HD108 improvements

* HD108 improvements
  • Loading branch information
awawa-dev authored Jul 21, 2023
1 parent 7d180e9 commit 69da76c
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 2 deletions.
1 change: 1 addition & 0 deletions sources/leddevice/LedDeviceSchemas.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<file alias="schema-sk6812spi">schemas/schema-sk6812spi.json</file>
<file alias="schema-sk6822spi">schemas/schema-sk6822spi.json</file>
<file alias="schema-sk9822">schemas/schema-sk9822.json</file>
<file alias="schema-hd108">schemas/schema-hd108.json</file>
<file alias="schema-tinkerforge">schemas/schema-tinkerforge.json</file>
<file alias="schema-tpm2net">schemas/schema-tpm2net.json</file>
<file alias="schema-tpm2">schemas/schema-tpm2.json</file>
Expand Down
129 changes: 129 additions & 0 deletions sources/leddevice/dev_spi/LedDeviceHD108.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* LedDeviceHD108.cpp
*
* MIT License
*
* Copyright (c) 2023 awawa-dev
*
* Project homesite: https://github.com/awawa-dev/HyperHDR
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include "LedDeviceHD108.h"

// Local HyperHDR includes
#include <utils/Logger.h>
#include <cmath>
#include <algorithm>

const int HD108_MAX_LEVEL = 0x1F;
const uint32_t HD108_MAX_THRESHOLD = 100u;
const uint32_t HD108_MAX_THRESHOLD_2 = HD108_MAX_THRESHOLD * HD108_MAX_THRESHOLD;
const uint16_t HD108_MAX_LEVEL_BIT = 0b1000000000000000;

LedDeviceHD108::LedDeviceHD108(const QJsonObject& deviceConfig)
: ProviderSpi(deviceConfig)
, _globalBrightnessControlThreshold(HD108_MAX_THRESHOLD)
, _globalBrightnessControlMaxLevel(HD108_MAX_LEVEL)
{
}

LedDevice* LedDeviceHD108::construct(const QJsonObject& deviceConfig)
{
return new LedDeviceHD108(deviceConfig);
}

bool LedDeviceHD108::init(const QJsonObject& deviceConfig)
{
bool isInitOK = false;

// Initialise sub-class
if (ProviderSpi::init(deviceConfig))
{
_globalBrightnessControlThreshold = static_cast<uint32_t>(std::min(
std::lround(deviceConfig["globalBrightnessControlThreshold"].toDouble(HD108_MAX_THRESHOLD) * HD108_MAX_THRESHOLD),
(long)HD108_MAX_THRESHOLD_2));
_globalBrightnessControlMaxLevel = deviceConfig["globalBrightnessControlMaxLevel"].toInt(HD108_MAX_LEVEL);
Info(_log, "[HD108] Using global brightness control with threshold of %d and max level of %d", _globalBrightnessControlThreshold, _globalBrightnessControlMaxLevel);

_ledBuffer.resize(0, 0x00);
_ledBuffer.resize((_ledCount * 8) + 16, 0x00);

isInitOK = true;
}
return isInitOK;
}

static inline uint16_t MSB_FIRST(uint16_t x, bool littleEndian)
{
if (littleEndian)
return (x >> 8) | (x << 8);
else
return x;
}

int LedDeviceHD108::write(const std::vector<ColorRgb>& ledValues)
{
int littleEndian = 1;

if (*(char*)&littleEndian != 1)
littleEndian = 0;


if (_ledCount != ledValues.size())
{
Warning(_log, "HD108 led's number has changed (old: %d, new: %d). Rebuilding buffer.", _ledCount, ledValues.size());
_ledCount = static_cast<uint>(ledValues.size());
_ledBuffer.resize(0, 0x00);
_ledBuffer.resize((_ledCount * 8) + 16, 0x00);
}


int index = 8;
uint16_t* data = reinterpret_cast<uint16_t*>(_ledBuffer.data());
for (auto const& rgb : ledValues)
{
const int isLit = (rgb.red || rgb.green || rgb.blue);
uint16_t red = rgb.red * 256u;
uint16_t green = rgb.green * 256u;
uint16_t blue = rgb.blue * 256u;
uint16_t level = HD108_MAX_LEVEL_BIT;

for (int i = 0; i < 3 && isLit; i++)
{
level |= (_globalBrightnessControlMaxLevel & HD108_MAX_LEVEL) << (5 * i);
}

if (_globalBrightnessControlThreshold < HD108_MAX_THRESHOLD_2)
{
red = (red * _globalBrightnessControlThreshold) / HD108_MAX_THRESHOLD_2;
green = (green * _globalBrightnessControlThreshold) / HD108_MAX_THRESHOLD_2;
blue = (blue * _globalBrightnessControlThreshold) / HD108_MAX_THRESHOLD_2;
}


data[index + 0] = MSB_FIRST(level, littleEndian);
data[index + 1] = MSB_FIRST(red, littleEndian);
data[index + 2] = MSB_FIRST(green, littleEndian);
data[index + 3] = MSB_FIRST(blue, littleEndian);
index += 4;
}

return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
53 changes: 53 additions & 0 deletions sources/leddevice/dev_spi/LedDeviceHD108.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* LedDeviceHD108.h
*
* MIT License
*
* Copyright (c) 2023 awawa-dev
*
* Project homesite: https://github.com/awawa-dev/HyperHDR
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef LEDEVICEHD108_H
#define LEDEVICEHD108_H

// HyperHDR includes
#include "ProviderSpi.h"

///
/// Implementation of the LedDevice interface for writing to LedDeviceHD108 led device via SPI.
///
class LedDeviceHD108 : public ProviderSpi
{
public:
explicit LedDeviceHD108(const QJsonObject& deviceConfig);

static LedDevice* construct(const QJsonObject& deviceConfig);

private:
uint32_t _globalBrightnessControlThreshold;
uint16_t _globalBrightnessControlMaxLevel;

bool init(const QJsonObject& deviceConfig) override;

int write(const std::vector<ColorRgb>& ledValues) override;
};

#endif // LEDEVICEHD108_H
54 changes: 54 additions & 0 deletions sources/leddevice/schemas/schema-hd108.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"type":"object",
"required":true,
"properties":{
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
"default" : "/dev/spidev0.0",
"required" : true,
"propertyOrder" : 1
},
"rate": {
"type": "integer",
"format" : "stepper",
"step" : 1000000,
"title":"edt_dev_spec_baudrate_title",
"default": 1000000,
"minimum": 1000000,
"required" : true,
"propertyOrder" : 2
},
"invert": {
"type": "boolean",
"format": "checkbox",
"title":"edt_dev_spec_invert_title",
"default": false,
"propertyOrder" : 3
},
"globalBrightnessControlMaxLevel": {
"type": "integer",
"format" : "stepper",
"step" : 1,
"title":"edt_dev_spec_globalBrightnessControlMaxLevel_title",
"default": 31,
"minimum": 1,
"maximum": 31,
"required" : true,
"propertyOrder" : 4
},
"globalBrightnessControlThreshold": {
"type": "number",
"format" : "stepper",
"title": "edt_conf_color_brightness_title",
"default": 100.0,
"minimum": 0,
"maximum": 100.0,
"step" : 0.25,
"append" : "edt_append_percent",
"required" : true,
"propertyOrder" : 5
}
},
"additionalProperties": true
}
4 changes: 2 additions & 2 deletions www/js/light_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ $(document).ready(function()
var yeelight_title = 'wiz_yeelight_title';
changeWizard(data, yeelight_title, startWizardYeelight);
}
else if (["apa102", "apa104", "awa_spi", "lpd6803", "lpd8806", "p9813", "sk6812spi", "sk6822spi", "sk9822", "ws2801", "ws2812spi", "wled", "adalight", "atmo", "dmx", "karate", "sedu", "tpm2"].includes(ledType))
else if (["apa102", "apa104", "awa_spi", "lpd6803", "lpd8806", "p9813", "sk6812spi", "sk6822spi", "sk9822", "ws2801", "ws2812spi", "wled", "adalight", "atmo", "dmx", "karate", "sedu", "tpm2", "hd108"].includes(ledType))
{
let selectorControl = $("<select id=\"deviceListInstances\" />");
let targetControl = 'output';
Expand Down Expand Up @@ -918,7 +918,7 @@ $(document).ready(function()

// create led device selection
var ledDevices = window.serverInfo.ledDevices.available;
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi','awa_spi'];
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi', 'awa_spi', 'hd108'];
var devRPiPWM = ['ws281x'];
var devRPiGPIO = ['piblaster'];

Expand Down

0 comments on commit 69da76c

Please sign in to comment.