diff --git a/libsrc/leddevice/LedHIDDevice.cpp b/libsrc/leddevice/LedHIDDevice.cpp new file mode 100644 index 00000000..e1506560 --- /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?" << 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; +};