much better input-device class registration

This commit is contained in:
Jack Andersen 2015-04-29 21:01:55 -10:00
parent d4b1211c24
commit 4b8651b844
19 changed files with 184 additions and 106 deletions

13
InputDeviceClasses.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "inputdev/SDeviceSignature.hpp"
#include "inputdev/CDolphinSmashAdapter.hpp"
namespace boo
{
const SDeviceSignature BOO_DEVICE_SIGS[] =
{
DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337, true),
DEVICE_SIG_SENTINEL()
};
}

View File

@ -11,11 +11,12 @@ namespace boo {typedef CCGLContext CGraphicsContext;}
#elif defined(__GNUC__) || defined(__clang__)
#include "x11/CGLXContext.hpp"
namespace boo {typedef boo::CGLXContext CGraphicsContext;}
namespace boo {typedef CGLXContext CGraphicsContext;}
#endif
#include "IGraphicsContext.hpp"
#include "inputdev/CDeviceFinder.hpp"
#include "inputdev/CDolphinSmashAdapter.hpp"
#endif // BOO_HPP

View File

@ -3,6 +3,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
namespace boo
{
@ -23,16 +24,18 @@ public:
virtual ~CDeviceBase();
void closeDevice();
virtual void deviceDisconnected()=0;
virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);}
/* Low-Level API */
bool sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length);
size_t receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length);
virtual void transferCycle() {};
virtual void finalCycle() {};
virtual void initialCycle() {}
virtual void transferCycle() {}
virtual void finalCycle() {}
/* High-Level API */
bool sendReport(const uint8_t* data, size_t length);
virtual size_t receiveReport(uint8_t* data, size_t length) {};
virtual size_t receiveReport(uint8_t* data, size_t length) {return 0;}
};

View File

@ -6,7 +6,8 @@
#include <stdexcept>
#include "CDeviceToken.hpp"
#include "IHIDListener.hpp"
#include "DeviceClasses.hpp"
#include "SDeviceSignature.hpp"
#include <string.h>
namespace boo
{
@ -24,7 +25,7 @@ public:
private:
/* Types this finder is interested in (immutable) */
EDeviceMask m_types;
SDeviceSignature::TDeviceSignatureSet m_types;
/* Platform-specific USB event registration
* (for auto-scanning, NULL if not registered) */
@ -45,9 +46,10 @@ private:
}
inline void _insertToken(CDeviceToken&& token)
{
if (BooDeviceMatchToken(token, m_types)) {
if (SDeviceSignature::DeviceMatchToken(token, m_types)) {
m_tokensLock.lock();
TInsertedDeviceToken inseredTok = m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token)));
TInsertedDeviceToken inseredTok =
m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token)));
m_tokensLock.unlock();
deviceConnected(inseredTok.first->second);
}
@ -81,12 +83,22 @@ public:
};
/* Application must specify its interested device-types */
CDeviceFinder(EDeviceMask types)
: m_types(types), m_listener(NULL)
CDeviceFinder(std::vector<const char*> types)
: m_listener(NULL)
{
if (skDevFinder)
throw std::runtime_error("only one instance of CDeviceFinder may be constructed");
skDevFinder = this;
for (const char* typeName : types)
{
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
while (sigIter->m_name)
{
if (!strcmp(sigIter->m_name, typeName))
m_types.push_back(sigIter);
++sigIter;
}
}
}
~CDeviceFinder()
{
@ -97,7 +109,7 @@ public:
}
/* Get interested device-type mask */
inline EDeviceMask getTypes() const {return m_types;}
inline const SDeviceSignature::TDeviceSignatureSet& getTypes() const {return m_types;}
/* Iterable set of tokens */
inline CDeviceTokensHandle getTokens() {return CDeviceTokensHandle(*this);}

View File

@ -3,7 +3,7 @@
#include <string>
#include "CDeviceBase.hpp"
#include "DeviceClasses.hpp"
#include "SDeviceSignature.hpp"
namespace boo
{
@ -48,7 +48,7 @@ public:
inline CDeviceBase* openAndGetDevice()
{
if (!m_connectedDev)
m_connectedDev = BooDeviceNew(*this);
m_connectedDev = SDeviceSignature::DeviceNew(*this);
return m_connectedDev;
}

View File

@ -54,6 +54,7 @@ class CDolphinSmashAdapter final : public CDeviceBase
uint8_t m_rumbleState;
bool m_didHandshake;
void deviceDisconnected();
void initialCycle();
void transferCycle();
void finalCycle();
public:

View File

@ -1,32 +0,0 @@
#ifndef CDEVICECLASSES_HPP
#define CDEVICECLASSES_HPP
#include "CDolphinSmashAdapter.hpp"
#include "CRevolutionPad.hpp"
#include "CCafeProPad.hpp"
#include "CDualshockPad.hpp"
#include "CGenericPad.hpp"
namespace boo
{
#define VID_NINTENDO 0x57e
#define PID_SMASH_ADAPTER 0x337
enum EDeviceMask
{
DEV_NONE = 0,
DEV_DOL_SMASH_ADAPTER = 1<<0,
DEV_RVL_PAD = 1<<1,
DEV_CAFE_PRO_PAD = 1<<2,
DEV_DUALSHOCK_PAD = 1<<3,
DEV_GENERIC_PAD = 1<<4,
DEV_ALL = 0xff
};
bool BooDeviceMatchToken(const CDeviceToken& token, EDeviceMask mask);
CDeviceBase* BooDeviceNew(CDeviceToken& token);
}
#endif // CDEVICECLASSES_HPP

View File

@ -15,7 +15,7 @@ class CDeviceFinder;
class IHIDListener
{
public:
virtual ~IHIDListener() {};
virtual ~IHIDListener() {}
/* Automatic device scanning */
virtual bool startScanning()=0;

View File

@ -0,0 +1,37 @@
#ifndef SDeviceSignature_HPP
#define SDeviceSignature_HPP
#include <vector>
#include <functional>
namespace boo
{
class CDeviceToken;
class CDeviceBase;
struct SDeviceSignature
{
typedef std::vector<const SDeviceSignature*> TDeviceSignatureSet;
typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda;
const char* m_name;
unsigned m_vid, m_pid;
bool m_lowLevel;
TFactoryLambda m_factory;
SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */
SDeviceSignature(const char* name, unsigned vid, unsigned pid, bool lowLevel, TFactoryLambda&& factory)
: m_name(name), m_vid(vid), m_pid(pid), m_lowLevel(lowLevel), m_factory(factory) {}
static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet);
static CDeviceBase* DeviceNew(CDeviceToken& token);
};
#define DEVICE_SIG(name, vid, pid, lowLevel) \
SDeviceSignature(#name, vid, pid, lowLevel, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
#define DEVICE_SIG_SENTINEL() SDeviceSignature()
extern const SDeviceSignature BOO_DEVICE_SIGS[];
}
#endif // SDeviceSignature_HPP

View File

@ -15,9 +15,9 @@ HEADERS += \
$$PWD/include/inputdev/CDeviceFinder.hpp \
$$PWD/include/inputdev/CDeviceToken.hpp \
$$PWD/include/inputdev/CDeviceBase.hpp \
$$PWD/include/inputdev/DeviceClasses.hpp \
$$PWD/include/inputdev/IHIDListener.hpp \
$$PWD/src/inputdev/IHIDDevice.hpp
$$PWD/src/inputdev/IHIDDevice.hpp \
$$PWD/include/inputdev/SDeviceSignature.hpp
unix:!macx:HEADERS += \
$$PWD/include/x11/CGLXContext.hpp
@ -29,6 +29,7 @@ win32:HEADERS += \
$$PWD/include/win/CWGLContext.hpp
SOURCES += \
$$PWD/InputDeviceClasses.cpp \
$$PWD/src/CSurface.cpp \
$$PWD/src/CRetraceWaiter.cpp \
$$PWD/src/CInputRelay.cpp \
@ -39,9 +40,9 @@ SOURCES += \
$$PWD/src/inputdev/CDualshockPad.cpp \
$$PWD/src/inputdev/CGenericPad.cpp \
$$PWD/src/inputdev/CDeviceBase.cpp \
$$PWD/src/inputdev/DeviceClasses.cpp \
$$PWD/src/inputdev/CHIDListenerUdev.cpp \
$$PWD/src/inputdev/CHIDDeviceUdev.cpp
$$PWD/src/inputdev/CHIDDeviceUdev.cpp \
$$PWD/src/inputdev/SDeviceSignature.cpp
unix:!macx:SOURCES += \
$$PWD/src/x11/CGLXContext.cpp

View File

@ -1,6 +1,8 @@
CONFIG -= Qt
#QMAKE_CXXFLAGS -= -std=c++0x
QMAKE_CXXFLAGS += -std=c++11
CONFIG += c++11
QMAKE_CXXFLAGS += -stdlib=libc++
LIBS += -std=c++11 -stdlib=libc++ -lc++abi
#unix:!macx:CONFIG += link_pkgconfig
#unix:!macx:PKGCONFIG += x11

View File

@ -118,7 +118,12 @@ void CDolphinSmashAdapter::transferCycle()
m_rumbleState = rumbleReq;
}
}
};
}
void CDolphinSmashAdapter::initialCycle()
{
}
void CDolphinSmashAdapter::finalCycle()
{
@ -127,7 +132,7 @@ void CDolphinSmashAdapter::finalCycle()
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
}
};
}
void CDolphinSmashAdapter::deviceDisconnected()
{

View File

@ -8,6 +8,9 @@
#define MAX_REPORT_SIZE 65536
namespace boo
{
class CHIDDeviceIOKit final : public IHIDDevice
{
CDeviceToken& m_token;
@ -253,3 +256,5 @@ IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLeve
{
return new CHIDDeviceIOKit(token, devImp, lowLevel);
}
}

View File

@ -17,7 +17,7 @@
namespace boo
{
udev* BooGetUdev();
udev* GetUdev();
#define MAX_REPORT_SIZE 65536
@ -52,7 +52,7 @@ class CHIDDeviceUdev final : public IHIDDevice
(void*)data
};
int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer);
if (ret != length)
if (ret != (int)length)
return false;
return true;
}
@ -79,12 +79,23 @@ class CHIDDeviceUdev final : public IHIDDevice
{
unsigned i;
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* hidDev = udev_device_new_from_syspath(BooGetUdev(), device->m_devPath.c_str());
udev_device* hidDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
/* Get the HID element's parent (USB interrupt transfer-interface) */
udev_device* usbDev = udev_device_get_parent_with_subsystem_devtype(hidDev, "usb", "usb_device");
const char* dp = udev_device_get_devnode(usbDev);
device->m_devFd = open(dp, O_RDONLY);
device->m_devFd = open(dp, O_RDWR);
if (device->m_devFd < 0)
{
char errStr[256];
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().c_str(), dp, strerror(errno));
device->m_devImp.deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(hidDev);
return;
}
usb_device_descriptor devDesc = {0};
read(device->m_devFd, &devDesc, 1);
read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1);
@ -128,13 +139,14 @@ class CHIDDeviceUdev final : public IHIDDevice
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp.initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp.transferCycle();
device->m_devImp.finalCycle();
/* Cleanup */
close(device->m_devFd);
device->m_devFd = NULL;
device->m_devFd = 0;
udev_device_unref(hidDev);
}
@ -173,7 +185,7 @@ public:
~CHIDDeviceUdev()
{
m_runningTransferLoop = false;
m_thread->detach();
m_thread->join();
delete m_thread;
}

View File

@ -6,6 +6,9 @@
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
namespace boo
{
/*
* Reference: http://oroboro.com/usb-serial-number-osx/
*/
@ -286,3 +289,4 @@ IHIDListener* IHIDListenerNew(CDeviceFinder& finder)
return new CHIDListenerIOKit(finder);
}
}

View File

@ -8,7 +8,7 @@ namespace boo
{
static udev* UDEV_INST = NULL;
udev* BooGetUdev()
udev* GetUdev()
{
if (!UDEV_INST)
UDEV_INST = udev_new();
@ -105,7 +105,7 @@ public:
{
/* Setup hotplug events */
m_udevMon = udev_monitor_new_from_netlink(BooGetUdev(), "udev");
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
if (!m_udevMon)
throw std::runtime_error("unable to init udev_monitor");
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "hid", NULL);
@ -145,7 +145,7 @@ public:
/* Manual device scanning */
bool scanNow()
{
udev_enumerate* uenum = udev_enumerate_new(BooGetUdev());
udev_enumerate* uenum = udev_enumerate_new(GetUdev());
udev_enumerate_add_match_subsystem(uenum, "hid");
udev_enumerate_scan_devices(uenum);
udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);

View File

@ -1,43 +0,0 @@
#include "inputdev/DeviceClasses.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
bool BooDeviceMatchToken(const CDeviceToken& token, EDeviceMask mask)
{
if (mask & DEV_DOL_SMASH_ADAPTER &&
token.getVendorId() == VID_NINTENDO && token.getProductId() == PID_SMASH_ADAPTER)
return true;
return false;
}
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel);
CDeviceBase* BooDeviceNew(CDeviceToken& token)
{
CDeviceBase* retval = NULL;
bool lowLevel = false;
if (token.getVendorId() == VID_NINTENDO && token.getProductId() == PID_SMASH_ADAPTER)
{
retval = new CDolphinSmashAdapter(&token);
lowLevel = true;
}
if (!retval)
return NULL;
IHIDDevice* newDev = IHIDDeviceNew(token, *retval, lowLevel);
if (!newDev)
{
delete retval;
return NULL;
}
return retval;
}
}

View File

@ -0,0 +1,57 @@
#include "inputdev/SDeviceSignature.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
extern const SDeviceSignature BOO_DEVICE_SIGS[];
bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet)
{
for (const SDeviceSignature* sig : sigSet)
{
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true;
}
return false;
}
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel);
CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
{
CDeviceBase* retval = NULL;
const SDeviceSignature* foundSig = NULL;
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
unsigned targetVid = token.getVendorId();
unsigned targetPid = token.getProductId();
while (sigIter->m_name)
{
if (sigIter->m_vid == targetVid && sigIter->m_pid == targetPid)
{
foundSig = sigIter;
break;
}
++sigIter;
}
if (!foundSig)
return NULL;
retval = foundSig->m_factory(&token);
if (!retval)
return NULL;
IHIDDevice* newDev = IHIDDeviceNew(token, *retval, foundSig->m_lowLevel);
if (!newDev)
{
delete retval;
return NULL;
}
return retval;
}
}

View File

@ -33,7 +33,7 @@ class CTestDeviceFinder : public CDeviceFinder
CDolphinSmashAdapterCallback m_cb;
public:
CTestDeviceFinder()
: CDeviceFinder(DEV_DOL_SMASH_ADAPTER)
: CDeviceFinder({"CDolphinSmashAdapter"})
{}
void deviceConnected(CDeviceToken& tok)
{