mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	| @@ -15,8 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||||
| ### Fixed | ||||
|  - Also allow an 8-LED configuration when using Karatelight | ||||
|  | ||||
| - Fix Lightpack issue (#1015) | ||||
|  | ||||
| ### Removed | ||||
|  | ||||
| - Replace Multi-Lightpack by multi-instance Lightpack configuration | ||||
|  | ||||
| ## [2.0.0-alpha.8](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.0-alpha.8) - 2020-09-14 | ||||
| ### Added | ||||
| - Add XCB grabber, a faster and safer alternative for X11 grabbing (#912) | ||||
|   | ||||
| @@ -572,7 +572,7 @@ $(document).ready(function() { | ||||
| 	var devRPiPWM = ['ws281x']; | ||||
| 	var devRPiGPIO = ['piblaster']; | ||||
| 	var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight']; | ||||
| 	var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate']; | ||||
| 	var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate']; | ||||
|  | ||||
| 	var optArr = [[]]; | ||||
| 	optArr[1]=[]; | ||||
|   | ||||
| @@ -11,7 +11,6 @@ | ||||
| 		<file alias="schema-lightpack">schemas/schema-lightpack.json</file> | ||||
| 		<file alias="schema-lpd6803">schemas/schema-lpd6803.json</file> | ||||
| 		<file alias="schema-lpd8806">schemas/schema-lpd8806.json</file> | ||||
| 		<file alias="schema-multilightpack">schemas/schema-multilightpack.json</file> | ||||
| 		<file alias="schema-p9813">schemas/schema-p9813.json</file> | ||||
| 		<file alias="schema-paintpack">schemas/schema-paintpack.json</file> | ||||
| 		<file alias="schema-philipshue">schemas/schema-philipshue.json</file> | ||||
|   | ||||
| @@ -35,6 +35,7 @@ enum DATA_VERSION_INDEXES{ | ||||
| LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig) | ||||
| 	: LedDevice(deviceConfig) | ||||
| 	  , _libusbContext(nullptr) | ||||
| 	  , _device(nullptr) | ||||
| 	  , _deviceHandle(nullptr) | ||||
| 	  , _busNumber(-1) | ||||
| 	  , _addressNumber(-1) | ||||
| @@ -80,17 +81,28 @@ bool LedDeviceLightpack::init(const QJsonObject &deviceConfig) | ||||
| 		else | ||||
| 		{ | ||||
| 			Debug(_log, "USB context initialized"); | ||||
| 			//libusb_set_debug(_libusbContext, 3); | ||||
|  | ||||
| 			if ( _log->getMinLevel() == Logger::LogLevel::DEBUG ) | ||||
| 			{ | ||||
| 				int logLevel = LIBUSB_LOG_LEVEL_INFO; | ||||
| 				#if LIBUSB_API_VERSION >= 0x01000106 | ||||
| 					libusb_set_option(_libusbContext, LIBUSB_OPTION_LOG_LEVEL, logLevel); | ||||
| 				#else | ||||
| 					libusb_set_debug(_libusbContext, logLevel); | ||||
| 				#endif | ||||
| 			} | ||||
|  | ||||
| 			// retrieve the list of USB devices | ||||
| 			libusb_device ** deviceList; | ||||
| 			ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList); | ||||
|  | ||||
| 			bool deviceFound = true; | ||||
| 			// iterate the list of devices | ||||
| 			for (ssize_t i = 0 ; i < deviceCount; ++i) | ||||
| 			{ | ||||
| 				// try to open and initialize the device | ||||
| 				if (testAndOpen(deviceList[i], _serialNumber) == 0) | ||||
| 				deviceFound = searchDevice(deviceList[i], _serialNumber); | ||||
| 				if ( deviceFound ) | ||||
| 				{ | ||||
| 					_device = deviceList[i]; | ||||
| 					// a device was successfully opened. break from list | ||||
| @@ -101,7 +113,7 @@ bool LedDeviceLightpack::init(const QJsonObject &deviceConfig) | ||||
| 			// free the device list | ||||
| 			libusb_free_device_list(deviceList, 1); | ||||
|  | ||||
| 			if (_deviceHandle == nullptr) | ||||
| 			if (!deviceFound) | ||||
| 			{ | ||||
| 				QString errortext; | ||||
| 				if (_serialNumber.isEmpty()) | ||||
| @@ -110,12 +122,16 @@ bool LedDeviceLightpack::init(const QJsonObject &deviceConfig) | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					errortext = QString ("No Lightpack device has been found with serial %1").arg( _serialNumber); | ||||
| 					errortext = QString ("No Lightpack device found with serial %1").arg( _serialNumber); | ||||
| 				} | ||||
| 				this->setInError( errortext ); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				// set the led buffer size (command + 6 bytes per led) | ||||
| 				_ledBuffer = std::vector<uint8_t>(1 + _hwLedCount * 6, 0); | ||||
| 				_ledBuffer[0] = CMD_UPDATE_LEDS; | ||||
|  | ||||
| 				isInitOK = true; | ||||
| 			} | ||||
| 		} | ||||
| @@ -128,18 +144,29 @@ int LedDeviceLightpack::open() | ||||
| 	int retval = -1; | ||||
| 	_isDeviceReady = false; | ||||
|  | ||||
| 	if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS ) | ||||
| 	if ( _device != nullptr) | ||||
| 	{ | ||||
| 		QString errortext = QString ("Failed to open [%1]").arg(_serialNumber); | ||||
| 		this->setInError(errortext); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// Everything is OK -> enable device | ||||
| 		_isDeviceReady = true; | ||||
| 		retval = 0; | ||||
| 	} | ||||
| 		openDevice(_device, &_deviceHandle); | ||||
|  | ||||
| 		if ( _deviceHandle == nullptr ) | ||||
| 		{ | ||||
| 			QString errortext = QString ("Failed to open device with serial [%1]").arg(_serialNumber); | ||||
| 			this->setInError(errortext); | ||||
| 			retval = -1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			disableSmoothing(); | ||||
| 			{ | ||||
| 				// Everything is OK | ||||
| 				_isDeviceReady = true; | ||||
| 				_isOpen = true; | ||||
|  | ||||
| 				Info(_log, "Lightpack device successfully opened"); | ||||
| 				retval = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| @@ -147,75 +174,64 @@ int LedDeviceLightpack::close() | ||||
| { | ||||
| 	int retval = 0; | ||||
| 	_isDeviceReady = false; | ||||
| 	_isOpen = false; | ||||
|  | ||||
| 	// LedDevice specific closing activities | ||||
| 	if (_deviceHandle != nullptr) | ||||
| 	if ( _deviceHandle != nullptr) | ||||
| 	{ | ||||
| 		_isOpen = false; | ||||
| 		libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE); | ||||
| 		libusb_attach_kernel_driver(_deviceHandle, LIGHTPACK_INTERFACE); | ||||
| 		libusb_close(_deviceHandle); | ||||
|  | ||||
| 		closeDevice(_deviceHandle); | ||||
| 		_deviceHandle = nullptr; | ||||
| 	} | ||||
|  | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber) | ||||
| bool LedDeviceLightpack::searchDevice(libusb_device * device, const QString & requestedSerialNumber) | ||||
| { | ||||
| 	bool lightPackFound = false; | ||||
|  | ||||
| 	libusb_device_descriptor deviceDescriptor; | ||||
| 	int error = libusb_get_device_descriptor(device, &deviceDescriptor); | ||||
| 	if (error != LIBUSB_SUCCESS) | ||||
| 	{ | ||||
| 		Error(_log, "Error while retrieving device descriptor(%d): %s", error, libusb_error_name(error)); | ||||
| 		return -1; | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	#define UNO_VENDOR_ID      0x2341 | ||||
| 	#define UNO_PRODUCT_ID     0x43 | ||||
|  | ||||
| 	if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) || | ||||
| 		(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID)) | ||||
| 		 (deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID)) | ||||
| 	{ | ||||
| 		Info(_log, "Found a Lightpack device. Retrieving more information..."); | ||||
|  | ||||
| 		Debug(_log, "vendorIdentifier : %s", QSTRING_CSTR(QString("0x%1").arg(static_cast<ushort>(deviceDescriptor.idVendor),0,16))); | ||||
| 		Debug(_log, "productIdentifier: %s", QSTRING_CSTR(QString("0x%1").arg(static_cast<ushort>(deviceDescriptor.idProduct),0,16))); | ||||
| 		Debug(_log, "release_number   : %s", QSTRING_CSTR(QString("0x%1").arg(static_cast<ushort>(deviceDescriptor.bcdDevice),0,16))); | ||||
| 		Debug(_log, "manufacturer     : %s", QSTRING_CSTR(getProperty(device, deviceDescriptor.iManufacturer))); | ||||
|  | ||||
| 		// get the hardware address | ||||
| 		int busNumber = libusb_get_bus_number(device); | ||||
| 		int addressNumber = libusb_get_device_address(device); | ||||
|  | ||||
| 		// get the serial number | ||||
| 		QString serialNumber; | ||||
| 		if (deviceDescriptor.iSerialNumber != 0) | ||||
| 		{ | ||||
| 			// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment | ||||
| 			try | ||||
| 			{ | ||||
| 				serialNumber = LedDeviceLightpack::getString(device, deviceDescriptor.iSerialNumber); | ||||
| 			} | ||||
| 			catch (int e) | ||||
| 			{ | ||||
| 				Error(_log, "unable to retrieve serial number from Lightpack device(%d): %s", e, libusb_error_name(e)); | ||||
| 				serialNumber = ""; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		QString serialNumber = LedDeviceLightpack::getProperty(device, deviceDescriptor.iSerialNumber); | ||||
| 		Debug(_log,"Lightpack device found: bus=%d address=%d serial=%s", busNumber, addressNumber, QSTRING_CSTR(serialNumber)); | ||||
|  | ||||
| 		// check if this is the device we are looking for | ||||
| 		if (requestedSerialNumber.isEmpty() || requestedSerialNumber == serialNumber) | ||||
| 		{ | ||||
| 			// This is it! | ||||
| 			// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment | ||||
| 			try | ||||
| 			libusb_device_handle * deviceHandle; | ||||
| 			if ( openDevice(device, &deviceHandle ) == 0 ) | ||||
| 			{ | ||||
| 				_deviceHandle = openDevice(device); | ||||
| 				_serialNumber = serialNumber; | ||||
| 				_busNumber = busNumber; | ||||
| 				_addressNumber = addressNumber; | ||||
|  | ||||
| 				Info(_log, "Lightpack device successfully opened"); | ||||
|  | ||||
| 				// get the firmware version | ||||
| 				uint8_t buffer[256]; | ||||
| 				error = libusb_control_transfer( | ||||
| 							_deviceHandle, | ||||
| 							deviceHandle, | ||||
| 							static_cast<uint8_t>( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE), | ||||
| 							0x01, | ||||
| 							0x0100, | ||||
| @@ -231,13 +247,12 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ | ||||
| 					_firmwareVersion.minorVersion = buffer[INDEX_FW_VER_MINOR]; | ||||
| 				} | ||||
|  | ||||
| 				#if 0 | ||||
| 				// FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6 | ||||
| 				_firmwareVersion.majorVersion = 6; | ||||
| 				#endif | ||||
|  | ||||
| 				// disable smoothing of the chosen device | ||||
| 				disableSmoothing(); | ||||
|  | ||||
| 				// determine the number of leds | ||||
| 				// determine the number of LEDs | ||||
| 				if (_firmwareVersion.majorVersion == 4) | ||||
| 				{ | ||||
| 					_hwLedCount = 8; | ||||
| @@ -257,24 +272,20 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ | ||||
| 				{ | ||||
| 					_bitsPerChannel = 8; | ||||
| 				} | ||||
| 				closeDevice(deviceHandle); | ||||
|  | ||||
| 				// set the led buffer size (command + 6 bytes per led) | ||||
| 				_ledBuffer = std::vector<uint8_t>(1 + _hwLedCount * 6, 0); | ||||
| 				_ledBuffer[0] = CMD_UPDATE_LEDS; | ||||
| 				Debug(_log, "Lightpack device found: bus=%d address=%d serial=%s version=%d.%d.", _busNumber, _addressNumber, QSTRING_CSTR(_serialNumber), _firmwareVersion.majorVersion, _firmwareVersion.minorVersion ); | ||||
| 				lightPackFound = true; | ||||
|  | ||||
| 				// return success | ||||
| 				Debug(_log, "Lightpack device opened: bus=%d address=%d serial=%s version=%d.%d.", _busNumber, _addressNumber, QSTRING_CSTR(_serialNumber), _firmwareVersion.majorVersion, _firmwareVersion.minorVersion ); | ||||
| 				return 0; | ||||
| 			} | ||||
| 			catch(int e) | ||||
| 			else | ||||
| 			{ | ||||
| 				_deviceHandle = nullptr; | ||||
| 				Warning(_log, "Unable to open Lightpack device. Searching for other device(%d): %s", e, libusb_error_name(e)); | ||||
| 				Warning(_log, "Unable to open Lightpack device. Searching for other device"); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return -1; | ||||
| 	return lightPackFound; | ||||
| } | ||||
|  | ||||
| int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues) | ||||
| @@ -322,24 +333,23 @@ const QString &LedDeviceLightpack::getSerialNumber() const | ||||
|  | ||||
| int LedDeviceLightpack::writeBytes(uint8_t *data, int size) | ||||
| { | ||||
| //	std::cout << "Writing " << size << " bytes: "; | ||||
| //	for (int i = 0; i < size ; ++i) printf("%02x ", data[i]); | ||||
| //	std::cout << std::endl; | ||||
| 	int rc = 0; | ||||
| 	//Debug( _log, "[%s]", QSTRING_CSTR(uint8_t_to_hex_string(data, size, 32)) ); | ||||
|  | ||||
| 	int error = libusb_control_transfer(_deviceHandle, | ||||
| 									 static_cast<uint8_t>( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ), | ||||
| 		0x09, | ||||
| 		(2 << 8), | ||||
| 		0x00, | ||||
| 		data, size, 1000); | ||||
| 								 static_cast<uint8_t>( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ), | ||||
| 	0x09, | ||||
| 	(2 << 8), | ||||
| 	0x00, | ||||
| 	data, size, 1000); | ||||
|  | ||||
| 	if (error == size) | ||||
| 	if (error != size) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 		rc = -1; | ||||
| 		Error(_log, "Unable to write %d bytes to Lightpack device(%d): %s", size, error, libusb_error_name(error)); | ||||
| 	} | ||||
|  | ||||
| 	Error(_log, "Unable to write %d bytes to Lightpack device(%d): %s", size, error, libusb_error_name(error)); | ||||
| 	return error; | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| int LedDeviceLightpack::disableSmoothing() | ||||
| @@ -354,15 +364,16 @@ int LedDeviceLightpack::disableSmoothing() | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device) | ||||
| int LedDeviceLightpack::openDevice(libusb_device *device, libusb_device_handle ** deviceHandle) | ||||
| { | ||||
| 	int rc = 0; | ||||
|  | ||||
| 	libusb_device_handle * handle = nullptr; | ||||
| 	Logger * log = Logger::getInstance("LedDevice"); | ||||
| 	int error = libusb_open(device, &handle); | ||||
| 	if (error != LIBUSB_SUCCESS) | ||||
| 	{ | ||||
| 		Error(log, "unable to open device(%d): %s", error, libusb_error_name(error)); | ||||
| 		throw error; | ||||
| 		Error(_log, "unable to open device(%d): %s", error, libusb_error_name(error)); | ||||
| 		rc = -1; | ||||
| 	} | ||||
|  | ||||
| 	// detach kernel driver if it is active | ||||
| @@ -371,42 +382,65 @@ libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device) | ||||
| 		error = libusb_detach_kernel_driver(handle, LIGHTPACK_INTERFACE); | ||||
| 		if (error != LIBUSB_SUCCESS) | ||||
| 		{ | ||||
| 			Error(log, "unable to detach kernel driver(%d): %s", error, libusb_error_name(error)); | ||||
| 			Error(_log, "unable to detach kernel driver(%d): %s", error, libusb_error_name(error)); | ||||
| 			libusb_close(handle); | ||||
| 			throw error; | ||||
| 			rc = -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	error = libusb_claim_interface(handle, LIGHTPACK_INTERFACE); | ||||
| 	if (error != LIBUSB_SUCCESS) | ||||
| 	{ | ||||
| 		Error(log, "unable to claim interface(%d): %s", error, libusb_error_name(error)); | ||||
| 		Error(_log, "unable to claim interface(%d): %s", error, libusb_error_name(error)); | ||||
| 		libusb_attach_kernel_driver(handle, LIGHTPACK_INTERFACE); | ||||
| 		libusb_close(handle); | ||||
| 		throw error; | ||||
| 		rc = -1; | ||||
| 	} | ||||
|  | ||||
| 	return handle; | ||||
| 	*deviceHandle = handle; | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| QString LedDeviceLightpack::getString(libusb_device * device, int stringDescriptorIndex) | ||||
| int LedDeviceLightpack::closeDevice(libusb_device_handle * deviceHandle) | ||||
| { | ||||
| 	libusb_device_handle * handle = nullptr; | ||||
| 	int rc = 0; | ||||
|  | ||||
| 	int error = libusb_open(device, &handle); | ||||
| 	int error = libusb_release_interface(deviceHandle, LIGHTPACK_INTERFACE); | ||||
| 	if (error != LIBUSB_SUCCESS) | ||||
| 	{ | ||||
| 		throw error; | ||||
| 		Debug(_log, "Error while releasing interface (%d): %s", error, libusb_error_name(error)); | ||||
| 		rc = -1; | ||||
| 	} | ||||
|  | ||||
| 	char buffer[256]; | ||||
| 	error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer)); | ||||
| 	if (error <= 0) | ||||
| 	error = libusb_attach_kernel_driver(deviceHandle, LIGHTPACK_INTERFACE); | ||||
| 	if (error != LIBUSB_SUCCESS) | ||||
| 	{ | ||||
| 		libusb_close(handle); | ||||
| 		throw error; | ||||
| 		Debug(_log, "Error while attaching kernel driver (%d): %s", error, libusb_error_name(error)); | ||||
| 		rc = -1; | ||||
| 	} | ||||
|  | ||||
| 	libusb_close(handle); | ||||
| 	return QString(QByteArray(buffer, error)); | ||||
| 	libusb_close(deviceHandle); | ||||
|  | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| QString LedDeviceLightpack::getProperty(libusb_device * device, int stringDescriptorIndex) | ||||
| { | ||||
| 	QString value; | ||||
|  | ||||
| 	if ( stringDescriptorIndex != 0 ) | ||||
| 	{ | ||||
| 		libusb_device_handle * handle = nullptr; | ||||
| 		if ( libusb_open(device, &handle) == LIBUSB_SUCCESS ) | ||||
| 		{ | ||||
| 			char buffer[256]; | ||||
| 			int error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer)); | ||||
| 			if (error > 0) | ||||
| 			{ | ||||
| 				value = QString(QByteArray(buffer, error)); | ||||
| 			} | ||||
| 			libusb_close(handle); | ||||
| 		} | ||||
| 	} | ||||
| 	return value; | ||||
| } | ||||
|   | ||||
| @@ -105,11 +105,12 @@ protected: | ||||
| private: | ||||
|  | ||||
| 	/// | ||||
| 	/// Test if the device is a (or the) lightpack we are looking for | ||||
| 	/// Search for a LightPack Device (first one found or matching a given serial number) | ||||
| 	/// | ||||
| 	/// @return Zero on succes else negative | ||||
| 	/// @param[in] requestedSerialNumber serial number of Lightpack to be search | ||||
| 	/// @return True on Lightpack found | ||||
| 	/// | ||||
| 	int testAndOpen(libusb_device * device, const QString & requestedSerialNumber); | ||||
| 	bool searchDevice(libusb_device * device, const QString & requestedSerialNumber); | ||||
|  | ||||
| 	/// write bytes to the device | ||||
| 	int writeBytes(uint8_t *data, int size); | ||||
| @@ -123,8 +124,11 @@ private: | ||||
| 		int minorVersion; | ||||
| 	}; | ||||
|  | ||||
| 	static libusb_device_handle * openDevice(libusb_device * device); | ||||
| 	static QString getString(libusb_device * device, int stringDescriptorIndex); | ||||
|  | ||||
| 	int openDevice(libusb_device *device, libusb_device_handle ** deviceHandle); | ||||
| 	int closeDevice(libusb_device_handle * deviceHandle); | ||||
|  | ||||
| 	QString getProperty(libusb_device * device, int stringDescriptorIndex); | ||||
|  | ||||
| 	/// libusb context | ||||
| 	libusb_context * _libusbContext; | ||||
|   | ||||
| @@ -1,256 +0,0 @@ | ||||
| // stl includes | ||||
| #include <exception> | ||||
| #include <cstring> | ||||
| #include <algorithm> | ||||
|  | ||||
| // 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(); | ||||
| } | ||||
|  | ||||
| LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig) | ||||
| 	: LedDevice(deviceConfig) | ||||
| 	, _lightpacks() | ||||
| { | ||||
| } | ||||
|  | ||||
| LedDeviceMultiLightpack::~LedDeviceMultiLightpack() | ||||
| { | ||||
| 	for (LedDeviceLightpack * device : _lightpacks) | ||||
| 	{ | ||||
| 		delete device; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig) | ||||
| { | ||||
| 	return new LedDeviceMultiLightpack(deviceConfig); | ||||
| } | ||||
|  | ||||
| bool LedDeviceMultiLightpack::init(const QJsonObject &deviceConfig) | ||||
| { | ||||
| 	bool isInitOK = false; | ||||
|  | ||||
| 	// Initialise sub-class | ||||
| 	if ( LedDevice::init(deviceConfig) ) | ||||
| 	{ | ||||
| 		// retrieve a list with Lightpack serials | ||||
| 		QStringList serialList = getLightpackSerials(); | ||||
|  | ||||
| 		// sort the list of Lightpacks based on the serial to get a fixed order | ||||
| 		std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks); | ||||
|  | ||||
| 		// open each Lightpack device | ||||
| 		for (auto serial : serialList) | ||||
| 		{ | ||||
| 			QJsonObject devConfig; | ||||
| 			devConfig["serial"] = serial; | ||||
| 			devConfig["latchTime"] = deviceConfig["latchTime"]; | ||||
| 			devConfig["rewriteTime"] = deviceConfig["rewriteTime"]; | ||||
|  | ||||
| 			LedDeviceLightpack * device = new LedDeviceLightpack(devConfig); | ||||
|  | ||||
| 			device->start(); | ||||
| 			if (device->open() == 0) | ||||
| 			{ | ||||
| 				_lightpacks.push_back(device); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial)); | ||||
| 				delete device; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (_lightpacks.empty()) | ||||
| 		{ | ||||
| 			//Warning(_log, "No Lightpack devices were found"); | ||||
| 			QString errortext = QString ("No Lightpack devices were found"); | ||||
| 			this->setInError(errortext); | ||||
| 			isInitOK = false; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			Info(_log, "%d Lightpack devices were found", _lightpacks.size()); | ||||
| 			isInitOK = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return isInitOK; | ||||
| } | ||||
|  | ||||
| int LedDeviceMultiLightpack::open() | ||||
| { | ||||
| 	int retval = -1; | ||||
| 	_isDeviceReady = false; | ||||
|  | ||||
| 	int lightsInError = 0; | ||||
| 	// open each Lightpack device | ||||
| 	for (LedDeviceLightpack * device : _lightpacks) | ||||
| 	{ | ||||
| 		if (device->open() < 0) | ||||
| 		{ | ||||
| 			Error( _log, "Failed to open [%s]", QSTRING_CSTR(device->getSerialNumber()) ); | ||||
| 			++lightsInError; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ( lightsInError < static_cast<int>(_lightpacks.size()) ) | ||||
| 	{ | ||||
| 		// Everything is OK -> enable device | ||||
| 		_isDeviceReady = true; | ||||
| 		retval = 0; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		this->setInError( "All Lightpacks failed to be opened!" ); | ||||
| 	} | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| int LedDeviceMultiLightpack::close() | ||||
| { | ||||
| 	_isDeviceReady = false; | ||||
|  | ||||
| 	for (LedDeviceLightpack * device : _lightpacks) | ||||
| 	{ | ||||
| 			device->close(); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues) | ||||
| { | ||||
| 	const ColorRgb * data = ledValues.data(); | ||||
| 	int size = ledValues.size(); | ||||
|  | ||||
| 	for (LedDeviceLightpack * device : _lightpacks) | ||||
| 	{ | ||||
| 		int count = qMin(static_cast<int>( device->getLedCount()), size); | ||||
|  | ||||
| 		if (count > 0) | ||||
| 		{ | ||||
| 			if ( device->isOpen() ) | ||||
| 			{ | ||||
| 				device->write(data, count); | ||||
| 			} | ||||
|  | ||||
| 			data += count; | ||||
| 			size -= count; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			Warning(_log, "Unable to write data to Lightpack device: no more led data available"); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| bool LedDeviceMultiLightpack::powerOff() | ||||
| { | ||||
| 	for (LedDeviceLightpack * device : _lightpacks) | ||||
| 	{ | ||||
| 		if ( device->isOpen() ) | ||||
| 		{ | ||||
| 			device->powerOff(); | ||||
| 		} | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| QStringList LedDeviceMultiLightpack::getLightpackSerials() | ||||
| { | ||||
| 	QStringList serialList; | ||||
| 	Logger * log = Logger::getInstance("LedDevice"); | ||||
| 	Debug(log, "Getting list of Lightpack serials"); | ||||
|  | ||||
| 	// initialize the USB context | ||||
| 	libusb_context * libusbContext; | ||||
| 	int error = libusb_init(&libusbContext); | ||||
| 	if (error != LIBUSB_SUCCESS) | ||||
| 	{ | ||||
| 		Error(log,"Error while initializing USB context(%d): %s", error, libusb_error_name(error)); | ||||
| 		libusbContext = nullptr; | ||||
| 		return serialList; | ||||
| 	} | ||||
| 	//libusb_set_debug(_libusbContext, 3); | ||||
| 	Info(log, "USB context initialized in multi Lightpack device"); | ||||
|  | ||||
| 	// 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) | ||||
| 		{ | ||||
| 			Error(log, "Error while retrieving device descriptor(%d): %s", error, libusb_error_name(error)); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) || | ||||
| 			(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID)) | ||||
| 		{ | ||||
| 			Info(log, "Found a Lightpack device. Retrieving serial..."); | ||||
|  | ||||
| 			// get the serial number | ||||
| 			QString serialNumber; | ||||
| 			if (deviceDescriptor.iSerialNumber != 0) | ||||
| 			{ | ||||
| 				// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment | ||||
| 				try | ||||
| 				{ | ||||
| 					serialNumber = LedDeviceMultiLightpack::getString(deviceList[i], deviceDescriptor.iSerialNumber); | ||||
| 				} | ||||
| 				catch (int e) | ||||
| 				{ | ||||
| 					Error(log,"Unable to retrieve serial number(%d): %s", e, libusb_error_name(e)); | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			Info(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber)); | ||||
| 			serialList.append(serialNumber); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// free the device list | ||||
| 	libusb_free_device_list(deviceList, 1); | ||||
| 	libusb_exit(libusbContext); | ||||
|  | ||||
| 	return serialList; | ||||
| } | ||||
|  | ||||
| QString 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 QString(QByteArray(buffer, error)); | ||||
| } | ||||
| @@ -1,92 +0,0 @@ | ||||
| #ifndef LEDEVICEMULTILIGHTPACK_H | ||||
| #define LEDEVICEMULTILIGHTPACK_H | ||||
|  | ||||
| // stl includes | ||||
| #include <vector> | ||||
| #include <cstdint> | ||||
| #include <QStringList> | ||||
| #include <QString> | ||||
|  | ||||
| // libusb include | ||||
| #include <libusb.h> | ||||
|  | ||||
| // Hyperion includes | ||||
| #include <leddevice/LedDevice.h> | ||||
| #include "LedDeviceLightpack.h" | ||||
|  | ||||
| /// | ||||
| /// LedDevice implementation for multiple lightpack devices | ||||
| /// | ||||
| class LedDeviceMultiLightpack : public LedDevice | ||||
| { | ||||
| public: | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Constructs a LedDevice of multiple Lightpack LED-devices | ||||
| 	/// | ||||
| 	/// @param deviceConfig Device's configuration as JSON-Object | ||||
| 	/// | ||||
| 	explicit LedDeviceMultiLightpack(const QJsonObject &deviceConfig); | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Destructor of the LedDevice | ||||
| 	/// | ||||
| 	~LedDeviceMultiLightpack() override; | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Constructs the LED-device | ||||
| 	/// | ||||
| 	/// @param[in] deviceConfig Device's configuration as JSON-Object | ||||
| 	/// @return LedDevice constructed | ||||
| 	/// | ||||
| 	static LedDevice* construct(const QJsonObject &deviceConfig); | ||||
|  | ||||
| protected: | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Initialise the device's configuration | ||||
| 	/// | ||||
| 	/// @param[in] deviceConfig the JSON device configuration | ||||
| 	/// @return True, if success | ||||
| 	/// | ||||
| 	bool init(const QJsonObject &deviceConfig) override; | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Opens the output device. | ||||
| 	/// | ||||
| 	/// @return Zero on success (i.e. device is ready), else negative | ||||
| 	/// | ||||
| 	int open() override; | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Closes the output device. | ||||
| 	/// | ||||
| 	/// @return Zero on success (i.e. device is closed), else negative | ||||
| 	/// | ||||
| 	int close() override; | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Power-/turn off the Nanoleaf device. | ||||
| 	/// | ||||
| 	/// @return True if success | ||||
| 	/// | ||||
| 	bool powerOff() override; | ||||
|  | ||||
| 	/// | ||||
| 	/// @brief Writes the RGB-Color values to the LEDs. | ||||
| 	/// | ||||
| 	/// @param[in] ledValues The RGB-color per LED | ||||
| 	/// @return Zero on success, else negative | ||||
| 	/// | ||||
| 	int write(const std::vector<ColorRgb> & ledValues) override; | ||||
|  | ||||
| private: | ||||
|  | ||||
| 	static QStringList getLightpackSerials(); | ||||
| 	static QString getString(libusb_device * device, int stringDescriptorIndex); | ||||
|  | ||||
| 	/// buffer for led data | ||||
| 	std::vector<LedDeviceLightpack *> _lightpacks; | ||||
| }; | ||||
|  | ||||
| #endif // LEDEVICEMULTILIGHTPACK_H | ||||
| @@ -1,26 +0,0 @@ | ||||
| { | ||||
| 	"type":"object", | ||||
| 	"required":true, | ||||
| 	"properties":{ | ||||
| 		"latchTime": { | ||||
| 			"type": "integer", | ||||
| 			"title":"edt_dev_spec_latchtime_title", | ||||
| 			"default": 11, | ||||
| 			"append" : "edt_append_ms", | ||||
| 			"minimum": 0, | ||||
| 			"maximum": 1000, | ||||
| 			"access" : "expert", | ||||
| 			"propertyOrder" : 1 | ||||
| 		}, | ||||
| 		"rewriteTime": { | ||||
| 			"type": "integer", | ||||
| 			"title":"edt_dev_general_rewriteTime_title", | ||||
| 			"default": 1000, | ||||
| 			"append" : "edt_append_ms", | ||||
| 			"minimum": 0, | ||||
| 			"access" : "expert", | ||||
| 			"propertyOrder" : 2 | ||||
| 		}		 | ||||
| 	}, | ||||
| 	"additionalProperties": true | ||||
| } | ||||
		Reference in New Issue
	
	Block a user