syndilights/open-lighting-architecture/ola-0.8.4/plugins/usbdmx/UsbDmxPlugin.cpp

283 lines
7.3 KiB
C++

/*
* This dmxgram 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 dmxgram 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 dmxgram; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* UsbDmxPlugin.cpp
* The UsbDmx plugin for ola
* Copyright (C) 2006-2007 Simon Newton
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <libusb.h>
#include <string>
#include <utility>
#include <vector>
#include "ola/Closure.h"
#include "ola/Logging.h"
#include "olad/PluginAdaptor.h"
#include "olad/Preferences.h"
#include "ola/network/Socket.h"
#include "plugins/usbdmx/AnymaDevice.h"
#include "plugins/usbdmx/FirmwareLoader.h"
#include "plugins/usbdmx/SunliteDevice.h"
#include "plugins/usbdmx/SunliteFirmwareLoader.h"
#include "plugins/usbdmx/UsbDevice.h"
#include "plugins/usbdmx/UsbDmxPlugin.h"
#include "plugins/usbdmx/VellemanDevice.h"
namespace ola {
namespace plugin {
namespace usbdmx {
using ola::network::DeviceSocket;
const char UsbDmxPlugin::PLUGIN_NAME[] = "USB";
const char UsbDmxPlugin::PLUGIN_PREFIX[] = "usbdmx";
/*
* Called by libusb when a new socket is created.
*/
void libusb_fd_added(int fd, short events, void *data) {
UsbDmxPlugin *plugin = reinterpret_cast<UsbDmxPlugin*>(data);
OLA_INFO << "USB new FD: " << fd;
plugin->AddDeviceSocket(fd);
}
/*
* Called by libusb when a socket is no longer needed.
*/
void libusb_fd_removed(int fd, void *data) {
UsbDmxPlugin *plugin = reinterpret_cast<UsbDmxPlugin*>(data);
OLA_INFO << "USB rm FD: " << fd;
plugin->RemoveDeviceSocket(fd);
}
/*
* Start the plugin
*/
bool UsbDmxPlugin::StartHook() {
if (libusb_init(NULL)) {
OLA_WARN << "Failed to init libusb";
return false;
}
// libusb_set_debug(NULL, 3);
if (LoadFirmware()) {
// we loaded firmware for at least one device, set up a callback to run in
// a couple of seconds to re-scan for devices
m_plugin_adaptor->RegisterSingleTimeout(
3500,
NewSingleClosure(this, &UsbDmxPlugin::FindDevices));
}
FindDevices();
/*
if (!libusb_pollfds_handle_timeouts(m_usb_context)) {
OLA_FATAL << "libusb doesn't have timeout support, BAD";
return false;
}
libusb_set_pollfd_notifiers(m_usb_context,
&libusb_fd_added,
&libusb_fd_removed,
this);
const libusb_pollfd **pollfds = libusb_get_pollfds(m_usb_context);
while (*pollfds) {
OLA_WARN << "poll fd " << (*pollfds)->fd;
AddDeviceSocket((*pollfds)->fd);
pollfds++;
}
*/
return true;
}
/*
* Load firmware onto devices if required.
* @returns true if we loaded firmware for one or more devices
*/
bool UsbDmxPlugin::LoadFirmware() {
libusb_device **device_list;
size_t device_count = libusb_get_device_list(NULL, &device_list);
FirmwareLoader *loader;
bool loaded = false;
for (unsigned int i = 0; i < device_count; i++) {
libusb_device *usb_device = device_list[i];
loader = NULL;
struct libusb_device_descriptor device_descriptor;
libusb_get_device_descriptor(usb_device, &device_descriptor);
if (device_descriptor.idVendor == 0x0962 &&
device_descriptor.idProduct == 0x2000) {
loader = new SunliteFirmwareLoader(usb_device);
}
if (loader) {
loader->LoadFirmware();
loaded = true;
delete loader;
}
}
libusb_free_device_list(device_list, 1); // unref devices
return loaded;
}
/*
* Find known devices & register them
*/
void UsbDmxPlugin::FindDevices() {
libusb_device **device_list;
libusb_device *found = NULL;
size_t device_count = libusb_get_device_list(NULL, &device_list);
for (unsigned int i = 0; i < device_count; i++) {
libusb_device *usb_device = device_list[i];
struct libusb_device_descriptor device_descriptor;
libusb_get_device_descriptor(usb_device, &device_descriptor);
UsbDevice *device = NULL;
pair<uint8_t, uint8_t> bus_dev_id(libusb_get_bus_number(usb_device),
libusb_get_device_address(usb_device));
if ((m_registered_devices.find(bus_dev_id) != m_registered_devices.end()))
continue;
if (device_descriptor.idVendor == 0x10cf &&
device_descriptor.idProduct == 0x8062) {
OLA_INFO << "Found a Velleman USB device";
device = new VellemanDevice(this, usb_device);
} else if (device_descriptor.idVendor == 0x0962 &&
device_descriptor.idProduct == 0x2001) {
OLA_INFO << "found a sunlite device";
device = new SunliteDevice(this, usb_device);
} else if (device_descriptor.idVendor == 0x16C0 &&
device_descriptor.idProduct == 0x05DC) {
OLA_INFO << "found a anyma device";
device = new AnymaDevice(this, usb_device);
}
if (device) {
if (!device->Start()) {
delete device;
continue;
}
m_registered_devices.insert(bus_dev_id);
m_devices.push_back(device);
m_plugin_adaptor->RegisterDevice(device);
}
}
libusb_free_device_list(device_list, 1); // unref devices
}
/*
* Stop the plugin
* @return true on success, false on failure
*/
bool UsbDmxPlugin::StopHook() {
vector<UsbDevice*>::iterator iter;
for (iter = m_devices.begin(); iter != m_devices.end(); ++iter) {
m_plugin_adaptor->UnregisterDevice(*iter);
(*iter)->Stop();
delete *iter;
}
m_devices.clear();
m_registered_devices.clear();
libusb_exit(NULL);
if (m_sockets.size()) {
OLA_WARN << "libusb is still using sockets, this is a bug";
}
return true;
}
/*
* Return the description for this plugin
*/
string UsbDmxPlugin::Description() const {
return
"USB DMX Plugin\n"
"----------------------------\n"
"\n"
"This plugin supports various USB DMX devices including the \n"
"Anyma uDMX, Sunlite USBDMX2 & Velleman K8062.\n";
}
/*
* Default to sensible values
*/
bool UsbDmxPlugin::SetDefaultPreferences() {
if (!m_preferences)
return false;
return true;
}
bool UsbDmxPlugin::AddDeviceSocket(int fd) {
vector<DeviceSocket*>::const_iterator iter = m_sockets.begin();
for (; iter != m_sockets.end(); ++iter) {
if ((*iter)->ReadDescriptor() == fd)
return true;
}
DeviceSocket *socket = new DeviceSocket(fd);
socket->SetOnData(NewClosure(this, &UsbDmxPlugin::SocketReady));
m_plugin_adaptor->AddSocket(socket);
m_sockets.push_back(socket);
}
bool UsbDmxPlugin::RemoveDeviceSocket(int fd) {
vector<DeviceSocket*>::iterator iter = m_sockets.begin();
for (; iter != m_sockets.end(); ++iter) {
if ((*iter)->ReadDescriptor() == fd) {
m_plugin_adaptor->RemoveSocket(*iter);
delete *iter;
m_sockets.erase(iter);
return true;
}
}
return false;
}
/*
* Called when there is activity on one of our sockets.
*/
void UsbDmxPlugin::SocketReady() {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
libusb_handle_events_timeout(NULL, &tv);
}
} // usbdmx
} // plugin
} // ola