diff --git a/deploy/hyperion_imx6.tar.gz.REMOVED.git-id b/deploy/hyperion_imx6.tar.gz.REMOVED.git-id index 1243e5d8..294f2909 100644 --- a/deploy/hyperion_imx6.tar.gz.REMOVED.git-id +++ b/deploy/hyperion_imx6.tar.gz.REMOVED.git-id @@ -1 +1 @@ -9a4c5499f7191aad3e23e0e3be806861a3ec1c02 \ No newline at end of file +3785db40d7232275fbc00b20e627280e0e057f99 \ No newline at end of file diff --git a/deploy/hyperion_rpi.tar.gz.REMOVED.git-id b/deploy/hyperion_rpi.tar.gz.REMOVED.git-id index a429abf8..0f6903ba 100644 --- a/deploy/hyperion_rpi.tar.gz.REMOVED.git-id +++ b/deploy/hyperion_rpi.tar.gz.REMOVED.git-id @@ -1 +1 @@ -3a346e54f8958f87ae7f4e8804f6afdec33aa9fc \ No newline at end of file +0769228a95e4a0d4b2ed6649f21ddf70b43773d6 \ No newline at end of file diff --git a/deploy/hyperion_wetek.tar.gz.REMOVED.git-id b/deploy/hyperion_wetek.tar.gz.REMOVED.git-id index e38beaa9..4a4621a7 100644 --- a/deploy/hyperion_wetek.tar.gz.REMOVED.git-id +++ b/deploy/hyperion_wetek.tar.gz.REMOVED.git-id @@ -1 +1 @@ -05227980ea998eeeecda03cefe090b5f55ff8ee0 \ No newline at end of file +7e53ee35b7258e7d58d96514701a50014a98da31 \ No newline at end of file diff --git a/deploy/hyperion_x32.tar.gz.REMOVED.git-id b/deploy/hyperion_x32.tar.gz.REMOVED.git-id index c189c367..24239241 100644 --- a/deploy/hyperion_x32.tar.gz.REMOVED.git-id +++ b/deploy/hyperion_x32.tar.gz.REMOVED.git-id @@ -1 +1 @@ -f3e3f4a3a8e52e4bfaf9a0337cb364da841e150b \ No newline at end of file +36d03bb18626fa0faea8aabf6426e571eab4f719 \ No newline at end of file diff --git a/deploy/hyperion_x64.tar.gz.REMOVED.git-id b/deploy/hyperion_x64.tar.gz.REMOVED.git-id index ca1bf5dd..f6368736 100644 --- a/deploy/hyperion_x64.tar.gz.REMOVED.git-id +++ b/deploy/hyperion_x64.tar.gz.REMOVED.git-id @@ -1 +1 @@ -9342bb64479ea4d5554f301b905a0a830e330635 \ No newline at end of file +6f86ceeb6650e527d179cf7153e0beada3b73889 \ No newline at end of file diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index 16463fb5..d6d4682c 100755 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -18,6 +18,8 @@ SET(Leddevice_QT_HEADERS ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.h ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.h ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.h + ${CURRENT_SOURCE_DIR}/LedHIDDevice.h + ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.h ) SET(Leddevice_HEADERS @@ -39,10 +41,12 @@ SET(Leddevice_SOURCES ${CURRENT_SOURCE_DIR}/LedDeviceFactory.cpp ${CURRENT_SOURCE_DIR}/LedRs232Device.cpp + ${CURRENT_SOURCE_DIR}/LedHIDDevice.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.cpp ${CURRENT_SOURCE_DIR}/LedDeviceLightpack.cpp ${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.cpp ${CURRENT_SOURCE_DIR}/LedDevicePaintpack.cpp diff --git a/libsrc/leddevice/LedDeviceAPA102.cpp b/libsrc/leddevice/LedDeviceAPA102.cpp index 2af01acf..26a21f72 100644 --- a/libsrc/leddevice/LedDeviceAPA102.cpp +++ b/libsrc/leddevice/LedDeviceAPA102.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // Linux includes #include @@ -21,14 +22,18 @@ LedDeviceAPA102::LedDeviceAPA102(const std::string& outputDevice, const unsigned int LedDeviceAPA102::write(const std::vector &ledValues) { const unsigned int startFrameSize = 4; - const unsigned int endFrameSize = (ledValues.size() + 63) / 64 * 4; + const unsigned int endFrameSize = std::max(((ledValues.size() + 15) / 16), 4); const unsigned int mLedCount = (ledValues.size() * 4) + startFrameSize + endFrameSize; if(_ledBuffer.size() != mLedCount){ - _ledBuffer.resize(mLedCount, 0x00); + _ledBuffer.resize(mLedCount, 0xFF); + _ledBuffer[0] = 0x00; + _ledBuffer[1] = 0x00; + _ledBuffer[2] = 0x00; + _ledBuffer[3] = 0x00; } - + for (unsigned iLed=1; iLed<=ledValues.size(); ++iLed) { - const ColorRgb& rgb = ledValues[iLed]; + const ColorRgb& rgb = ledValues[iLed-1]; _ledBuffer[iLed*4] = 0xFF; _ledBuffer[iLed*4+1] = rgb.red; _ledBuffer[iLed*4+2] = rgb.green; diff --git a/libsrc/leddevice/LedDeviceAdalight.h b/libsrc/leddevice/LedDeviceAdalight.h index 66d299d1..650fdfb1 100644 --- a/libsrc/leddevice/LedDeviceAdalight.h +++ b/libsrc/leddevice/LedDeviceAdalight.h @@ -6,7 +6,7 @@ // Qt includes #include -// hyperion incluse +// hyperion include #include "LedRs232Device.h" /// diff --git a/libsrc/leddevice/LedDeviceAdalightApa102.cpp b/libsrc/leddevice/LedDeviceAdalightApa102.cpp index 172e76de..07732080 100644 --- a/libsrc/leddevice/LedDeviceAdalightApa102.cpp +++ b/libsrc/leddevice/LedDeviceAdalightApa102.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // Linux includes #include @@ -23,10 +24,10 @@ LedDeviceAdalightApa102::LedDeviceAdalightApa102(const std::string& outputDevice int LedDeviceAdalightApa102::write(const std::vector & ledValues) { const unsigned int startFrameSize = 4; - const unsigned int endFrameSize = (ledValues.size() + 63) / 64 * 4; + const unsigned int endFrameSize = std::max(((ledValues.size() + 15) / 16), 4); const unsigned int mLedCount = (ledValues.size() * 4) + startFrameSize + endFrameSize; if(_ledBuffer.size() != mLedCount){ - _ledBuffer.resize(mLedCount, 0x00); + _ledBuffer.resize(mLedCount, 0xFF); _ledBuffer[0] = 'A'; _ledBuffer[1] = 'd'; _ledBuffer[2] = 'a'; @@ -36,7 +37,7 @@ int LedDeviceAdalightApa102::write(const std::vector & ledValues) } for (unsigned iLed=1; iLed<=ledValues.size(); iLed++) { - const ColorRgb& rgb = ledValues[iLed]; + const ColorRgb& rgb = ledValues[iLed-1]; _ledBuffer[iLed*4+6] = 0xFF; _ledBuffer[iLed*4+1+6] = rgb.red; _ledBuffer[iLed*4+2+6] = rgb.green; diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index ce8cb835..85f665a5 100755 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -23,6 +23,7 @@ #include "LedDeviceAdalight.h" #include "LedDeviceAmbiLed.h" +#include "LedDeviceRawHID.h" #include "LedDeviceLightpack.h" #include "LedDeviceMultiLightpack.h" #include "LedDevicePaintpack.h" @@ -147,6 +148,21 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) device = deviceTinkerforge; } #endif + else if (type == "rawhid") + { + const int delay_ms = deviceConfig["delayAfterConnect"].asInt(); + auto VendorIdString = deviceConfig.get("VID", "0x2341").asString(); + auto ProductIdString = deviceConfig.get("PID", "0x8036").asString(); + + // Convert HEX values to integer + auto VendorId = std::stoul(VendorIdString, nullptr, 16); + auto ProductId = std::stoul(ProductIdString, nullptr, 16); + + LedDeviceRawHID* deviceHID = new LedDeviceRawHID(VendorId, ProductId, delay_ms); + deviceHID->open(); + + device = deviceHID; + } else if (type == "lightpack") { const std::string output = deviceConfig.get("output", "").asString(); @@ -165,7 +181,15 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) } else if (type == "paintpack") { - LedDevicePaintpack * devicePainLightpack = new LedDevicePaintpack(); + const int delay_ms = deviceConfig["delayAfterConnect"].asInt(); + auto VendorIdString = deviceConfig.get("VID", "0x0EBF").asString(); + auto ProductIdString = deviceConfig.get("PID", "0x0025").asString(); + + // Convert HEX values to integer + auto VendorId = std::stoul(VendorIdString, nullptr, 16); + auto ProductId = std::stoul(ProductIdString, nullptr, 16); + + LedDevicePaintpack * devicePainLightpack = new LedDevicePaintpack(VendorId, ProductId, delay_ms); devicePainLightpack->open(); device = devicePainLightpack; diff --git a/libsrc/leddevice/LedDevicePaintpack.cpp b/libsrc/leddevice/LedDevicePaintpack.cpp index 7ed0c847..db87bf49 100644 --- a/libsrc/leddevice/LedDevicePaintpack.cpp +++ b/libsrc/leddevice/LedDevicePaintpack.cpp @@ -2,61 +2,25 @@ // Hyperion includes #include "LedDevicePaintpack.h" -LedDevicePaintpack::LedDevicePaintpack() : - LedDevice(), - _deviceHandle(nullptr) +// Use out report HID device +LedDevicePaintpack::LedDevicePaintpack(const unsigned short VendorId, const unsigned short ProductId, int delayAfterConnect_ms) : + LedHIDDevice(VendorId, ProductId, delayAfterConnect_ms, false), + _ledBuffer(0) { // empty } -int LedDevicePaintpack::open() + +int LedDevicePaintpack::write(const std::vector & ledValues) { - // initialize the usb context - int error = hid_init(); - if (error != 0) + if (_ledBuffer.size() < 2 + ledValues.size()*3) { - std::cerr << "Error while initializing the hidapi context" << std::endl; - return -1; - } - std::cout << "Hidapi initialized" << std::endl; - - // Initialise the paintpack device - const unsigned short Paintpack_VendorId = 0x0ebf; - const unsigned short Paintpack_ProductId = 0x0025; - _deviceHandle = hid_open(Paintpack_VendorId, Paintpack_ProductId, nullptr); - if (_deviceHandle == nullptr) - { - // Failed to open the device - std::cerr << "Failed to open HID Paintpakc device " << std::endl; - return -1; + _ledBuffer.resize(2 + ledValues.size()*3, uint8_t(0)); + _ledBuffer[0] = 3; + _ledBuffer[1] = 0; } - return 0; -} - -LedDevicePaintpack::~LedDevicePaintpack() -{ - if (_deviceHandle != nullptr) - { - hid_close(_deviceHandle); - _deviceHandle = nullptr; - } - - hid_exit(); -} - -int LedDevicePaintpack::write(const std::vector& ledValues) -{ - if (_ledBuffer.size() < 3 + ledValues.size()*3) - { - _ledBuffer.resize(3 + ledValues.size()*3, uint8_t(0)); - - _ledBuffer[0] = 0; - _ledBuffer[1] = 3; - _ledBuffer[2] = 0; - } - - auto bufIt = _ledBuffer.begin()+3; + auto bufIt = _ledBuffer.begin()+2; for (const ColorRgb & ledValue : ledValues) { *bufIt = ledValue.red; @@ -67,11 +31,12 @@ int LedDevicePaintpack::write(const std::vector& ledValues) ++bufIt; } - return hid_write(_deviceHandle, _ledBuffer.data(), _ledBuffer.size()); + return writeBytes(_ledBuffer.size(), _ledBuffer.data()); } + int LedDevicePaintpack::switchOff() { - std::fill(_ledBuffer.begin()+3, _ledBuffer.end(), uint8_t(0)); - return hid_write(_deviceHandle, _ledBuffer.data(), _ledBuffer.size()); + std::fill(_ledBuffer.begin() + 2, _ledBuffer.end(), uint8_t(0)); + return writeBytes(_ledBuffer.size(), _ledBuffer.data()); } diff --git a/libsrc/leddevice/LedDevicePaintpack.h b/libsrc/leddevice/LedDevicePaintpack.h index 327dc123..3ed91eab 100644 --- a/libsrc/leddevice/LedDevicePaintpack.h +++ b/libsrc/leddevice/LedDevicePaintpack.h @@ -3,34 +3,19 @@ // STL includes #include -// libusb include -#include - // Hyperion includes -#include +#include "LedHIDDevice.h" /// /// LedDevice implementation for a paintpack device () /// -class LedDevicePaintpack : public LedDevice +class LedDevicePaintpack : public LedHIDDevice { public: /** * Constructs the paintpack device */ - LedDevicePaintpack(); - - /** - * Destructs the paintpack device, closes USB connection if open - */ - virtual ~LedDevicePaintpack(); - - /** - * Opens the Paintpack device - * - * @return Zero on succes else negative - */ - int open(); + LedDevicePaintpack(const unsigned short VendorId, const unsigned short ProductId, int delayAfterConnect_ms); /// /// Writes the RGB-Color values to the leds. @@ -49,11 +34,6 @@ public: virtual int switchOff(); private: - /// libusb device handle - hid_device * _deviceHandle; - /// buffer for led data std::vector _ledBuffer; - - }; diff --git a/libsrc/leddevice/LedDeviceRawHID.cpp b/libsrc/leddevice/LedDeviceRawHID.cpp new file mode 100644 index 00000000..18d678c3 --- /dev/null +++ b/libsrc/leddevice/LedDeviceRawHID.cpp @@ -0,0 +1,57 @@ + +// STL includes +#include +#include +#include + +// Linux includes +#include +#include + +// hyperion local includes +#include "LedDeviceRawHID.h" + +// Use feature report HID device +LedDeviceRawHID::LedDeviceRawHID(const unsigned short VendorId, const unsigned short ProductId, int delayAfterConnect_ms) : + LedHIDDevice(VendorId, ProductId, delayAfterConnect_ms, true), + _ledBuffer(0), + _timer() +{ + // setup the timer + _timer.setSingleShot(false); + _timer.setInterval(5000); + connect(&_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds())); + + // start the timer + _timer.start(); +} + +int LedDeviceRawHID::write(const std::vector & ledValues) +{ + // Resize buffer if required + if (_ledBuffer.size() < ledValues.size() * 3) { + _ledBuffer.resize(3 * ledValues.size()); + } + + // restart the timer + _timer.start(); + + // write data + memcpy(_ledBuffer.data(), ledValues.data(), ledValues.size() * 3); + return writeBytes(_ledBuffer.size(), _ledBuffer.data()); +} + +int LedDeviceRawHID::switchOff() +{ + // restart the timer + _timer.start(); + + // write data + std::fill(_ledBuffer.begin(), _ledBuffer.end(), uint8_t(0)); + return writeBytes(_ledBuffer.size(), _ledBuffer.data()); +} + +void LedDeviceRawHID::rewriteLeds() +{ + writeBytes(_ledBuffer.size(), _ledBuffer.data()); +} diff --git a/libsrc/leddevice/LedDeviceRawHID.h b/libsrc/leddevice/LedDeviceRawHID.h new file mode 100644 index 00000000..6e23fe02 --- /dev/null +++ b/libsrc/leddevice/LedDeviceRawHID.h @@ -0,0 +1,48 @@ +#pragma once + +// STL includes +#include + +// Qt includes +#include + +// hyperion include +#include "LedHIDDevice.h" + +/// +/// Implementation of the LedDevice interface for writing to an RawHID led device. +/// +class LedDeviceRawHID : public LedHIDDevice +{ + Q_OBJECT + +public: + /// + /// Constructs the LedDevice for attached RawHID device + /// + LedDeviceRawHID(const unsigned short VendorId, const unsigned short ProductId, int delayAfterConnect_ms); + + /// + /// Writes the led color values to the led-device + /// + /// @param ledValues The color-value per led + /// @return Zero on succes else negative + /// + virtual int write(const std::vector & ledValues); + + /// Switch the leds off + virtual int switchOff(); + +private slots: + /// Write the last data to the leds again + void rewriteLeds(); + +private: + /// The buffer containing the packed RGB values + std::vector _ledBuffer; + + /// Timer object which makes sure that led data is written at a minimum rate + /// The RawHID device will switch off when it does not receive data at least + /// every 15 seconds + QTimer _timer; +}; diff --git a/libsrc/leddevice/LedHIDDevice.cpp b/libsrc/leddevice/LedHIDDevice.cpp new file mode 100644 index 00000000..0ed53524 --- /dev/null +++ b/libsrc/leddevice/LedHIDDevice.cpp @@ -0,0 +1,152 @@ + +// STL includes +#include +#include + +// Qt includes +#include + +// Local Hyperion includes +#include "LedHIDDevice.h" + +LedHIDDevice::LedHIDDevice(const unsigned short VendorId, const unsigned short ProductId, int delayAfterConnect_ms, const bool useFeature) : + _VendorId(VendorId), + _ProductId(ProductId), + _useFeature(useFeature), + _deviceHandle(nullptr), + _delayAfterConnect_ms(delayAfterConnect_ms), + _blockedForDelay(false) +{ + // empty +} + +LedHIDDevice::~LedHIDDevice() +{ + if (_deviceHandle != nullptr) + { + hid_close(_deviceHandle); + _deviceHandle = nullptr; + } + + hid_exit(); +} + +int LedHIDDevice::open() +{ + // Initialize the usb context + int error = hid_init(); + if (error != 0) + { + std::cerr << "Error while initializing the hidapi context" << std::endl; + return -1; + } + std::cout << "Hidapi initialized" << std::endl; + + // Open the device + printf("Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId); + _deviceHandle = hid_open(_VendorId, _ProductId, nullptr); + + if (_deviceHandle == nullptr) + { + // Failed to open the device + std::cerr << "Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo." << std::endl; + + // 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; + while (cur_dev) { + printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", + cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); + printf("\n"); + printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); + printf(" Product: %ls\n", cur_dev->product_string); + printf("\n"); + cur_dev = cur_dev->next; + } + hid_free_enumeration(devs); + */ + + return -1; + } + else{ + std::cout << "Opened HID device successful" << std::endl; + } + + // Wait after device got opened if enabled + if (_delayAfterConnect_ms > 0) + { + _blockedForDelay = true; + QTimer::singleShot(_delayAfterConnect_ms, this, SLOT(unblockAfterDelay())); + std::cout << "Device blocked for " << _delayAfterConnect_ms << " ms" << std::endl; + } + + return 0; +} + + +int LedHIDDevice::writeBytes(const unsigned size, const uint8_t * data) +{ + if (_blockedForDelay) { + return 0; + } + + if (_deviceHandle == nullptr) + { + // try to reopen + auto status = open(); + if(status < 0){ + // Try again in 3 seconds + int seconds = 3000; + _blockedForDelay = true; + QTimer::singleShot(seconds, this, SLOT(unblockAfterDelay())); + std::cout << "Device blocked for " << seconds << " ms" << std::endl; + } + // Return here, to not write led data if the device should be blocked after connect + return status; + } + + // Prepend report ID to the buffer + uint8_t ledData[size + 1]; + ledData[0] = 0; // Report ID + memcpy(ledData + 1, data, size_t(size)); + + // Send data via feature or out report + int ret; + if(_useFeature){ + ret = hid_send_feature_report(_deviceHandle, ledData, size + 1); + } + else{ + ret = hid_write(_deviceHandle, ledData, size + 1); + } + + // Handle first error + if(ret < 0){ + std::cerr << "Failed to write to HID device." << std::endl; + + // Try again + if(_useFeature){ + ret = hid_send_feature_report(_deviceHandle, ledData, size + 1); + } + else{ + ret = hid_write(_deviceHandle, ledData, size + 1); + } + + // Writing failed again, device might have disconnected + if(ret < 0){ + std::cerr << "Failed to write to HID device." << std::endl; + + hid_close(_deviceHandle); + _deviceHandle = nullptr; + } + } + + return ret; +} + +void LedHIDDevice::unblockAfterDelay() +{ + std::cout << "Device unblocked" << std::endl; + _blockedForDelay = false; +} diff --git a/libsrc/leddevice/LedHIDDevice.h b/libsrc/leddevice/LedHIDDevice.h new file mode 100644 index 00000000..fb4aa6b3 --- /dev/null +++ b/libsrc/leddevice/LedHIDDevice.h @@ -0,0 +1,66 @@ +#pragma once + +#include + +// libusb include +#include + +// Leddevice includes +#include + +/// +/// The LedHIDDevice implements an abstract base-class for LedDevices using an HID-device. +/// +class LedHIDDevice : public QObject, public LedDevice +{ + Q_OBJECT + +public: + /// + /// Constructs the LedDevice attached to an HID-device + /// + /// @param[in] VendorId The USB VID of the output device + /// @param[in] ProductId The USB PID of the output device + /// + LedHIDDevice(const unsigned short VendorId, const unsigned short ProductId, int delayAfterConnect_ms = 0, const bool useFeature = false); + + /// + /// Destructor of the LedDevice; closes the output device if it is open + /// + virtual ~LedHIDDevice(); + + /// + /// Opens and configures the output device + /// + /// @return Zero on succes else negative + /// + int open(); +protected: + /** + * 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 + */ + int writeBytes(const unsigned size, const uint8_t *data); + +private slots: + /// Unblock the device after a connection delay + void unblockAfterDelay(); + +private: + // HID VID and PID + const unsigned short _VendorId; + const unsigned short _ProductId; + const bool _useFeature; + + /// libusb device handle + hid_device * _deviceHandle; + + /// Sleep after the connect before continuing + const int _delayAfterConnect_ms; + + bool _blockedForDelay; +};