From 409b800a8e883deb2ba1029baf2f9c547257b638 Mon Sep 17 00:00:00 2001 From: johan Date: Wed, 20 Nov 2013 20:54:04 +0100 Subject: [PATCH] Restructured Lightpack device (fix bug concerning the lifecycle of the libusb context) Former-commit-id: ef7187e9117d75208e4d79b9f64839f88044a3c2 --- deploy/hyperiond.REMOVED.git-id | 2 +- libsrc/hyperion/Hyperion.cpp | 4 +- libsrc/hyperion/device/LedDeviceLightpack.cpp | 74 ++++----- libsrc/hyperion/device/LedDeviceLightpack.h | 19 ++- .../device/LedDeviceMultiLightpack.cpp | 150 +++++++++++++----- .../hyperion/device/LedDeviceMultiLightpack.h | 5 + 6 files changed, 155 insertions(+), 99 deletions(-) diff --git a/deploy/hyperiond.REMOVED.git-id b/deploy/hyperiond.REMOVED.git-id index 1eec85ee..30be7ab4 100644 --- a/deploy/hyperiond.REMOVED.git-id +++ b/deploy/hyperiond.REMOVED.git-id @@ -1 +1 @@ -5031f4b1d3a2682b6df94ba6671bcc97f9b5a4d1 \ No newline at end of file +5078baeb33a6dca64d20161907b9638aeb047ffb \ No newline at end of file diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index b7c71183..dbfd123d 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -89,8 +89,8 @@ LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig) { const std::string output = deviceConfig.get("output", "").asString(); - LedDeviceLightpack* deviceLightpack = new LedDeviceLightpack(output); - deviceLightpack->open(); + LedDeviceLightpack* deviceLightpack = new LedDeviceLightpack(); + deviceLightpack->open(output); device = deviceLightpack; } diff --git a/libsrc/hyperion/device/LedDeviceLightpack.cpp b/libsrc/hyperion/device/LedDeviceLightpack.cpp index b8c8fbe2..1dd262ff 100644 --- a/libsrc/hyperion/device/LedDeviceLightpack.cpp +++ b/libsrc/hyperion/device/LedDeviceLightpack.cpp @@ -32,13 +32,13 @@ enum DATA_VERSION_INDEXES{ INDEX_FW_VER_MINOR }; -LedDeviceLightpack::LedDeviceLightpack(const std::string &serialNumber) : +LedDeviceLightpack::LedDeviceLightpack() : LedDevice(), _libusbContext(nullptr), _deviceHandle(nullptr), _busNumber(-1), _addressNumber(-1), - _serialNumber(serialNumber), + _serialNumber(""), _firmwareVersion({-1,-1}), _ledCount(-1), _bitsPerChannel(-1), @@ -64,7 +64,7 @@ LedDeviceLightpack::~LedDeviceLightpack() } } -int LedDeviceLightpack::open() +int LedDeviceLightpack::open(const std::string & serialNumber) { int error; @@ -86,7 +86,7 @@ int LedDeviceLightpack::open() for (ssize_t i = 0 ; i < deviceCount; ++i) { // try to open and initialize the device - error = open(deviceList[i]); + error = testAndOpen(deviceList[i], serialNumber); if (error == 0) { @@ -113,7 +113,7 @@ int LedDeviceLightpack::open() return _deviceHandle == nullptr ? -1 : 0; } -int LedDeviceLightpack::open(libusb_device * device) +int LedDeviceLightpack::testAndOpen(libusb_device * device, const std::string & requestedSerialNumber) { libusb_device_descriptor deviceDescriptor; int error = libusb_get_device_descriptor(device, &deviceDescriptor); @@ -147,22 +147,10 @@ int LedDeviceLightpack::open(libusb_device * device) } } - // get the firmware version - Version version = {-1,-1}; - try - { - version = LedDeviceLightpack::getVersion(device); - } - catch (int e) - { - std::cerr << "unable to retrieve firmware version number from Lightpack device(" << e << "): " << libusb_error_name(e) << std::endl; - version = {-1,-1}; - } - - std::cout << "Lightpack device found: bus=" << busNumber << " address=" << addressNumber << " serial=" << serialNumber << " version=" << version.majorVersion << "." << version.minorVersion << std::endl; + std::cout << "Lightpack device found: bus=" << busNumber << " address=" << addressNumber << " serial=" << serialNumber << std::endl; // check if this is the device we are looking for - if (_serialNumber.empty() || _serialNumber == serialNumber) + if (requestedSerialNumber.empty() || requestedSerialNumber == serialNumber) { // This is it! try @@ -174,6 +162,25 @@ int LedDeviceLightpack::open(libusb_device * device) std::cout << "Lightpack device successfully opened" << std::endl; + // get the firmware version + uint8_t buffer[256]; + error = libusb_control_transfer( + _deviceHandle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + 0x01, + 0x0100, + 0, + buffer, sizeof(buffer), 1000); + if (error < 3) + { + std::cerr << "Unable to retrieve firmware version number from Lightpack device(" << error << "): " << libusb_error_name(error) << std::endl; + } + else + { + _firmwareVersion.majorVersion = buffer[INDEX_FW_VER_MAJOR]; + _firmwareVersion.minorVersion = buffer[INDEX_FW_VER_MINOR]; + } + // FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6 _firmwareVersion.majorVersion = 6; @@ -206,6 +213,7 @@ int LedDeviceLightpack::open(libusb_device * device) _ledBuffer[0] = CMD_UPDATE_LEDS; // return success + std::cout << "Lightpack device opened: bus=" << _busNumber << " address=" << _addressNumber << " serial=" << _serialNumber << " version=" << _firmwareVersion.majorVersion << "." << _firmwareVersion.minorVersion << std::endl; return 0; } catch(int e) @@ -347,31 +355,3 @@ std::string LedDeviceLightpack::getString(libusb_device * device, int stringDesc libusb_close(handle); return std::string(buffer, error); } - -LedDeviceLightpack::Version LedDeviceLightpack::getVersion(libusb_device *device) -{ - libusb_device_handle * handle = nullptr; - - int error = libusb_open(device, &handle); - if (error != LIBUSB_SUCCESS) - { - throw error; - } - - uint8_t buffer[256]; - error = libusb_control_transfer( - handle, - LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - 0x01, - 0x0100, - 0, - buffer, sizeof(buffer), 1000); - if (error < 3) - { - libusb_close(handle); - throw error; - } - - libusb_close(handle); - return Version{buffer[INDEX_FW_VER_MAJOR], buffer[INDEX_FW_VER_MINOR]}; -} diff --git a/libsrc/hyperion/device/LedDeviceLightpack.h b/libsrc/hyperion/device/LedDeviceLightpack.h index 8c0ca245..6c4b2232 100644 --- a/libsrc/hyperion/device/LedDeviceLightpack.h +++ b/libsrc/hyperion/device/LedDeviceLightpack.h @@ -20,7 +20,7 @@ public: /// /// Constructs the LedDeviceLightpack /// - LedDeviceLightpack(const std::string & serialNumber = ""); + LedDeviceLightpack(); /// /// Destructor of the LedDevice; closes the output device if it is open @@ -32,14 +32,7 @@ public: /// /// @return Zero on succes else negative /// - int open(); - - /// - /// Opens and configures the output device with the sepcified device - /// - /// @return Zero on succes else negative - /// - int open(libusb_device * device); + int open(const std::string & serialNumber = ""); /// /// Writes the RGB-Color values to the leds. @@ -74,6 +67,13 @@ public: int getLedCount() const; private: + /// + /// Test if the device is a (or the) lightpack we are looking for + /// + /// @return Zero on succes else negative + /// + int testAndOpen(libusb_device * device, const std::string & requestedSerialNumber); + /// write bytes to the device int writeBytes(uint8_t *data, int size); @@ -88,7 +88,6 @@ private: static libusb_device_handle * openDevice(libusb_device * device); static std::string getString(libusb_device * device, int stringDescriptorIndex); - static Version getVersion(libusb_device * device); private: /// libusb context diff --git a/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp b/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp index a784bfa5..d6acc253 100644 --- a/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp +++ b/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp @@ -6,6 +6,12 @@ // Local Hyperion includes #include "LedDeviceMultiLightpack.h" +// from USB_ID.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/USB_ID.h) +#define USB_OLD_VENDOR_ID 0x03EB +#define USB_OLD_PRODUCT_ID 0x204F +#define USB_VENDOR_ID 0x1D50 +#define USB_PRODUCT_ID 0x6022 + bool compareLightpacks(LedDeviceLightpack * lhs, LedDeviceLightpack * rhs) { return lhs->getSerialNumber() < rhs->getSerialNumber(); @@ -27,49 +33,28 @@ LedDeviceMultiLightpack::~LedDeviceMultiLightpack() int LedDeviceMultiLightpack::open() { - int error; - - // initialize the usb context - libusb_context * libusbContext; - if ((error = libusb_init(&libusbContext)) != LIBUSB_SUCCESS) - { - std::cerr << "Error while initializing USB context(" << error << "): " << libusb_error_name(error) << std::endl; - libusbContext = nullptr; - return -1; - } - //libusb_set_debug(_libusbContext, 3); - std::cout << "USB context initialized in multi Lightpack device" << std::endl; - - // 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 the device as a Lightpack - LedDeviceLightpack * device = new LedDeviceLightpack(); - error = device->open(deviceList[i]); - - if (error == 0) - { - // Device is successfully opened as Lightpack - std::cout << "Lightpack with serial " << device->getSerialNumber() << " added to set of Lightpacks" << std::endl; - _lightpacks.push_back(device); - } - else - { - // No Lightpack... - delete device; - } - } + // retrieve a list with Lightpack serials + std::list serialList = getLightpackSerials(); // sort the list of Lightpacks based on the serial to get a fixed order std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks); - // free the device list - libusb_free_device_list(deviceList, 1); - libusb_exit(libusbContext); + // open each lightpack device + for (const std::string & serial : serialList) + { + LedDeviceLightpack * device = new LedDeviceLightpack(); + int error = device->open(serial); + + if (error == 0) + { + _lightpacks.push_back(device); + } + else + { + std::cerr << "Error while creating Lightpack device with serial " << serial << std::endl; + delete device; + } + } if (_lightpacks.size() == 0) { @@ -117,3 +102,90 @@ int LedDeviceMultiLightpack::switchOff() return 0; } + +std::list LedDeviceMultiLightpack::getLightpackSerials() +{ + std::list serialList; + + std::cout << "Getting list of Lightpack serials" << std::endl; + + // initialize the usb context + libusb_context * libusbContext; + int error = libusb_init(&libusbContext); + if (error != LIBUSB_SUCCESS) + { + std::cerr << "Error while initializing USB context(" << error << "): " << libusb_error_name(error) << std::endl; + libusbContext = nullptr; + return serialList; + } + //libusb_set_debug(_libusbContext, 3); + std::cout << "USB context initialized in multi Lightpack device" << std::endl; + + // 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) + { + libusb_device_descriptor deviceDescriptor; + error = libusb_get_device_descriptor(deviceList[i], &deviceDescriptor); + if (error != LIBUSB_SUCCESS) + { + std::cerr << "Error while retrieving device descriptor(" << error << "): " << libusb_error_name(error) << std::endl; + continue; + } + + if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) || + (deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID)) + { + std::cout << "Found a lightpack device. Retrieving serial..." << std::endl; + + // get the serial number + std::string serialNumber; + if (deviceDescriptor.iSerialNumber != 0) + { + try + { + serialNumber = LedDeviceMultiLightpack::getString(deviceList[i], deviceDescriptor.iSerialNumber); + } + catch (int e) + { + std::cerr << "Unable to retrieve serial number(" << e << "): " << libusb_error_name(e) << std::endl; + continue; + } + } + + std::cout << "Lightpack device found with serial " << serialNumber << std::endl; + serialList.push_back(serialNumber); + } + } + + // free the device list + libusb_free_device_list(deviceList, 1); + libusb_exit(libusbContext); + + return serialList; +} + +std::string LedDeviceMultiLightpack::getString(libusb_device * device, int stringDescriptorIndex) +{ + libusb_device_handle * handle = nullptr; + + int error = libusb_open(device, &handle); + if (error != LIBUSB_SUCCESS) + { + throw error; + } + + char buffer[256]; + error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast(buffer), sizeof(buffer)); + if (error <= 0) + { + libusb_close(handle); + throw error; + } + + libusb_close(handle); + return std::string(buffer, error); +} diff --git a/libsrc/hyperion/device/LedDeviceMultiLightpack.h b/libsrc/hyperion/device/LedDeviceMultiLightpack.h index 7126d96a..c7174ad3 100644 --- a/libsrc/hyperion/device/LedDeviceMultiLightpack.h +++ b/libsrc/hyperion/device/LedDeviceMultiLightpack.h @@ -4,6 +4,7 @@ #include #include #include +#include // libusb include #include @@ -51,6 +52,10 @@ public: /// virtual int switchOff(); +private: + static std::list getLightpackSerials(); + static std::string getString(libusb_device * device, int stringDescriptorIndex); + private: /// buffer for led data std::vector _lightpacks;