Skip to content

Commit

Permalink
Add asynchronous command sending through Dispatcher object
Browse files Browse the repository at this point in the history
  • Loading branch information
cvuchener committed Mar 8, 2017
1 parent 3fc4610 commit 5dc3181
Show file tree
Hide file tree
Showing 35 changed files with 818 additions and 459 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -Wall")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(TINYXML2 tinyxml2)
pkg_check_modules(LIBUDEV libudev)
Expand Down
1 change: 1 addition & 0 deletions src/libhidpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(LIBHIDPP_SOURCES
misc/Log.cpp
misc/CRC.cpp
misc/UsageStrings.cpp
hidpp/Dispatcher.cpp
hidpp/Device.cpp
hidpp/Report.cpp
hidpp/DeviceInfo.cpp
Expand Down
203 changes: 11 additions & 192 deletions src/libhidpp/hidpp/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,112 +18,20 @@

#include "Device.h"

#include <hidpp/Dispatcher.h>
#include <hidpp10/Device.h>
#include <hidpp10/IReceiver.h>
#include <hidpp20/IRoot.h>
#include <hidpp10/Error.h>
#include <hidpp20/Error.h>
#include <misc/Log.h>

#include <algorithm>

using namespace HIDPP;

Device::NoHIDPPReportException::NoHIDPPReportException ()
Device::Device (Dispatcher *dispatcher, DeviceIndex device_index):
_dispatcher (dispatcher), _device_index (device_index)
{
}

const char *Device::NoHIDPPReportException::what () const noexcept
{
return "No HID++ report";
}

static const std::array<uint8_t, 27> ShortReportDesc = {
0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
0x09, 0x01, // Usage (0001 - Vendor)
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};

static const std::array<uint8_t, 27> LongReportDesc = {
0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
0x09, 0x02, // Usage (0002 - Vendor)
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x75, 0x08, // Report Size (8)
0x95, 0x13, // Report Count (19)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};

/* Alternative versions from the G602 */
static const std::array<uint8_t, 27> ShortReportDesc2 = {
0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
0x09, 0x01, // Usage (0001 - Vendor)
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};

static const std::array<uint8_t, 27> LongReportDesc2 = {
0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
0x09, 0x02, // Usage (0002 - Vendor)
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x95, 0x13, // Report Count (19)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};

Device::Device (const std::string &path, DeviceIndex device_index):
HIDRaw (path), _device_index (device_index)
{
const HIDRaw::ReportDescriptor &rdesc = getReportDescriptor ();
if (rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
ShortReportDesc.begin (),
ShortReportDesc.end ()) &&
rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
ShortReportDesc2.begin (),
ShortReportDesc2.end ()))
throw NoHIDPPReportException ();
if (rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
LongReportDesc.begin (),
LongReportDesc.end ()) &&
rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
LongReportDesc2.begin (),
LongReportDesc2.end ()))
throw NoHIDPPReportException ();

if (device_index >= WirelessDevice1 && device_index <= WirelessDevice6) {
HIDPP10::Device ur (path, DefaultDevice);
HIDPP10::Device ur (_dispatcher, DefaultDevice);
HIDPP10::IReceiver ireceiver (&ur);
ireceiver.getDeviceInformation (device_index - 1,
nullptr,
Expand All @@ -133,73 +41,20 @@ Device::Device (const std::string &path, DeviceIndex device_index):
_name = ireceiver.getDeviceName (device_index - 1);
}
else {
_product_id = HIDRaw::productID ();
_name = HIDRaw::name ();
auto &hidraw = _dispatcher->hidraw ();
_product_id = hidraw.productID ();
_name = hidraw.name ();
}
}

DeviceIndex Device::deviceIndex () const
Dispatcher *Device::dispatcher () const
{
return _device_index;
return _dispatcher;
}

void Device::getProtocolVersion (unsigned int &major, unsigned int &minor)
DeviceIndex Device::deviceIndex () const
{
constexpr int software_id = 1; // Must be a 4 bit unsigned value
Report request (Report::Short,
_device_index,
HIDPP20::IRoot::index,
HIDPP20::IRoot::Ping,
software_id);
sendReport (request);
while (true) {
Report response = getReport (true); // Time out if there is no valid response received fast enough

if (response.deviceIndex () != _device_index) {
Log::debug () << __FUNCTION__ << ": "
<< "Ignored report with wrong device index"
<< std::endl;
continue;
}

uint8_t sub_id, address, error_code;
if (response.checkErrorMessage10 (&sub_id, &address, &error_code)) {
if (sub_id != HIDPP20::IRoot::index ||
address != (HIDPP20::IRoot::Ping << 4 | software_id)) {
Log::debug () << __FUNCTION__ << ": "
<< "Ignored error message with wrong subID or address"
<< std::endl;
continue;
}
if (error_code != HIDPP10::Error::InvalidSubID)
throw HIDPP10::Error (static_cast<HIDPP10::Error::ErrorCode> (error_code));
major = 1;
minor = 0;
return;
}
uint8_t feature_index;
unsigned int function, sw_id;
if (response.checkErrorMessage20 (&feature_index, &function, &sw_id, &error_code)) {
if (feature_index != HIDPP20::IRoot::index || function != HIDPP20::IRoot::Ping || sw_id != software_id) {
Log::debug () << __FUNCTION__ << ": "
<< "Ignored error message with wrong feature/function/softwareID"
<< std::endl;
continue;
}
throw HIDPP20::Error (static_cast<HIDPP20::Error::ErrorCode> (error_code));
}
if (response.featureIndex () == HIDPP20::IRoot::index &&
response.function () == HIDPP20::IRoot::Ping &&
response.softwareID () == software_id) {
auto params = response.parameterBegin ();
major = params[0];
minor = params[1];
return;
}
Log::debug () << __FUNCTION__ << ": "
<< "Ignored report with wrong feature/function/softwareID"
<< std::endl;
}
return _device_index;
}

uint16_t Device::productID () const
Expand All @@ -211,39 +66,3 @@ std::string Device::name () const
{
return _name;
}

int Device::sendReport (const Report &report)
{
return writeReport (report.rawReport ());
}

Report Device::getReport (bool timeout)
{
std::vector<uint8_t> raw_report;
while (true) {
try {
raw_report.resize (Report::MaxDataLength+1);
if (timeout)
readReport (raw_report, 1);
else
readReport (raw_report);
return Report (raw_report[0], &raw_report[1], raw_report.size () - 1);
}
catch (Report::InvalidReportID e) {
// Ignore non-HID++ reports
Log::debug () << __FUNCTION__ << ": "
<< "Ignored non HID++ report" << std::endl;
Log::debug ().printBytes ("Ignored report:",
raw_report.begin (), raw_report.end ());
continue;
}
catch (Report::InvalidReportLength e) {
// Ignore non-HID++ reports
Log::warning () << __FUNCTION__ << ": "
<< "Invalid HID++ report length" << std::endl;
Log::warning ().printBytes ("Ignored report:",
raw_report.begin (), raw_report.end ());
continue;
}
}
}
45 changes: 7 additions & 38 deletions src/libhidpp/hidpp/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,68 +19,49 @@
#ifndef HIDPP_DEVICE_H
#define HIDPP_DEVICE_H

#include <misc/HIDRaw.h>
#include <hidpp/defs.h>
#include <hidpp/Report.h>

namespace HIDPP
{

class Dispatcher;

/**
* A generic HID++ Device
*
* \ingroup hidpp
*/
class Device: public HIDRaw
class Device
{
public:
/**
* Exception when no HID++ report is found in the report descriptor.
*/
class NoHIDPPReportException: public std::exception
{
public:
NoHIDPPReportException ();
virtual const char *what () const noexcept;
};

/**
* HID++ device constructor.
*
* Open the hidraw device node at \p path.
*
* For receivers and wireless devices, multiple devices use the same hidraw
* node, \p device_index is needed to select a particular device.
*
* \throws SysCallError
* \throws NoHIDPPReportException
* \throws HIDPP10::Error Only for wireless devices, if there is an error
* while reading device information.
*/
Device (const std::string &path, DeviceIndex device_index = DefaultDevice);
Device (Dispatcher *dispatcher, DeviceIndex device_index = DefaultDevice);

Device (Device &&other) = default;
Dispatcher *dispatcher () const;

/**
* Access the device index.
*/
DeviceIndex deviceIndex () const;

/**
* Check the HID++ protocol version.
*
* \param major Major number of the protocol version.
* \param minor Minor number of the protocol version.
*/
void getProtocolVersion (unsigned int &major, unsigned int &minor);

/**
* Get the product ID of the device.
*
* - Use HID product ID for wired device or receivers.
* - Use wireless PID given by the receiver for wireless devices.
*/
uint16_t productID () const;

/**
* Get the product name of the device.
*
Expand All @@ -89,20 +70,8 @@ class Device: public HIDRaw
*/
std::string name () const;

/**
* Send a HID++ report to this device.
*/
int sendReport (const Report &report);
/**
* Read a HID++ report from this device.
*
* It discards any non-HID++ report.
*
* \param timeout If true, try to read a report with a time out, throw HIDRaw::TimeoutError if no valid report is read fast enough.
*/
Report getReport (bool timeout = false);

private:
Dispatcher *_dispatcher;
DeviceIndex _device_index;
uint16_t _product_id;
std::string _name;
Expand Down
Loading

0 comments on commit 5dc3181

Please sign in to comment.