LED Device Features, Fixes and Refactoring (Resubmit PR855) (#875)

* Refactor LedDevices - Initial version
* Small renamings
* Add WLED as own device
* Lpd8806 Remove open() method
* remove dependency on Qt 5.10
* Lpd8806 Remove open() method
* Update WS281x
* Update WS2812SPI
* Add writeBlack for WLED powerOff
* WLED remove extra bracket
* Allow different Nanoleaf panel numbering sequence (Feature req.#827)
* build(deps): bump websocket-extensions from 0.1.3 to 0.1.4 in /docs (#826)
* Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
  - [Release notes](https://github.com/faye/websocket-extensions-node/releases)
  - [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
  - [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)
* Fix typos
* Nanoleaf clean-up
* Yeelight support, generalize wizard elements
* Update Yeelight to handle quota in music mode
* Yeelight extend rage for extraTimeDarkness for testing
* Clean-up - Add commentary, Remove development debug statements
* Fix brightnessSwitchOffOnMinimum typo and default value
* Yeelight support restoreOriginalState, additional Fixes
* WLED - Remove UDP-Port, as it is not configurable
* Fix merging issue
* Remove QHostAddress::operator=(const QString&)' is deprecated
* Windows compile errors and (Qt 5.15 deprecation) warnings
* Fix order includes
* LedDeviceFile Support Qt5.7 and greater
* Windows compatibility and other Fixes
* Fix Qt Version compatability
* Rs232 - Resolve portname from unix /dev/ style, fix DMX sub-type support
* Disable WLED Wizard Button (until Wizard is available)
* Yeelight updates
* Add wrong log-type as per #505
* Fixes and Clean-up after clang-tidy report
* Fix udpe131 not enabled for generated CID
* Change timer into dynamic for Qt Thread-Affinity
* Hue clean-up and diyHue workaround
* Updates after review feedback by m-seker
* Add "chrono" includes
This commit is contained in:
LordGrey
2020-07-12 20:27:56 +02:00
committed by GitHub
parent 3b48d8c9d6
commit 7389068a66
125 changed files with 8864 additions and 3217 deletions

View File

@@ -5,11 +5,12 @@
// Local Hyperion includes
#include "LedDeviceHyperionUsbasp.h"
// Static constants which define the Hyperion Usbasp device
uint16_t LedDeviceHyperionUsbasp::_usbVendorId = 0x16c0;
uint16_t LedDeviceHyperionUsbasp::_usbProductId = 0x05dc;
QString LedDeviceHyperionUsbasp::_usbProductDescription = "Hyperion led controller";
// Constants which define the Hyperion USBasp device
namespace {
uint16_t _usbVendorId = 0x16c0;
uint16_t _usbProductId = 0x05dc;
QString _usbProductDescription = "Hyperion led controller";
}
LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig)
: LedDevice()
@@ -17,11 +18,17 @@ LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig
, _deviceHandle(nullptr)
{
_devConfig = deviceConfig;
_deviceReady = false;
_isDeviceReady = false;
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
{
if (_libusbContext != nullptr)
{
libusb_exit(_libusbContext);
}
}
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
@@ -31,18 +38,68 @@ LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
bool isInitOK = false;
QString ledType = deviceConfig["ledType"].toString("ws2801");
if (ledType != "ws2801" && ledType != "ws2812")
// Initialise sub-class
if ( LedDevice::init(deviceConfig) )
{
QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
this->setInError(errortext);
isInitOK = false;
}
else
{
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
QString ledType = deviceConfig["ledType"].toString("ws2801");
if (ledType != "ws2801" && ledType != "ws2812")
{
QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
this->setInError(errortext);
isInitOK = false;
}
else
{
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
int error;
// initialize the USB context
if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
{
_libusbContext = nullptr;
QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
this->setInError(errortext);
isInitOK = false;
}
else
{
Debug(_log, "USB context initialized");
//libusb_set_debug(_libusbContext, 3);
// retrieve the list of USB devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
// iterate the list of devices
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
// try to open and initialize the device
if ( testAndOpen(deviceList[i]) == 0 )
{
_device = deviceList[i];
// a device was successfully opened. break from list
break;
}
}
// free the device list
libusb_free_device_list(deviceList, 1);
if (_deviceHandle == nullptr)
{
QString errortext;
errortext = QString ("No %1 has been found").arg( _usbProductDescription);
this->setInError( errortext );
}
else
{
isInitOK = true;
}
}
}
}
return isInitOK;
@@ -51,73 +108,29 @@ bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
int LedDeviceHyperionUsbasp::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
_isDeviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
{
int error;
// initialize the usb context
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
{
//Error(_log, "Error while initializing USB context(%d):%s", error, libusb_error_name(error));
errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
_libusbContext = nullptr;
}
else
{
//libusb_set_debug(_libusbContext, 3);
Debug(_log, "USB context initialized");
// retrieve the list of usb devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
// iterate the list of devices
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
// try to open and initialize the device
error = testAndOpen(deviceList[i]);
if (error == 0)
{
// a device was sucessfully opened. break from list
break;
}
}
// free the device list
libusb_free_device_list(deviceList, 1);
if (_deviceHandle == nullptr)
{
//Error(_log, "No %s has been found", QSTRING_CSTR(_usbProductDescription));
errortext = QString ("No %1 has been found").arg( _usbProductDescription);
}
else
{
// Everything is OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
}
}
// On error/exceptions, set LedDevice in error
if ( retval < 0 )
{
this->setInError( errortext );
}
QString errortext = QString ("Failed to open [%1]").arg(_usbProductDescription);
this->setInError(errortext);
}
else
{
// Everything is OK -> enable device
_isDeviceReady = true;
retval = 0;
}
return retval;
}
void LedDeviceHyperionUsbasp::close()
int LedDeviceHyperionUsbasp::close()
{
LedDevice::close();
int retval = 0;
_isDeviceReady = false;
// LedDevice specific closing activites
// LedDevice specific closing activities
if (_deviceHandle != nullptr)
{
libusb_release_interface(_deviceHandle, 0);
@@ -126,12 +139,7 @@ void LedDeviceHyperionUsbasp::close()
_deviceHandle = nullptr;
}
if (_libusbContext != nullptr)
{
libusb_exit(_libusbContext);
_libusbContext = nullptr;
}
return retval;
}
int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
@@ -176,7 +184,7 @@ int LedDeviceHyperionUsbasp::write(const std::vector<ColorRgb> &ledValues)
{
int nbytes = libusb_control_transfer(
_deviceHandle, // device handle
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, // request type
static_cast<uint8_t>( LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT ), // request type
_writeLedsCommand, // request
0, // value
0, // index
@@ -184,7 +192,7 @@ int LedDeviceHyperionUsbasp::write(const std::vector<ColorRgb> &ledValues)
(3*_ledCount) & 0xffff, // length
5000); // timeout
// Disabling interupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
// Disabling interrupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
if(nbytes < 0 && nbytes != LIBUSB_ERROR_PIPE)
{
Error(_log, "Error while writing data to %s (%s)", QSTRING_CSTR(_usbProductDescription), libusb_error_name(nbytes));

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef LEDEVICEHYPERIONUSBASP_H
#define LEDEVICEHYPERIONUSBASP_H
// stl includes
#include <vector>
@@ -32,7 +33,7 @@ public:
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @para#endif // LEDEVICETEMPLATE_Hm deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig) override;
@@ -49,7 +50,7 @@ public slots:
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
virtual int close() override;
protected:
///
@@ -85,11 +86,11 @@ protected:
/// libusb context
libusb_context * _libusbContext;
/// libusb device
libusb_device * _device;
/// libusb device handle
libusb_device_handle * _deviceHandle;
/// Usb device identifiers
static uint16_t _usbVendorId;
static uint16_t _usbProductId;
static QString _usbProductDescription;
};
#endif // LEDEVICEHYPERIONUSBASP_H

View File

@@ -32,20 +32,6 @@ enum DATA_VERSION_INDEXES{
INDEX_FW_VER_MINOR
};
LedDeviceLightpack::LedDeviceLightpack(const QString & serialNumber)
: LedDevice()
, _libusbContext(nullptr)
, _deviceHandle(nullptr)
, _busNumber(-1)
, _addressNumber(-1)
, _serialNumber(serialNumber)
, _firmwareVersion({-1,-1})
, _bitsPerChannel(-1)
, _hwLedCount(-1)
{
_deviceReady = false;
}
LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
: LedDevice()
, _libusbContext(nullptr)
@@ -55,13 +41,20 @@ LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
, _firmwareVersion({-1,-1})
, _bitsPerChannel(-1)
, _hwLedCount(-1)
,_isOpen(false)
{
_devConfig = deviceConfig;
_deviceReady = false;
_isDeviceReady = false;
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceLightpack::~LedDeviceLightpack()
{
if (_libusbContext != nullptr)
{
libusb_exit(_libusbContext);
}
}
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
@@ -71,36 +64,29 @@ LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
_serialNumber = deviceConfig["output"].toString("");
bool isInitOK = false;
return isInitOK;
}
int LedDeviceLightpack::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
// Initialise sub-class
if ( LedDevice::init(deviceConfig) )
{
int error;
_serialNumber = deviceConfig["serial"].toString("");
// initialize the usb context
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
int error;
// initialize the USB context
if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
{
//Error(_log, "Error while initializing USB context(%d): %s", error, libusb_error_name(error));
errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
_libusbContext = nullptr;
QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
this->setInError(errortext);
isInitOK = false;
}
else
{
//libusb_set_debug(_libusbContext, 3);
Debug(_log, "USB context initialized");
//libusb_set_debug(_libusbContext, 3);
// retrieve the list of usb devices
// retrieve the list of USB devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
@@ -108,11 +94,10 @@ int LedDeviceLightpack::open()
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
// try to open and initialize the device
error = testAndOpen(deviceList[i], _serialNumber);
if (error == 0)
if (testAndOpen(deviceList[i], _serialNumber) == 0)
{
// a device was sucessfully opened. break from list
_device = deviceList[i];
// a device was successfully opened. break from list
break;
}
}
@@ -122,53 +107,62 @@ int LedDeviceLightpack::open()
if (_deviceHandle == nullptr)
{
QString errortext;
if (_serialNumber.isEmpty())
{
//Warning(_log, "No Lightpack device has been found");
errortext = QString ("No Lightpack devices were found");
}
else
{
//Error(_log,"No Lightpack device has been found with serial %", QSTRING_CSTR(_serialNumber));
errortext = QString ("No Lightpack device has been found with serial %1").arg( _serialNumber);
}
this->setInError( errortext );
}
else
{
// Everything is OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
isInitOK = true;
}
}
// On error/exceptions, set LedDevice in error
if ( retval < 0 )
{
this->setInError( errortext );
}
}
return isInitOK;
}
int LedDeviceLightpack::open()
{
int retval = -1;
_isDeviceReady = false;
if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
{
QString errortext = QString ("Failed to open [%1]").arg(_serialNumber);
this->setInError(errortext);
}
else
{
// Everything is OK -> enable device
_isDeviceReady = true;
retval = 0;
}
return retval;
}
void LedDeviceLightpack::close()
int LedDeviceLightpack::close()
{
LedDevice::close();
int retval = 0;
_isDeviceReady = false;
// LedDevice specific closing activites
// LedDevice specific closing activities
if (_deviceHandle != nullptr)
{
_isOpen = false;
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_attach_kernel_driver(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_close(_deviceHandle);
_deviceHandle = nullptr;
}
if (_libusbContext != nullptr)
{
libusb_exit(_libusbContext);
_libusbContext = nullptr;
}
return retval;
}
int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber)
@@ -184,7 +178,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
Info(_log, "Found a lightpack device. Retrieving more information...");
Info(_log, "Found a Lightpack device. Retrieving more information...");
// get the hardware address
int busNumber = libusb_get_bus_number(device);
@@ -226,7 +220,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
uint8_t buffer[256];
error = libusb_control_transfer(
_deviceHandle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
static_cast<uint8_t>( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE),
0x01,
0x0100,
0,
@@ -289,19 +283,19 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
{
return write(ledValues.data(), ledValues.size());
return write(ledValues.data(), static_cast<int>(ledValues.size()));
}
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{
int count = qMin(_hwLedCount, static_cast<int>( _ledCount));
int count = qMin(_hwLedCount, static_cast<int>( size ));
for (int i = 0; i < count ; ++i)
{
const ColorRgb & color = ledValues[i];
// copy the most significant bits of the rgb values to the first three bytes
// offset 1 to accomodate for the command byte
// copy the most significant bits of the RGB values to the first three bytes
// offset 1 to accommodate for the command byte
_ledBuffer[6*i+1] = color.red;
_ledBuffer[6*i+2] = color.green;
_ledBuffer[6*i+3] = color.blue;
@@ -315,14 +309,13 @@ int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
return error >= 0 ? 0 : error;
}
int LedDeviceLightpack::switchOff()
bool LedDeviceLightpack::powerOff()
{
int rc = LedDevice::switchOff();
if ( _deviceReady )
{
unsigned char buf[1] = {CMD_OFF_ALL};
rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
}
bool rc = false;
unsigned char buf[1] = {CMD_OFF_ALL};
rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
return rc;
}
@@ -338,7 +331,7 @@ int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
// std::cout << std::endl;
int error = libusb_control_transfer(_deviceHandle,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
static_cast<uint8_t>( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ),
0x09,
(2 << 8),
0x00,
@@ -356,7 +349,13 @@ int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
int LedDeviceLightpack::disableSmoothing()
{
unsigned char buf[2] = {CMD_SET_SMOOTH_SLOWDOWN, 0};
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
int rc = 0;
if ( writeBytes(buf, sizeof(buf)) == sizeof(buf) )
{
rc = 1;
}
return rc;
}
libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device)

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef LEDEVICELIGHTPACK_H
#define LEDEVICELIGHTPACK_H
// stl includes
#include <cstdint>
@@ -15,79 +16,93 @@
class LedDeviceLightpack : public LedDevice
{
public:
///
/// Constructs the LedDeviceLightpack
/// @brief Constructs a Lightpack LED-device
///
/// @param serialNumber serial output device
///
LedDeviceLightpack(const QString & serialNumber = "");
explicit LedDeviceLightpack(const QString & serialNumber = "");
///
/// Constructs specific LedDevice
/// @brief Constructs a Lightpack LED-device
///
/// @param deviceConfig json device config
/// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceLightpack(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig) override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
///
/// Destructor of the LedDevice; closes the output device if it is open
/// @brief Destructor of the LedDevice
///
virtual ~LedDeviceLightpack() override;
///
/// Opens and configures the output device
/// @brief Constructs the LED-device
///
/// @return Zero on succes else negative
/// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed
///
int open() override;
static LedDevice* construct(const QJsonObject &deviceConfig);
///
/// Writes the RGB-Color values to the leds.
/// @brief Initialise the device's configuration
///
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
virtual bool init(const QJsonObject &deviceConfig) override;
///
/// @brief Opens the output device.
///
/// @return Zero on success (i.e. device is ready), else negative
///
virtual int open() override;
///
/// @brief Closes the output device.
///
/// @return Zero on success (i.e. device is closed), else negative
///
virtual int close() override;
///
/// @brief Power-/turn off the Nanoleaf device.
///
/// @return True if success
///
virtual bool powerOff() override;
///
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues Array of RGB values
/// @param[in] size The number of RGB values
///
/// @return Zero on success else negative
/// @return Zero on success, else negative
///
int write(const ColorRgb * ledValues, int size);
///
/// Switch the leds off
/// @brief Get the serial number of the Lightpack
///
/// @return Zero on success else negative
///
virtual int switchOff() override;
/// Get the serial of the Lightpack
/// @return Serial Number
/// ///
const QString & getSerialNumber() const;
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
bool isOpen(){ return _isOpen; }
protected:
///
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues) override;
private:
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues) override;
///
/// Test if the device is a (or the) lightpack we are looking for
@@ -114,6 +129,9 @@ private:
/// libusb context
libusb_context * _libusbContext;
/// libusb device
libusb_device * _device;
/// libusb device handle
libusb_device_handle * _deviceHandle;
@@ -134,4 +152,8 @@ private:
/// count of real hardware leds
int _hwLedCount;
bool _isOpen;
};
#endif // LEDEVICELIGHTPACK_H

View File

@@ -22,14 +22,19 @@ LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig
, _lightpacks()
{
_devConfig = deviceConfig;
_deviceReady = false;
_isDeviceReady = false;
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
{
for (LedDeviceLightpack * device : _lightpacks)
{
delete device;
if ( device != nullptr)
{
delete device;
}
}
}
@@ -38,14 +43,12 @@ LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig)
return new LedDeviceMultiLightpack(deviceConfig);
}
int LedDeviceMultiLightpack::open()
bool LedDeviceMultiLightpack::init(const QJsonObject &deviceConfig)
{
int retval = -1;
QString errortext;
_deviceReady = false;
bool isInitOK = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
// Initialise sub-class
if ( LedDevice::init(deviceConfig) )
{
// retrieve a list with Lightpack serials
QStringList serialList = getLightpackSerials();
@@ -53,47 +56,84 @@ int LedDeviceMultiLightpack::open()
// sort the list of Lightpacks based on the serial to get a fixed order
std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks);
// open each lightpack device
// open each Lightpack device
for (auto serial : serialList)
{
LedDeviceLightpack * device = new LedDeviceLightpack(serial);
int error = device->open();
QJsonObject devConfig;
devConfig["serial"] = serial;
devConfig["latchTime"] = deviceConfig["latchTime"];
devConfig["rewriteTime"] = deviceConfig["rewriteTime"];
if (error == 0)
LedDeviceLightpack * device = new LedDeviceLightpack(devConfig);
device->start();
if (device->open() == 0)
{
_lightpacks.push_back(device);
}
else
{
//Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
errortext = QString ("Error while creating Lightpack device with serial %1").arg( serial );
Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
delete device;
}
}
if (_lightpacks.size() == 0)
if (_lightpacks.empty())
{
//Warning(_log, "No Lightpack devices were found");
errortext = QString ("No Lightpack devices were found");
QString errortext = QString ("No Lightpack devices were found");
this->setInError(errortext);
isInitOK = false;
}
else
{
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
// Everything is OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
}
// On error/exceptions, set LedDevice in error
if ( retval < 0 )
{
this->setInError( errortext );
isInitOK = true;
}
}
return isInitOK;
}
int LedDeviceMultiLightpack::open()
{
int retval = -1;
_isDeviceReady = false;
int lightsInError = 0;
// open each Lightpack device
for (LedDeviceLightpack * device : _lightpacks)
{
if (device->open() < 0)
{
Error( _log, "Failed to open [%s]", QSTRING_CSTR(device->getSerialNumber()) );
++lightsInError;
}
}
if ( lightsInError < static_cast<int>(_lightpacks.size()) )
{
// Everything is OK -> enable device
_isDeviceReady = true;
retval = 0;
}
else
{
this->setInError( "All Lightpacks failed to be opened!" );
}
return retval;
}
int LedDeviceMultiLightpack::close()
{
_isDeviceReady = false;
for (LedDeviceLightpack * device : _lightpacks)
{
device->close();
}
return 0;
}
int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
{
const ColorRgb * data = ledValues.data();
@@ -105,7 +145,10 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
if (count > 0)
{
device->write(data, count);
if ( device->isOpen() )
{
device->write(data, count);
}
data += count;
size -= count;
@@ -119,14 +162,16 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
return 0;
}
int LedDeviceMultiLightpack::switchOff()
bool LedDeviceMultiLightpack::powerOff()
{
for (LedDeviceLightpack * device : _lightpacks)
{
device->switchOff();
if ( device->isOpen() )
{
device->powerOff();
}
}
return 0;
return true;
}
QStringList LedDeviceMultiLightpack::getLightpackSerials()
@@ -135,7 +180,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
Logger * log = Logger::getInstance("LedDevice");
Debug(log, "Getting list of Lightpack serials");
// initialize the usb context
// initialize the USB context
libusb_context * libusbContext;
int error = libusb_init(&libusbContext);
if (error != LIBUSB_SUCCESS)
@@ -147,7 +192,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
//libusb_set_debug(_libusbContext, 3);
Info(log, "USB context initialized in multi Lightpack device");
// retrieve the list of usb devices
// retrieve the list of USB devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(libusbContext, &deviceList);
@@ -165,7 +210,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
Info(log, "Found a lightpack device. Retrieving serial...");
Info(log, "Found a Lightpack device. Retrieving serial...");
// get the serial number
QString serialNumber;
@@ -183,7 +228,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
}
}
Error(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));;
Info(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));
serialList.append(serialNumber);
}
}

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef LEDEVICEMULTILIGHTPACK_H
#define LEDEVICEMULTILIGHTPACK_H
// stl includes
#include <vector>
@@ -19,43 +20,67 @@
class LedDeviceMultiLightpack : public LedDevice
{
public:
///
/// Constructs specific LedDevice
///
explicit LedDeviceMultiLightpack(const QJsonObject &);
///
/// Destructor of the LedDevice; closes the output device if it is open
/// @brief Constructs a LedDevice of multiple Lightpack LED-devices
///
/// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceMultiLightpack(const QJsonObject &deviceConfig);
///
/// @brief Destructor of the LedDevice
///
virtual ~LedDeviceMultiLightpack() override;
/// constructs leddevice
///
/// @brief Constructs the LED-device
///
/// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed
///
static LedDevice* construct(const QJsonObject &deviceConfig);
///
virtual int switchOff() override;
protected:
///
/// Opens and configures the output device7
/// @brief Initialise the device's configuration
///
/// @return Zero on succes else negative
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
int open() override;
virtual bool init(const QJsonObject &deviceConfig) override;
///
/// Switch the leds off
/// @brief Opens the output device.
///
/// @return Zero on success else negative
/// @return Zero on success (i.e. device is ready), else negative
///
virtual int open() override;
///
/// @brief Closes the output device.
///
/// @return Zero on success (i.e. device is closed), else negative
///
virtual int close() override;
///
/// @brief Power-/turn off the Nanoleaf device.
///
/// @return True if success
///
virtual bool powerOff() override;
///
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative
///
int write(const std::vector<ColorRgb> & ledValues) override;
private:
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues) override;
static QStringList getLightpackSerials();
static QString getString(libusb_device * device, int stringDescriptorIndex);
@@ -63,3 +88,5 @@ private:
/// buffer for led data
std::vector<LedDeviceLightpack *> _lightpacks;
};
#endif // LEDEVICEMULTILIGHTPACK_H

View File

@@ -5,9 +5,11 @@ LedDevicePaintpack::LedDevicePaintpack(const QJsonObject &deviceConfig)
: ProviderHID()
{
_devConfig = deviceConfig;
_deviceReady = false;
_isDeviceReady = false;
_useFeature = false;
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
@@ -17,12 +19,17 @@ LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
bool LedDevicePaintpack::init(const QJsonObject &deviceConfig)
{
bool isInitOK = ProviderHID::init(deviceConfig);
bool isInitOK = false;
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
_ledBuffer[0] = 3;
_ledBuffer[1] = 0;
// Initialise sub-class
if ( ProviderHID::init(deviceConfig) )
{
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
_ledBuffer[0] = 3;
_ledBuffer[1] = 0;
isInitOK = true;
}
return isInitOK;
}

View File

@@ -1,38 +1,48 @@
#pragma once
#ifndef LEDEVICEPAINTTPACK_H
#define LEDEVICEPAINTTPACK_H
// Hyperion includes
#include "ProviderHID.h"
///
/// LedDevice implementation for a paintpack device ()
/// LedDevice implementation for a paintpack LED-device
///
class LedDevicePaintpack : public ProviderHID
{
public:
///
/// Constructs specific LedDevice
/// @brief Constructs a Paintpack LED-device
///
/// @param deviceConfig json device config
/// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDevicePaintpack(const QJsonObject &deviceConfig);
/// constructs leddevice
///
/// @brief Constructs the LED-device
///
/// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed
///
static LedDevice* construct(const QJsonObject &deviceConfig);
private:
///
/// Sets configuration
/// @brief Initialise the device's configuration
///
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
/// Writes the RGB-Color values to the leds.
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues The RGB-color per led
/// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues) override;
virtual int write(const std::vector<ColorRgb> & ledValues) override;
};
#endif // LEDEVICEPAINTTPACK_H

View File

@@ -5,7 +5,9 @@ LedDeviceRawHID::LedDeviceRawHID(const QJsonObject &deviceConfig)
: ProviderHID()
{
_devConfig = deviceConfig;
_deviceReady = false;
_isDeviceReady = false;
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
_useFeature = true;
}
@@ -17,10 +19,14 @@ LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
bool LedDeviceRawHID::init(const QJsonObject &deviceConfig)
{
bool isInitOK = ProviderHID::init(deviceConfig);
_ledBuffer.resize(_ledRGBCount);
bool isInitOK = false;
// Initialise sub-class
if ( ProviderHID::init(deviceConfig) )
{
_ledBuffer.resize(_ledRGBCount);
isInitOK = true;
}
return isInitOK;
}

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef LEDEVICERAWHID_H
#define LEDEVICERAWHID_H
// Qt includes
#include <QTimer>
@@ -11,31 +12,40 @@
///
class LedDeviceRawHID : public ProviderHID
{
public:
///
/// Constructs specific LedDevice
/// @brief Constructs a Raw-HID LED-device
///
/// @param deviceConfig json device config
/// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceRawHID(const QJsonObject &deviceConfig);
/// constructs leddevice
///
/// @brief Constructs the LED-device
///
/// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed
///
static LedDevice* construct(const QJsonObject &deviceConfig);
private:
///
/// Sets configuration
/// @brief Initialise the device's configuration
///
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
/// Writes the led color values to the led-device
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
/// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues) override;
};
#endif // LEDEVICERAWHID_H

View File

@@ -21,54 +21,59 @@ ProviderHID::ProviderHID()
ProviderHID::~ProviderHID()
{
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
}
hid_exit();
}
bool ProviderHID::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
bool isInitOK = false;
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
auto ProductIdString = deviceConfig["PID"].toString("0x8036").toStdString();
// Initialise sub-class
if ( LedDevice::init(deviceConfig) )
{
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
auto ProductIdString = deviceConfig["PID"].toString("0x8036").toStdString();
// Convert HEX values to integer
_VendorId = std::stoul(VendorIdString, nullptr, 16);
_ProductId = std::stoul(ProductIdString, nullptr, 16);
// Convert HEX values to integer
_VendorId = std::stoul(VendorIdString, nullptr, 16);
_ProductId = std::stoul(ProductIdString, nullptr, 16);
// Initialize the USB context
if ( hid_init() != 0)
{
this->setInError("Error initializing the HIDAPI context");
isInitOK = false;
}
else
{
Debug(_log,"HIDAPI initialized");
isInitOK = true;
}
}
return isInitOK;
}
int ProviderHID::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
_isDeviceReady = false;
if ( init(_devConfig) )
// Open the device
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
if (_deviceHandle == nullptr)
{
// Initialize the usb context
int error = hid_init();
if (error != 0)
{
//Error(_log, "Error while initializing the hidapi context");
errortext = "Error while initializing the hidapi context";
}
else
{
Debug(_log,"Hidapi initialized");
// Failed to open the device
this->setInError( "Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo." );
// Open the device
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
if (_deviceHandle == nullptr)
{
// Failed to open the device
Error(_log,"Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo.");
errortext = "Failed to open HID device";
// http://www.signal11.us/oss/hidapi/
/*
// http://www.signal11.us/oss/hidapi/
/*
std::cout << "Showing a list of all available HID devices:" << std::endl;
auto devs = hid_enumerate(0x00, 0x00);
auto cur_dev = devs;
@@ -83,45 +88,38 @@ int ProviderHID::open()
}
hid_free_enumeration(devs);
*/
}
else
{
Info(_log,"Opened HID device successful");
// Everything is OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
}
// Wait after device got opened if enabled
if (_delayAfterConnect_ms > 0)
{
_blockedForDelay = true;
QTimer::singleShot(_delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
}
}
// On error/exceptions, set LedDevice in error
if ( retval < 0 )
{
this->setInError( errortext );
}
}
else
{
Info(_log,"Opened HID device successful");
// Everything is OK -> enable device
_isDeviceReady = true;
retval = 0;
}
// Wait after device got opened if enabled
if (_delayAfterConnect_ms > 0)
{
_blockedForDelay = true;
QTimer::singleShot(_delayAfterConnect_ms, this, &ProviderHID::unblockAfterDelay );
Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
}
return retval;
}
void ProviderHID::close()
int ProviderHID::close()
{
LedDevice::close();
int retval = 0;
_isDeviceReady = false;
// LedDevice specific closing activites
// LedDevice specific closing activities
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
_deviceHandle = nullptr;
}
hid_exit();
return retval;
}
int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
@@ -138,7 +136,7 @@ int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
// Try again in 3 seconds
int delay_ms = 3000;
_blockedForDelay = true;
QTimer::singleShot(delay_ms, this, SLOT(unblockAfterDelay()));
QTimer::singleShot(delay_ms, this, &ProviderHID::unblockAfterDelay );
Debug(_log,"Device blocked for %d ms", delay_ms);
}
// Return here, to not write led data if the device should be blocked after connect
@@ -188,3 +186,38 @@ void ProviderHID::unblockAfterDelay()
Debug(_log,"Device unblocked");
_blockedForDelay = false;
}
QJsonObject ProviderHID::discover()
{
QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
QJsonArray deviceList;
// Discover HID Devices
auto devs = hid_enumerate(0x00, 0x00);
if ( devs != nullptr )
{
auto cur_dev = devs;
while (cur_dev)
{
QJsonObject deviceInfo;
deviceInfo.insert("manufacturer",QString::fromWCharArray(cur_dev->manufacturer_string));
deviceInfo.insert("path",cur_dev->path);
deviceInfo.insert("productIdentifier", QString("0x%1").arg(static_cast<ushort>(cur_dev->product_id),0,16));
deviceInfo.insert("release_number",QString("0x%1").arg(static_cast<ushort>(cur_dev->release_number),0,16));
deviceInfo.insert("serialNumber",QString::fromWCharArray(cur_dev->serial_number));
deviceInfo.insert("usage_page", QString("0x%1").arg(static_cast<ushort>(cur_dev->usage_page),0,16));
deviceInfo.insert("vendorIdentifier", QString("0x%1").arg(static_cast<ushort>(cur_dev->vendor_id),0,16));
deviceInfo.insert("interface_number",cur_dev->interface_number);
deviceList.append(deviceInfo);
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
}
devicesDiscovered.insert("devices", deviceList);
return devicesDiscovered;
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include <QObject>
#ifndef PROVIDERHID_H
#define PROVIDERHID_H
// libusb include
#include <hidapi/hidapi.h>
@@ -16,46 +15,57 @@ class ProviderHID : public LedDevice
Q_OBJECT
public:
///
/// Constructs specific LedDevice
/// @brief Constructs a HID (USB) LED-device
///
/// @param deviceConfig Device's configuration as JSON-Object
///
ProviderHID();
///
/// Destructor of the LedDevice; closes the output device if it is open
/// @brief Destructor of the LedDevice
///
virtual ~ProviderHID() override;
///
/// Sets configuration
/// @brief Discover HIB (USB) devices available (for configuration).
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
public slots:
/// @return A JSON structure holding a list of devices found
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
virtual QJsonObject discover() override;
protected:
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open() override;
/**
* Writes the given bytes to the HID-device and
*
* @param[in] size The length of the data
* @param[in] data The data
*
* @return Zero on succes else negative
*/
///
/// @brief Initialise the device's configuration
///
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
virtual bool init(const QJsonObject &deviceConfig) override;
///
/// @brief Opens the output device.
///
/// @return Zero on success (i.e. device is ready), else negative
///
virtual int open() override;
///
/// @brief Closes the output device.
///
/// @return Zero on success (i.e. device is closed), else negative
///
virtual int close() override;
///
/// @brief Write the given bytes to the HID-device
///
/// @param[in[ size The length of the data
/// @param[in] data The data
/// @return Zero on success, else negative
///
int writeBytes(const unsigned size, const uint8_t *data);
// HID VID and PID
@@ -74,4 +84,10 @@ protected:
private slots:
/// Unblock the device after a connection delay
void unblockAfterDelay();
private:
};
#endif // PROVIDERHID_H