-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the Anyma, Eurolite and Fadecandy widgets. #543
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Library General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* AnymauDMX.cpp | ||
* The synchronous and asynchronous Anyma uDMX widgets. | ||
* Copyright (C) 2014 Simon Newton | ||
*/ | ||
|
||
#include "plugins/usbdmx/AnymauDMX.h" | ||
|
||
#include <unistd.h> | ||
#include <string> | ||
|
||
#include "ola/Logging.h" | ||
#include "ola/Constants.h" | ||
#include "plugins/usbdmx/AsyncUsbSender.h" | ||
#include "plugins/usbdmx/LibUsbAdaptor.h" | ||
#include "plugins/usbdmx/ThreadedUsbSender.h" | ||
|
||
namespace ola { | ||
namespace plugin { | ||
namespace usbdmx { | ||
|
||
using std::string; | ||
|
||
namespace { | ||
|
||
static const unsigned int URB_TIMEOUT_MS = 500; | ||
static const unsigned int UDMX_SET_CHANNEL_RANGE = 0x0002; | ||
|
||
} // namespace | ||
|
||
// AnymaThreadedSender | ||
// ----------------------------------------------------------------------------- | ||
|
||
/* | ||
* Sends messages to a Anyma device in a separate thread. | ||
*/ | ||
class AnymaThreadedSender: public ThreadedUsbSender { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also feels inconsistent when the classes don't match the style of the filename (manufacturer only). I'd still be in favour of dropping the device from the filename. |
||
public: | ||
AnymaThreadedSender(LibUsbAdaptor *adaptor, | ||
libusb_device *usb_device, | ||
libusb_device_handle *handle) | ||
: ThreadedUsbSender(usb_device, handle), | ||
m_adaptor(adaptor) { | ||
} | ||
|
||
private: | ||
LibUsbAdaptor* const m_adaptor; | ||
|
||
bool TransmitBuffer(libusb_device_handle *handle, | ||
const DmxBuffer &buffer); | ||
}; | ||
|
||
bool AnymaThreadedSender::TransmitBuffer(libusb_device_handle *handle, | ||
const DmxBuffer &buffer) { | ||
int r = m_adaptor->ControlTransfer( | ||
handle, | ||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | | ||
LIBUSB_ENDPOINT_OUT, // bmRequestType | ||
UDMX_SET_CHANNEL_RANGE, // bRequest | ||
buffer.Size(), // wValue | ||
0, // wIndex | ||
const_cast<unsigned char*>(buffer.GetRaw()), // data | ||
buffer.Size(), // wLength | ||
URB_TIMEOUT_MS); // timeout | ||
// Sometimes we get PIPE errors here, those are non-fatal | ||
return r > 0 || r == LIBUSB_ERROR_PIPE; | ||
} | ||
|
||
|
||
// SynchronousAnymauDMX | ||
// ----------------------------------------------------------------------------- | ||
|
||
SynchronousAnymauDMX::SynchronousAnymauDMX(LibUsbAdaptor *adaptor, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make up your mind. :) |
||
libusb_device *usb_device, | ||
const string &serial) | ||
: AnymauDMX(adaptor, serial), | ||
m_usb_device(usb_device) { | ||
} | ||
|
||
bool SynchronousAnymauDMX::Init() { | ||
libusb_device_handle *usb_handle; | ||
|
||
bool ok = m_adaptor->OpenDeviceAndClaimInterface( | ||
m_usb_device, 0, &usb_handle); | ||
if (!ok) { | ||
return false; | ||
} | ||
|
||
std::auto_ptr<AnymaThreadedSender> sender( | ||
new AnymaThreadedSender(m_adaptor, m_usb_device, usb_handle)); | ||
if (!sender->Start()) { | ||
return false; | ||
} | ||
m_sender.reset(sender.release()); | ||
return true; | ||
} | ||
|
||
bool SynchronousAnymauDMX::SendDMX(const DmxBuffer &buffer) { | ||
return m_sender.get() ? m_sender->SendDMX(buffer) : false; | ||
} | ||
|
||
// AnymaAsyncUsbSender | ||
// ----------------------------------------------------------------------------- | ||
class AnymaAsyncUsbSender : public AsyncUsbSender { | ||
public: | ||
AnymaAsyncUsbSender(LibUsbAdaptor *adaptor, libusb_device *usb_device) | ||
: AsyncUsbSender(adaptor, usb_device) { | ||
m_control_setup_buffer = | ||
new uint8_t[LIBUSB_CONTROL_SETUP_SIZE + DMX_UNIVERSE_SIZE]; | ||
} | ||
|
||
~AnymaAsyncUsbSender() { | ||
CancelTransfer(); | ||
delete[] m_control_setup_buffer; | ||
} | ||
|
||
libusb_device_handle* SetupHandle() { | ||
libusb_device_handle *usb_handle; | ||
bool ok = m_adaptor->OpenDeviceAndClaimInterface( | ||
m_usb_device, 0, &usb_handle); | ||
return ok ? usb_handle : NULL; | ||
} | ||
|
||
bool PerformTransfer(const DmxBuffer &buffer) { | ||
m_adaptor->FillControlSetup( | ||
m_control_setup_buffer, | ||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | | ||
LIBUSB_ENDPOINT_OUT, // bmRequestType | ||
UDMX_SET_CHANNEL_RANGE, // bRequest | ||
buffer.Size(), // wValue | ||
0, // wIndex | ||
buffer.Size()); // wLength | ||
|
||
unsigned int length = DMX_UNIVERSE_SIZE; | ||
buffer.Get(m_control_setup_buffer + LIBUSB_CONTROL_SETUP_SIZE, &length); | ||
|
||
FillControlTransfer(m_control_setup_buffer, URB_TIMEOUT_MS); | ||
return SubmitTransfer() == 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Brackets. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need parens here though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know you don't, it just feels it would make it a bit more readable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to make you happy :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. |
||
} | ||
|
||
private: | ||
uint8_t *m_control_setup_buffer; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(AnymaAsyncUsbSender); | ||
}; | ||
|
||
// AsynchronousAnymauDMX | ||
// ----------------------------------------------------------------------------- | ||
|
||
AsynchronousAnymauDMX::AsynchronousAnymauDMX( | ||
LibUsbAdaptor *adaptor, | ||
libusb_device *usb_device, | ||
const string &serial) | ||
: AnymauDMX(adaptor, serial) { | ||
m_sender.reset(new AnymaAsyncUsbSender(m_adaptor, usb_device)); | ||
} | ||
|
||
bool AsynchronousAnymauDMX::Init() { | ||
return m_sender->Init(); | ||
} | ||
|
||
bool AsynchronousAnymauDMX::SendDMX(const DmxBuffer &buffer) { | ||
return m_sender->SendDMX(buffer); | ||
} | ||
} // namespace usbdmx | ||
} // namespace plugin | ||
} // namespace ola |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Library General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* AnymauDMX.h | ||
* The synchronous and asynchronous Anyma uDMX widgets. | ||
* Copyright (C) 2014 Simon Newton | ||
*/ | ||
|
||
#ifndef PLUGINS_USBDMX_ANYMAUDMX_H_ | ||
#define PLUGINS_USBDMX_ANYMAUDMX_H_ | ||
|
||
#include <libusb.h> | ||
#include <memory> | ||
#include <string> | ||
|
||
#include "ola/DmxBuffer.h" | ||
#include "ola/base/Macro.h" | ||
#include "ola/thread/Mutex.h" | ||
#include "plugins/usbdmx/Widget.h" | ||
|
||
namespace ola { | ||
namespace plugin { | ||
namespace usbdmx { | ||
|
||
/** | ||
* @brief The base class for Anyma Widgets. | ||
*/ | ||
class AnymauDMX: public BaseWidget { | ||
public: | ||
/** | ||
* @brief Create a new AnymauDMX. | ||
* @param adaptor the LibUsbAdaptor to use. | ||
* @param serial the serial number of the widget. | ||
*/ | ||
AnymauDMX(LibUsbAdaptor *adaptor, | ||
const std::string &serial) | ||
: BaseWidget(adaptor), | ||
m_serial(serial) {} | ||
|
||
virtual ~AnymauDMX() {} | ||
|
||
/** | ||
* @brief Get the serial number of this widget. | ||
* @returns The serial number of the widget. | ||
*/ | ||
std::string SerialNumber() const { | ||
return m_serial; | ||
} | ||
|
||
private: | ||
std::string m_serial; | ||
}; | ||
|
||
/** | ||
* @brief An Anyma widget that uses synchronous libusb operations. | ||
* | ||
* Internally this spawns a new thread to avoid blocking SendDMX() calls. | ||
*/ | ||
class SynchronousAnymauDMX: public AnymauDMX { | ||
public: | ||
/** | ||
* @brief Create a new SynchronousAnymauDMX. | ||
* @param adaptor the LibUsbAdaptor to use. | ||
* @param usb_device the libusb_device to use for the widget. | ||
* @param serial the serial number of the widget. | ||
*/ | ||
SynchronousAnymauDMX(LibUsbAdaptor *adaptor, | ||
libusb_device *usb_device, | ||
const std::string &serial); | ||
|
||
bool Init(); | ||
|
||
bool SendDMX(const DmxBuffer &buffer); | ||
|
||
private: | ||
libusb_device* const m_usb_device; | ||
std::auto_ptr<class AnymaThreadedSender> m_sender; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(SynchronousAnymauDMX); | ||
}; | ||
|
||
/** | ||
* @brief An Anyma widget that uses asynchronous libusb operations. | ||
*/ | ||
class AsynchronousAnymauDMX : public AnymauDMX { | ||
public: | ||
/** | ||
* @brief Create a new AsynchronousAnymauDMX. | ||
* @param adaptor the LibUsbAdaptor to use. | ||
* @param usb_device the libusb_device to use for the widget. | ||
* @param serial the serial number of the widget. | ||
*/ | ||
AsynchronousAnymauDMX(LibUsbAdaptor *adaptor, | ||
libusb_device *usb_device, | ||
const std::string &serial); | ||
|
||
bool Init(); | ||
|
||
bool SendDMX(const DmxBuffer &buffer); | ||
|
||
private: | ||
std::auto_ptr<class AnymaAsyncUsbSender> m_sender; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(AsynchronousAnymauDMX); | ||
}; | ||
} // namespace usbdmx | ||
} // namespace plugin | ||
} // namespace ola | ||
#endif // PLUGINS_USBDMX_ANYMAUDMX_H_ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Library General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* AnymauDMXFactory.cpp | ||
* The factory for Anyma uDMX widgets. | ||
* Copyright (C) 2014 Simon Newton | ||
*/ | ||
|
||
#include "plugins/usbdmx/AnymauDMXFactory.h" | ||
|
||
#include "ola/Logging.h" | ||
#include "ola/base/Flags.h" | ||
#include "plugins/usbdmx/AnymauDMX.h" | ||
#include "plugins/usbdmx/LibUsbAdaptor.h" | ||
|
||
DECLARE_bool(use_async_libusb); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra blank line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
||
namespace ola { | ||
namespace plugin { | ||
namespace usbdmx { | ||
|
||
const char AnymauDMXFactory::EXPECTED_MANUFACTURER[] = "www.anyma.ch"; | ||
const char AnymauDMXFactory::EXPECTED_PRODUCT[] = "uDMX"; | ||
const uint16_t AnymauDMXFactory::PRODUCT_ID = 0x05DC; | ||
const uint16_t AnymauDMXFactory::VENDOR_ID = 0x16C0; | ||
|
||
bool AnymauDMXFactory::DeviceAdded( | ||
WidgetObserver *observer, | ||
libusb_device *usb_device, | ||
const struct libusb_device_descriptor &descriptor) { | ||
if (descriptor.idVendor != VENDOR_ID || descriptor.idProduct != PRODUCT_ID || | ||
HasDevice(usb_device)) { | ||
return false; | ||
} | ||
|
||
OLA_INFO << "Found a new Anyma device"; | ||
LibUsbAdaptor::DeviceInformation info; | ||
if (!m_adaptor->GetDeviceInfo(usb_device, descriptor, &info)) { | ||
return false; | ||
} | ||
|
||
if (!m_adaptor->CheckManufacturer(EXPECTED_MANUFACTURER, info)) { | ||
return false; | ||
} | ||
|
||
if (!m_adaptor->CheckProduct(EXPECTED_PRODUCT, info)) { | ||
return false; | ||
} | ||
|
||
// 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. | ||
if (info.serial.empty()) { | ||
if (m_missing_serial_number) { | ||
OLA_WARN << "Failed to read serial number or serial number empty. " | ||
<< "We can only support one device without a serial number."; | ||
return false; | ||
} else { | ||
OLA_WARN << "Failed to read serial number from " << info.manufacturer | ||
<< " : " << info.product | ||
<< " the device probably doesn't have one"; | ||
m_missing_serial_number = true; | ||
} | ||
} | ||
|
||
AnymauDMX *widget = NULL; | ||
if (FLAGS_use_async_libusb) { | ||
widget = new AsynchronousAnymauDMX(m_adaptor, usb_device, info.serial); | ||
} else { | ||
widget = new SynchronousAnymauDMX(m_adaptor, usb_device, info.serial); | ||
} | ||
return AddWidget(observer, usb_device, widget); | ||
} | ||
} // namespace usbdmx | ||
} // namespace plugin | ||
} // namespace ola |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Firstly, personally I'm still in favour of the files just being manufacturer, rather than manufacturer-device.
Regardless of that, this file doesn't match the Camel Case style we're using elsewhere, and just looks a bit odd to me. I wonder if it should be AnymaUDmx.cpp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual name of the device is uDMX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, but we don't stick to that with include/ola/DmxBuffer.h; although we're not very consistent looking at include/ola/http/HTTPServer.h.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I standardized on 'DMX' for the client code but DmxBuffer predates that. I'd prefer to use DMX going forward.