diff --git a/deploy/hyperiond.REMOVED.git-id b/deploy/hyperiond.REMOVED.git-id index 00f01af5..935b1da3 100644 --- a/deploy/hyperiond.REMOVED.git-id +++ b/deploy/hyperiond.REMOVED.git-id @@ -1 +1 @@ -1cb3f98f75d106f770d15416e067095bee750f8d \ No newline at end of file +b4ecb001b419687ffbef1bebb7c274bb31ea55f1 \ No newline at end of file diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 5cd73b84..937a8906 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -32,6 +32,7 @@ SET(Hyperion_HEADERS ${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.h ${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.h ${CURRENT_SOURCE_DIR}/device/LedDeviceLightpack.h + ${CURRENT_SOURCE_DIR}/device/LedDeviceMultiLightpack.h ) SET(Hyperion_SOURCES @@ -55,6 +56,7 @@ SET(Hyperion_SOURCES ${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.cpp ${CURRENT_SOURCE_DIR}/device/LedDeviceAdalight.cpp ${CURRENT_SOURCE_DIR}/device/LedDeviceLightpack.cpp + ${CURRENT_SOURCE_DIR}/device/LedDeviceMultiLightpack.cpp ) set(Hyperion_RESOURCES diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 124e15b3..b7c71183 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -20,6 +20,7 @@ #include "device/LedDeviceWs2801.h" #include "device/LedDeviceAdalight.h" #include "device/LedDeviceLightpack.h" +#include "device/LedDeviceMultiLightpack.h" #include "LinearColorSmoothing.h" @@ -93,6 +94,13 @@ LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig) device = deviceLightpack; } + else if (type == "multi-lightpack") + { + LedDeviceMultiLightpack* deviceLightpack = new LedDeviceMultiLightpack(); + deviceLightpack->open(); + + device = deviceLightpack; + } else if (type == "test") { const std::string output = deviceConfig["output"].asString(); diff --git a/libsrc/hyperion/device/LedDeviceLightpack.cpp b/libsrc/hyperion/device/LedDeviceLightpack.cpp index d3f0f2af..aea2d9d7 100644 --- a/libsrc/hyperion/device/LedDeviceLightpack.cpp +++ b/libsrc/hyperion/device/LedDeviceLightpack.cpp @@ -75,6 +75,7 @@ int LedDeviceLightpack::open() _libusbContext = nullptr; return -1; } + //libusb_set_debug(_libusbContext, 3); std::cout << "USB context initialized" << std::endl; // retrieve the list of usb devices @@ -84,112 +85,20 @@ int LedDeviceLightpack::open() // 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) + // try to open and initialize the device + error = open(deviceList[i]); + + if (error == 0) { - std::cerr << "Error while retrieving device descriptor(" << error << "): " << libusb_error_name(error) << std::endl; - // continue with next usb device - 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 more information..." << std::endl; - - // get the hardware address - int busNumber = libusb_get_bus_number(deviceList[i]); - int addressNumber = libusb_get_device_address(deviceList[i]); - - // get the serial number - std::string serialNumber; - if (deviceDescriptor.iSerialNumber != 0) - { - try - { - serialNumber = LedDeviceLightpack::getString(deviceList[i], deviceDescriptor.iSerialNumber); - } - catch (int e) - { - std::cerr << "unable to retrieve serial number from Lightpack device(" << e << "): " << libusb_error_name(e) << std::endl; - } - } - - // get the firmware version - Version version = {-1,-1}; - try - { - version = LedDeviceLightpack::getVersion(deviceList[i]); - } - catch (int e) - { - std::cerr << "unable to retrieve firmware version number from Lightpack device(" << e << "): " << libusb_error_name(e) << std::endl; - } - - std::cout << "Lightpack device found: bus=" << busNumber << " address=" << addressNumber << " serial=" << serialNumber << " version=" << version.majorVersion << "." << version.minorVersion << std::endl; - - // check if this is the device we are looking for - if (_serialNumber.empty() || _serialNumber == serialNumber) - { - // This is it! - try - { - _deviceHandle = openDevice(deviceList[i]); - _serialNumber = serialNumber; - _busNumber = busNumber; - _addressNumber = addressNumber; - - std::cout << "Lightpack device successfully opened" << std::endl; - - // break from the search loop - break; - } - catch(int e) - { - std::cerr << "unable to open Lightpack device. Searching for other device(" << e << "): " << libusb_error_name(e) << std::endl; - } - } + // a device was sucessfully opened. break from list + break; } } // free the device list libusb_free_device_list(deviceList, 1); - if (_deviceHandle != nullptr) - { - // FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6 - _firmwareVersion.majorVersion = 6; - - // disable smoothing of the chosen device - disableSmoothing(); - - // determine the number of leds - if (_firmwareVersion.majorVersion == 4) - { - _ledCount = 8; - } - else - { - _ledCount = 10; - } - - // determine the bits per channel - if (_firmwareVersion.majorVersion == 6) - { - // maybe also or version 7? The firmware suggest this is only for 6... (2013-11-13) - _bitsPerChannel = 12; - } - else - { - _bitsPerChannel = 8; - } - - // set the led buffer size (command + 6 bytes per led) - _ledBuffer = std::vector(1 + _ledCount * 6, 0); - _ledBuffer[0] = CMD_UPDATE_LEDS; - } - else + if (_deviceHandle == nullptr) { if (_serialNumber.empty()) { @@ -204,9 +113,120 @@ int LedDeviceLightpack::open() return _deviceHandle == nullptr ? -1 : 0; } +int LedDeviceLightpack::open(libusb_device * device) +{ + libusb_device_descriptor deviceDescriptor; + int error = libusb_get_device_descriptor(device, &deviceDescriptor); + if (error != LIBUSB_SUCCESS) + { + std::cerr << "Error while retrieving device descriptor(" << error << "): " << libusb_error_name(error) << std::endl; + return -1; + } + + 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 more information..." << std::endl; + + // get the hardware address + int busNumber = libusb_get_bus_number(device); + int addressNumber = libusb_get_device_address(device); + + // get the serial number + std::string serialNumber; + if (deviceDescriptor.iSerialNumber != 0) + { + try + { + serialNumber = LedDeviceLightpack::getString(device, deviceDescriptor.iSerialNumber); + } + catch (int e) + { + std::cerr << "unable to retrieve serial number from Lightpack device(" << e << "): " << libusb_error_name(e) << std::endl; + serialNumber = ""; + } + } + + // 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; + + // check if this is the device we are looking for + if (_serialNumber.empty() || _serialNumber == serialNumber) + { + // This is it! + try + { + _deviceHandle = openDevice(device); + _serialNumber = serialNumber; + _busNumber = busNumber; + _addressNumber = addressNumber; + + std::cout << "Lightpack device successfully opened" << std::endl; + + // FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6 + _firmwareVersion.majorVersion = 6; + + // disable smoothing of the chosen device + disableSmoothing(); + + // determine the number of leds + if (_firmwareVersion.majorVersion == 4) + { + _ledCount = 8; + } + else + { + _ledCount = 10; + } + + // determine the bits per channel + if (_firmwareVersion.majorVersion == 6) + { + // maybe also or version 7? The firmware suggest this is only for 6... (2013-11-13) + _bitsPerChannel = 12; + } + else + { + _bitsPerChannel = 8; + } + + // set the led buffer size (command + 6 bytes per led) + _ledBuffer = std::vector(1 + _ledCount * 6, 0); + _ledBuffer[0] = CMD_UPDATE_LEDS; + + // return success + return 0; + } + catch(int e) + { + _deviceHandle = nullptr; + std::cerr << "Unable to open Lightpack device. Searching for other device(" << e << "): " << libusb_error_name(e) << std::endl; + } + } + } + + return -1; +} + int LedDeviceLightpack::write(const std::vector &ledValues) { - int count = std::min(_ledCount, (int) ledValues.size()); + return write(ledValues.data(), ledValues.size()); +} + +int LedDeviceLightpack::write(const ColorRgb * ledValues, int size) +{ + int count = std::min(_ledCount, size); for (int i = 0; i < count ; ++i) { @@ -219,7 +239,7 @@ int LedDeviceLightpack::write(const std::vector &ledValues) _ledBuffer[6*i+3] = color.blue; // leave the next three bytes on zero... - // 12-bit values have zeros in the lowest 4 bits which is almost correct, but it saves extra + // 12-bit values having zeros in the lowest 4 bits which is almost correct, but it saves extra // switches to determine what to do and some bit shuffling } @@ -233,16 +253,36 @@ int LedDeviceLightpack::switchOff() return writeBytes(buf, sizeof(buf)) == sizeof(buf); } +const std::string &LedDeviceLightpack::getSerialNumber() const +{ + return _serialNumber; +} + +int LedDeviceLightpack::getLedCount() const +{ + return _ledCount; +} + int LedDeviceLightpack::writeBytes(uint8_t *data, int size) { - std::cout << "Writing " << size << " bytes to Lightpack device" << std::endl; +// std::cout << "Writing " << size << " bytes: "; +// for (int i = 0; i < size ; ++i) printf("%02x ", data[i]); +// std::cout << std::endl; - return libusb_control_transfer(_deviceHandle, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - 0x09, + int error = libusb_control_transfer(_deviceHandle, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + LIBUSB_REQUEST_SET_CONFIGURATION, (2 << 8), 0x00, - data, size, 100); + data, size, 1000); + + if (error == size) + { + return 0; + } + + std::cerr << "Unable to write " << size << " bytes to Lightpack device(" << error << "): " << libusb_error_name(error) << std::endl; + return error; } int LedDeviceLightpack::disableSmoothing() @@ -317,11 +357,11 @@ LedDeviceLightpack::Version LedDeviceLightpack::getVersion(libusb_device *device uint8_t buffer[256]; error = libusb_control_transfer( handle, - LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_INTERFACE, - LIBUSB_REQUEST_GET_DESCRIPTOR, - (LIBUSB_DT_REPORT << 8), + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + 0x01, + 0x0100, 0, - buffer, sizeof(buffer), 100); + buffer, sizeof(buffer), 1000); if (error < 3) { libusb_close(handle); diff --git a/libsrc/hyperion/device/LedDeviceLightpack.h b/libsrc/hyperion/device/LedDeviceLightpack.h index b68e0471..8c0ca245 100644 --- a/libsrc/hyperion/device/LedDeviceLightpack.h +++ b/libsrc/hyperion/device/LedDeviceLightpack.h @@ -28,12 +28,19 @@ public: virtual ~LedDeviceLightpack(); /// - /// Opens and configures the output device7 + /// Opens and configures the output device /// /// @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); + /// /// Writes the RGB-Color values to the leds. /// @@ -43,6 +50,16 @@ public: /// virtual int write(const std::vector& ledValues); + /// + /// 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 + /// + int write(const ColorRgb * ledValues, int size); + /// /// Switch the leds off /// @@ -50,19 +67,25 @@ public: /// virtual int switchOff(); -private: - struct Version - { - int majorVersion; - int minorVersion; - }; + /// Get the serial of the Lightpack + const std::string & getSerialNumber() const; + /// Get the number of leds + int getLedCount() const; + +private: /// write bytes to the device int writeBytes(uint8_t *data, int size); /// Disable the internal smoothing on the Lightpack device int disableSmoothing(); + struct Version + { + int majorVersion; + int minorVersion; + }; + static libusb_device_handle * openDevice(libusb_device * device); static std::string getString(libusb_device * device, int stringDescriptorIndex); static Version getVersion(libusb_device * device); diff --git a/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp b/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp new file mode 100644 index 00000000..a784bfa5 --- /dev/null +++ b/libsrc/hyperion/device/LedDeviceMultiLightpack.cpp @@ -0,0 +1,119 @@ +// stl includes +#include +#include +#include + +// Local Hyperion includes +#include "LedDeviceMultiLightpack.h" + +bool compareLightpacks(LedDeviceLightpack * lhs, LedDeviceLightpack * rhs) +{ + return lhs->getSerialNumber() < rhs->getSerialNumber(); +} + +LedDeviceMultiLightpack::LedDeviceMultiLightpack() : + LedDevice(), + _lightpacks() +{ +} + +LedDeviceMultiLightpack::~LedDeviceMultiLightpack() +{ + for (LedDeviceLightpack * device : _lightpacks) + { + delete device; + } +} + +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; + } + } + + // 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); + + if (_lightpacks.size() == 0) + { + std::cerr << "No Lightpack devices were found" << std::endl; + } + else + { + std::cout << _lightpacks.size() << " Lightpack devices were found" << std::endl; + } + + return _lightpacks.size() > 0 ? 0 : -1; +} + +int LedDeviceMultiLightpack::write(const std::vector &ledValues) +{ + const ColorRgb * data = ledValues.data(); + int size = ledValues.size(); + + for (LedDeviceLightpack * device : _lightpacks) + { + int count = std::min(device->getLedCount(), size); + + if (count > 0) + { + device->write(data, count); + + data += count; + size -= count; + } + else + { + std::cout << "Unable to write data to Lightpack device: no more led data available" << std::endl; + } + } + + return 0; +} + +int LedDeviceMultiLightpack::switchOff() +{ + for (LedDeviceLightpack * device : _lightpacks) + { + device->switchOff(); + } + + return 0; +} diff --git a/libsrc/hyperion/device/LedDeviceMultiLightpack.h b/libsrc/hyperion/device/LedDeviceMultiLightpack.h new file mode 100644 index 00000000..7126d96a --- /dev/null +++ b/libsrc/hyperion/device/LedDeviceMultiLightpack.h @@ -0,0 +1,57 @@ +#pragma once + +// stl includes +#include +#include +#include + +// libusb include +#include + +// Hyperion includes +#include +#include "LedDeviceLightpack.h" + +/// +/// LedDevice implementation for multiple lightpack devices +/// +class LedDeviceMultiLightpack : public LedDevice +{ +public: + /// + /// Constructs the LedDeviceMultiLightpack + /// + LedDeviceMultiLightpack(); + + /// + /// Destructor of the LedDevice; closes the output device if it is open + /// + virtual ~LedDeviceMultiLightpack(); + + /// + /// Opens and configures the output device7 + /// + /// @return Zero on succes else negative + /// + int open(); + + /// + /// 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& ledValues); + + /// + /// Switch the leds off + /// + /// @return Zero on success else negative + /// + virtual int switchOff(); + +private: + /// buffer for led data + std::vector _lightpacks; +};