-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of https://github.com/OpenLightingProject/ola i…
…nto trivial-fixes
- Loading branch information
Showing
17 changed files
with
1,818 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
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, | ||
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; | ||
} | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
|
||
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 |
Oops, something went wrong.