Restructured Lightpack device (fix bug concerning the lifecycle of the libusb context)

Former-commit-id: ef7187e9117d75208e4d79b9f64839f88044a3c2
This commit is contained in:
johan 2013-11-20 20:54:04 +01:00
parent d60cca9e20
commit 409b800a8e
6 changed files with 155 additions and 99 deletions

View File

@ -1 +1 @@
5031f4b1d3a2682b6df94ba6671bcc97f9b5a4d1
5078baeb33a6dca64d20161907b9638aeb047ffb

View File

@ -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;
}

View File

@ -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]};
}

View File

@ -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

View File

@ -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<std::string> 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<std::string> LedDeviceMultiLightpack::getLightpackSerials()
{
std::list<std::string> 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<unsigned char *>(buffer), sizeof(buffer));
if (error <= 0)
{
libusb_close(handle);
throw error;
}
libusb_close(handle);
return std::string(buffer, error);
}

View File

@ -4,6 +4,7 @@
#include <vector>
#include <cstdint>
#include <string>
#include <list>
// libusb include
#include <libusb.h>
@ -51,6 +52,10 @@ public:
///
virtual int switchOff();
private:
static std::list<std::string> getLightpackSerials();
static std::string getString(libusb_device * device, int stringDescriptorIndex);
private:
/// buffer for led data
std::vector<LedDeviceLightpack *> _lightpacks;