diff --git a/config/ola.m4 b/config/ola.m4 index af7b0bc3a..f767788c8 100644 --- a/config/ola.m4 +++ b/config/ola.m4 @@ -49,7 +49,14 @@ if test -z "$PROTOC" ; then AC_MSG_ERROR([cannot find 'protoc' program]); elif test -n "$1" ; then AC_MSG_CHECKING([protoc version]) - [protoc_version=`$PROTOC --version 2>&1 | grep 'libprotoc' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`] + # Since v20.x we only get effectively the minor and patch versions out of protoc. + # Treat them as major and minor and everything should keep working indefinitely. + # See https://protobuf.dev/support/version-support/ + # So we've got either of these: + # libprotoc 2.4.1 + # libprotoc 23.3 + # The first sed ensures all versions have major, minor, patch, by adding a .0 on the end of ones missing it + [protoc_version=`$PROTOC --version 2>&1 | grep 'libprotoc' | sed 's/\([^\.0-9][0-9][0-9]*\.[0-9][0-9]*\)$/\1\.0/g' | sed 's/[^0-9]*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`] [required=$1] [required_major=`echo $required | sed 's/[^0-9].*//'`] [required_minor=`echo $required | sed 's/[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*/\1/'`] diff --git a/plugins/usbdmx/AVLdiyD512Factory.cpp b/plugins/usbdmx/AVLdiyD512Factory.cpp index 0f965ab7f..2e0481636 100644 --- a/plugins/usbdmx/AVLdiyD512Factory.cpp +++ b/plugins/usbdmx/AVLdiyD512Factory.cpp @@ -63,6 +63,9 @@ bool AVLdiyD512Factory::DeviceAdded( // Some AVLdiy devices don't have serial numbers. Since there isn't another // good way to uniquely identify a USB device, we only support one of these // types of devices per host. + // TODO(Peter): We could instead use the device & bus number (like the + // Eurolite plugin). You could use more than one device, but the patch + // wouldn't follow if you plugged it into a different port if (info.serial.empty()) { if (m_missing_serial_number) { OLA_WARN << "Failed to read serial number or serial number empty. " diff --git a/plugins/usbdmx/AnymauDMXFactory.cpp b/plugins/usbdmx/AnymauDMXFactory.cpp index 1995fd87b..86df54f2d 100644 --- a/plugins/usbdmx/AnymauDMXFactory.cpp +++ b/plugins/usbdmx/AnymauDMXFactory.cpp @@ -63,6 +63,9 @@ bool AnymauDMXFactory::DeviceAdded( // Some Anyma devices don't have serial numbers. Since there isn't another // good way to uniquely identify a USB device, we only support one of these // types of devices per host. + // TODO(Peter): We could instead use the device & bus number (like the + // Eurolite plugin). You could use more than one device, but the patch + // wouldn't follow if you plugged it into a different port if (info.serial.empty()) { if (m_missing_serial_number) { OLA_WARN << "Failed to read serial number or serial number empty. " diff --git a/plugins/usbdmx/DMXCreator512BasicFactory.cpp b/plugins/usbdmx/DMXCreator512BasicFactory.cpp index 0728e7a18..caa6a0de5 100644 --- a/plugins/usbdmx/DMXCreator512BasicFactory.cpp +++ b/plugins/usbdmx/DMXCreator512BasicFactory.cpp @@ -55,6 +55,9 @@ bool DMXCreator512BasicFactory::DeviceAdded( // vendor and product ids. Also, since DMXCreator 512 Basic devices don't have // serial numbers and there is no other good way to uniquely identify a USB // device, we only support one of these types of devices per host. + // TODO(Peter): We could instead use the device & bus number (like the + // Eurolite plugin). You could use more than one device, but the patch + // wouldn't follow if you plugged it into a different port if (info.serial.empty()) { if (m_missing_serial_number) { OLA_WARN << "We can only support one device without a serial number."; diff --git a/plugins/usbdmx/EuroliteProFactory.cpp b/plugins/usbdmx/EuroliteProFactory.cpp index ce4a0b5e1..42efe7bea 100644 --- a/plugins/usbdmx/EuroliteProFactory.cpp +++ b/plugins/usbdmx/EuroliteProFactory.cpp @@ -20,6 +20,8 @@ #include "plugins/usbdmx/EuroliteProFactory.h" +#include + #include "libs/usb/LibUsbAdaptor.h" #include "ola/Logging.h" #include "ola/base/Flags.h" @@ -46,12 +48,34 @@ const uint16_t EuroliteProFactory::VENDOR_ID_MK2 = 0x0403; const char EuroliteProFactory::ENABLE_EUROLITE_MK2_KEY[] = "enable_eurolite_mk2"; +const char EuroliteProFactory::EUROLITE_MK2_SERIAL_KEY[] = + "eurolite_mk2_serial"; EuroliteProFactory::EuroliteProFactory(ola::usb::LibUsbAdaptor *adaptor, Preferences *preferences) : BaseWidgetFactory("EuroliteProFactory"), m_adaptor(adaptor), m_enable_eurolite_mk2(IsEuroliteMk2Enabled(preferences)) { + const std::vector serials = + preferences->GetMultipleValue(EUROLITE_MK2_SERIAL_KEY); + // A single empty string is considered the same as specifying + // no serial numbers. This is useful as a default value. + const bool has_default_value = + serials.size() == 1 && serials[0].empty(); + if (!has_default_value) { + for (std::vector::const_iterator iter = serials.begin(); + iter != serials.end(); ++iter) { + if (iter->empty()) { + OLA_WARN << EUROLITE_MK2_SERIAL_KEY + << " requires a serial number, but it is empty."; + } else if (STLContains(m_expected_eurolite_mk2_serials, *iter)) { + OLA_WARN << EUROLITE_MK2_SERIAL_KEY << " lists serial " + << *iter << " more than once."; + } else { + m_expected_eurolite_mk2_serials.insert(*iter); + } + } + } } bool EuroliteProFactory::IsEuroliteMk2Enabled(Preferences *preferences) { @@ -68,11 +92,11 @@ bool EuroliteProFactory::DeviceAdded( libusb_device *usb_device, const struct libusb_device_descriptor &descriptor) { bool is_mk2 = false; + LibUsbAdaptor::DeviceInformation info; // Eurolite USB-DMX512-PRO? if (descriptor.idVendor == VENDOR_ID && descriptor.idProduct == PRODUCT_ID) { OLA_INFO << "Found a new Eurolite USB-DMX512-PRO device"; - LibUsbAdaptor::DeviceInformation info; if (!m_adaptor->GetDeviceInfo(usb_device, descriptor, &info)) { return false; } @@ -88,13 +112,21 @@ bool EuroliteProFactory::DeviceAdded( // Eurolite USB-DMX512-PRO MK2? } else if (descriptor.idVendor == VENDOR_ID_MK2 && descriptor.idProduct == PRODUCT_ID_MK2) { - if (m_enable_eurolite_mk2) { - OLA_INFO << "Found a possible new Eurolite USB-DMX512-PRO MK2 device"; - LibUsbAdaptor::DeviceInformation info; - if (!m_adaptor->GetDeviceInfo(usb_device, descriptor, &info)) { - return false; - } + if (!m_adaptor->GetDeviceInfo(usb_device, descriptor, &info)) { + return false; + } + + const bool serial_matches = + STLContains(m_expected_eurolite_mk2_serials, info.serial); + if (m_enable_eurolite_mk2 || serial_matches) { + if (serial_matches) { + OLA_INFO << "Found a probable new Eurolite USB-DMX512-PRO MK2 device " + << "with matching serial " << info.serial; + } else { + OLA_INFO << "Found a probable new Eurolite USB-DMX512-PRO MK2 device " + << "with serial " << info.serial; + } if (!m_adaptor->CheckManufacturer(EXPECTED_MANUFACTURER_MK2, info)) { return false; } @@ -104,9 +136,12 @@ bool EuroliteProFactory::DeviceAdded( } is_mk2 = true; } else { - OLA_INFO << "Connected FTDI device could be a Eurolite " - << "USB-DMX512-PRO MK2 but was ignored, because " - << ENABLE_EUROLITE_MK2_KEY << " was false."; + OLA_INFO << "Connected FTDI device with serial " << info.serial + << " could be a Eurolite USB-DMX512-PRO MK2 but was " + << "ignored, because " + << ENABLE_EUROLITE_MK2_KEY << " was false and " + << "its serial number was not listed specifically in " + << EUROLITE_MK2_SERIAL_KEY; return false; } } else { @@ -114,17 +149,21 @@ bool EuroliteProFactory::DeviceAdded( return false; } - // The Eurolite doesn't have a serial number, so instead we use the device & - // bus number. + // The original Eurolite doesn't have a serial number, so instead we use the + // device & bus number. The MK2 does, so we use that where available. // TODO(simon): check if this supports the SERIAL NUMBER label and use that // instead. - // There is no Serialnumber--> work around: bus+device number - int bus_number = libusb_get_bus_number(usb_device); - int device_address = libusb_get_device_address(usb_device); - std::ostringstream serial_str; - serial_str << bus_number << "-" << device_address; + if (is_mk2 && !info.serial.empty()) { + serial_str << info.serial; + } else { + // Original, there is no Serialnumber--> work around: bus+device number + int bus_number = libusb_get_bus_number(usb_device); + int device_address = libusb_get_device_address(usb_device); + + serial_str << bus_number << "-" << device_address; + } EurolitePro *widget = NULL; if (FLAGS_use_async_libusb) { diff --git a/plugins/usbdmx/EuroliteProFactory.h b/plugins/usbdmx/EuroliteProFactory.h index 23ebdc3f8..249735dd7 100644 --- a/plugins/usbdmx/EuroliteProFactory.h +++ b/plugins/usbdmx/EuroliteProFactory.h @@ -21,6 +21,9 @@ #ifndef PLUGINS_USBDMX_EUROLITEPROFACTORY_H_ #define PLUGINS_USBDMX_EUROLITEPROFACTORY_H_ +#include +#include + #include "libs/usb/LibUsbAdaptor.h" #include "ola/base/Macro.h" #include "olad/Preferences.h" @@ -46,10 +49,12 @@ class EuroliteProFactory : public BaseWidgetFactory { static bool IsEuroliteMk2Enabled(Preferences *preferences); static const char ENABLE_EUROLITE_MK2_KEY[]; + static const char EUROLITE_MK2_SERIAL_KEY[]; private: ola::usb::LibUsbAdaptor *m_adaptor; bool m_enable_eurolite_mk2; + std::set m_expected_eurolite_mk2_serials; static const uint16_t PRODUCT_ID; static const uint16_t VENDOR_ID; diff --git a/plugins/usbdmx/README.md b/plugins/usbdmx/README.md index 79d0eb8b8..04696f1c3 100644 --- a/plugins/usbdmx/README.md +++ b/plugins/usbdmx/README.md @@ -9,7 +9,7 @@ This plugin supports various USB DMX devices including: * DMXControl Projects e.V. Nodle U1 * DMXCreator 512 Basic * Eurolite USB-DMX512 PRO -* Eurolite USB-DMX512 PRO MK2 (when `enable_eurolite_mk2 = true`) +* Eurolite USB-DMX512 PRO MK2 (see notes below) * Eurolite freeDMX Wi-Fi * Fadecandy * FX5 DMX @@ -20,25 +20,36 @@ This plugin supports various USB DMX devices including: ## Config file : `ola-usbdmx.conf` -`libusb_debug_level = {0,1,2,3,4}` -The debug level for libusb, see http://libusb.sourceforge.net/api-1.0/ +`libusb_debug_level = {0,1,2,3,4}` +The debug level for libusb, see http://libusb.sourceforge.net/api-1.0/ 0 = No logging, 4 = Verbose debug. `enable_eurolite_mk2 = {false,true}` Whether to enable detection of the Eurolite USB-DMX512 PRO MK2. -Default = false. This device is indistinguishable from other devices +Default = `false`. This device is indistinguishable from other devices with an FTDI chip, and is therefore disabled by default. When enabled, this plugin will conflict with the usbserial, StageProfi and FTDI USB DMX -plugins. +plugins. If this is undesirable, the `eurolite_mk2_serial` setting can be +used instead, which manually marks a specific USB device as a Eurolite +USB-DMX512 PRO MK2. -`nodle--mode = {0,1,2,3,4,5,6,7}` +`eurolite_mk2_serial = ` +Claim the USB device with the given serial number as a Eurolite USB-DMX512 +PRO MK2 even when `enable_eurolite_mk2 = false`. This makes it possible +to use the Eurolite USB-DMX512 PRO MK2 together with other devices that +can not be distinguished otherwise. This setting has no effect when +`enable_eurolite_mk2 = true` or if no device is connected with the given +serial. The setting may be specified multiple times to use multiple Eurolite +USB-DMX512 PRO MK2 devices. + +`nodle--mode = {0,1,2,3,4,5,6,7}` The mode for the Nodle U1 interface with serial number `` to operate -in. Default = 6 -0 - Standby -1 - DMX In -> DMX Out -2 - PC Out -> DMX Out -3 - DMX In + PC Out -> DMX Out -4 - DMX In -> PC In -5 - DMX In -> DMX Out & DMX In -> PC In -6 - PC Out -> DMX Out & DMX In -> PC In +in. Default = 6 +0 - Standby +1 - DMX In -> DMX Out +2 - PC Out -> DMX Out +3 - DMX In + PC Out -> DMX Out +4 - DMX In -> PC In +5 - DMX In -> DMX Out & DMX In -> PC In +6 - PC Out -> DMX Out & DMX In -> PC In 7 - DMX In + PC Out -> DMX Out & DMX In -> PC In diff --git a/plugins/usbdmx/ScanlimeFadecandyFactory.cpp b/plugins/usbdmx/ScanlimeFadecandyFactory.cpp index 4f1420a8b..60f28d5dd 100644 --- a/plugins/usbdmx/ScanlimeFadecandyFactory.cpp +++ b/plugins/usbdmx/ScanlimeFadecandyFactory.cpp @@ -64,6 +64,9 @@ bool ScanlimeFadecandyFactory::DeviceAdded( // Fadecandy devices may be missing serial numbers. Since there isn't another // good way to uniquely identify a USB device, we only support one of these // types of devices per host. + // TODO(Peter): We could instead use the device & bus number (like the + // Eurolite plugin). You could use more than one device, but the patch + // wouldn't follow if you plugged it into a different port if (info.serial.empty()) { if (m_missing_serial_number) { OLA_WARN << "Failed to read serial number or serial number empty. " diff --git a/plugins/usbdmx/UsbDmxPlugin.cpp b/plugins/usbdmx/UsbDmxPlugin.cpp index d1760aea9..4aa3f7f88 100644 --- a/plugins/usbdmx/UsbDmxPlugin.cpp +++ b/plugins/usbdmx/UsbDmxPlugin.cpp @@ -107,6 +107,11 @@ bool UsbDmxPlugin::SetDefaultPreferences() { BoolValidator(), false); + save |= m_preferences->SetDefaultValue( + EuroliteProFactory::EUROLITE_MK2_SERIAL_KEY, + StringValidator(), + ""); + if (save) { m_preferences->Save(); }