// STL includes #include #include // Qt includes #include // Local Hyperion includes #include "ProviderHID.h" ProviderHID::ProviderHID() : _useFeature(false) , _deviceHandle(nullptr) , _blockedForDelay(false) { } ProviderHID::~ProviderHID() { if (_deviceHandle != nullptr) { hid_close(_deviceHandle); _deviceHandle = nullptr; } hid_exit(); } bool ProviderHID::init(const Json::Value &deviceConfig) { _delayAfterConnect_ms = deviceConfig.get("delayAfterConnect", 0 ).asInt(); auto VendorIdString = deviceConfig.get("VID", "0x2341").asString(); auto ProductIdString = deviceConfig.get("PID", "0x8036").asString(); // Convert HEX values to integer _VendorId = std::stoul(VendorIdString, nullptr, 16); _ProductId = std::stoul(ProductIdString, nullptr, 16); return true; } int ProviderHID::open() { // Initialize the usb context int error = hid_init(); if (error != 0) { Error(_log, "Error while initializing the hidapi context"); return -1; } Debug(_log,"Hidapi initialized"); // 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."); // 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 { Info(_log,"Opened HID device successful"); } // 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); } return 0; } int ProviderHID::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 delay_ms = 3000; _blockedForDelay = true; QTimer::singleShot(delay_ms, this, SLOT(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 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){ Error(_log,"Failed to write to HID device."); // 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){ Error(_log,"Failed to write to HID device."); hid_close(_deviceHandle); _deviceHandle = nullptr; } } return ret; } void ProviderHID::unblockAfterDelay() { Debug(_log,"Device unblocked"); _blockedForDelay = false; }