Monitor all HID++ reports on wireless device 1
Again, many things were done in this commit such as implementing an I/O queue, a mutex_queue, and implementing the hidpp::Report class. I'm expecting commits to be like this until I can get a clean codebase for the backend.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#include <assert.h>
|
||||
#include "Device.h"
|
||||
#include "Report.h"
|
||||
|
||||
@@ -21,10 +22,67 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
|
||||
}
|
||||
|
||||
/// TODO: Initialize a single RawDevice for each path.
|
||||
Device::Device(std::string path, DeviceIndex index):
|
||||
Device::Device(const std::string& path, DeviceIndex index):
|
||||
raw_device (std::make_shared<raw::RawDevice>(path)), path (path), index (index)
|
||||
{
|
||||
supported_reports = getSupportedReports(raw_device->reportDescriptor());
|
||||
if(!supported_reports)
|
||||
throw InvalidDevice(InvalidDevice::NoHIDPPReport);
|
||||
}
|
||||
|
||||
// Pass all HID++ events with device index to this device.
|
||||
RawEventHandler rawEventHandler;
|
||||
rawEventHandler.condition = [index](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[Offset::Type] == Report::Short ||
|
||||
report[Offset::Type] == Report::Long) && (report[Offset::DeviceIndex] == index);
|
||||
};
|
||||
rawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
Report _report(report);
|
||||
this->handleEvent(_report);
|
||||
};
|
||||
|
||||
raw_device->addEventHandler("DEV_" + std::to_string(index), rawEventHandler);
|
||||
}
|
||||
|
||||
void Device::addEventHandler(const std::string& nickname, EventHandler& handler)
|
||||
{
|
||||
auto it = event_handlers.find(nickname);
|
||||
assert(it == event_handlers.end());
|
||||
|
||||
event_handlers.emplace(nickname, handler);
|
||||
}
|
||||
|
||||
void Device::removeEventHandler(const std::string& nickname)
|
||||
{
|
||||
event_handlers.erase(nickname);
|
||||
}
|
||||
|
||||
void Device::handleEvent(Report& report)
|
||||
{
|
||||
for(auto& handler : event_handlers)
|
||||
if(handler.second.condition(report))
|
||||
handler.second.callback(report);
|
||||
}
|
||||
|
||||
Report Device::sendReport(Report& report)
|
||||
{
|
||||
switch(report.type())
|
||||
{
|
||||
case Report::Short:
|
||||
if(!(supported_reports & HIDPP_REPORT_SHORT_SUPPORTED))
|
||||
report.setType(Report::Long);
|
||||
break;
|
||||
case Report::Long:
|
||||
/* Report can be truncated, but that isn't a good idea. */
|
||||
assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED);
|
||||
}
|
||||
|
||||
auto raw_response = raw_device->sendReport(report.rawReport());
|
||||
return Report(raw_response);
|
||||
}
|
||||
|
||||
void Device::listen()
|
||||
{
|
||||
raw_device->listen();
|
||||
}
|
||||
|
@@ -3,22 +3,21 @@
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include "../raw/RawDevice.h"
|
||||
#include "Report.h"
|
||||
#include "defs.h"
|
||||
|
||||
namespace logid::backend::hidpp
|
||||
namespace logid {
|
||||
namespace backend {
|
||||
namespace hidpp
|
||||
{
|
||||
enum DeviceIndex: uint8_t
|
||||
struct EventHandler
|
||||
{
|
||||
DefaultDevice = 0,
|
||||
WirelessDevice1 = 1,
|
||||
WirelessDevice2 = 2,
|
||||
WirelessDevice3 = 3,
|
||||
WirelessDevice4 = 4,
|
||||
WirelessDevice5 = 5,
|
||||
WirelessDevice6 = 6,
|
||||
CordedDevice = 0xff
|
||||
std::function<bool(Report&)> condition;
|
||||
std::function<void(Report&)> callback;
|
||||
};
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
@@ -35,17 +34,30 @@ namespace logid::backend::hidpp
|
||||
virtual Reason code() const noexcept;
|
||||
private:
|
||||
Reason _reason;
|
||||
|
||||
};
|
||||
Device(std::string path, DeviceIndex index);
|
||||
|
||||
Device(const std::string& path, DeviceIndex index);
|
||||
|
||||
std::string devicePath() const { return path; }
|
||||
DeviceIndex deviceIndex() const { return index; }
|
||||
|
||||
void listen(); // Runs asynchronously
|
||||
void stopListening();
|
||||
|
||||
void addEventHandler(const std::string& nickname, EventHandler& handler);
|
||||
void removeEventHandler(const std::string& nickname);
|
||||
|
||||
Report sendReport(Report& report);
|
||||
|
||||
void handleEvent(Report& report);
|
||||
private:
|
||||
std::shared_ptr<logid::backend::raw::RawDevice> raw_device;
|
||||
std::shared_ptr<raw::RawDevice> raw_device;
|
||||
std::string path;
|
||||
DeviceIndex index;
|
||||
uint8_t supported_reports;
|
||||
|
||||
std::map<std::string, EventHandler> event_handlers;
|
||||
};
|
||||
}
|
||||
} } }
|
||||
|
||||
#endif //LOGID_HIDPP_DEVICE_H
|
@@ -1,5 +1,6 @@
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include "Report.h"
|
||||
|
||||
using namespace logid::backend::hidpp;
|
||||
@@ -80,4 +81,80 @@ uint8_t hidpp::getSupportedReports(std::vector<uint8_t>&& rdesc)
|
||||
ret |= HIDPP_REPORT_LONG_SUPPORTED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
const char *Report::InvalidReportID::what() const noexcept
|
||||
{
|
||||
return "Invalid report ID";
|
||||
}
|
||||
|
||||
const char *Report::InvalidReportLength::what() const noexcept
|
||||
{
|
||||
return "Invalid report length";
|
||||
}
|
||||
|
||||
Report::Report(Report::Type type, DeviceIndex device_index,
|
||||
uint8_t feature_index, uint8_t function, uint8_t sw_id)
|
||||
{
|
||||
assert(!(function & functionMask));
|
||||
assert(!(sw_id & swIdMask));
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case Short:
|
||||
_data.resize(HeaderLength + ShortParamLength);
|
||||
break;
|
||||
case Long:
|
||||
_data.resize(HeaderLength + LongParamLength);
|
||||
break;
|
||||
default:
|
||||
throw InvalidReportID();
|
||||
}
|
||||
|
||||
_data[Offset::Type] = type;
|
||||
_data[Offset::DeviceIndex] = device_index;
|
||||
_data[Offset::Feature] = feature_index;
|
||||
_data[Offset::Function] = (function & functionMask) << 4 | (sw_id & swIdMask);
|
||||
}
|
||||
|
||||
Report::Report(const std::vector<uint8_t>& data)
|
||||
{
|
||||
_data = data;
|
||||
|
||||
switch(_data[Offset::Type])
|
||||
{
|
||||
case Short:
|
||||
_data.resize(HeaderLength + ShortParamLength);
|
||||
break;
|
||||
case Long:
|
||||
_data.resize(HeaderLength + LongParamLength);
|
||||
break;
|
||||
default:
|
||||
throw InvalidReportID();
|
||||
}
|
||||
}
|
||||
|
||||
void Report::setType(Report::Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Short:
|
||||
_data.resize(HeaderLength + ShortParamLength);
|
||||
break;
|
||||
case Long:
|
||||
_data.resize(HeaderLength + LongParamLength);
|
||||
break;
|
||||
default:
|
||||
throw InvalidReportID();
|
||||
}
|
||||
|
||||
_data[Offset::Type] = type;
|
||||
}
|
||||
|
||||
void Report::setParams(const std::vector<uint8_t>& _params)
|
||||
{
|
||||
assert(_params.size() <= _data.size()-HeaderLength);
|
||||
|
||||
for(std::size_t i = 0; i < _params.size(); i++)
|
||||
_data[Offset::Parameters + i] = _params[i];
|
||||
}
|
||||
|
@@ -3,9 +3,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include "../raw/RawDevice.h"
|
||||
#include "Device.h"
|
||||
|
||||
#define LOGID_HIDPP_SW_ID 0x0f
|
||||
#include "defs.h"
|
||||
|
||||
/* Some devices only support a subset of these reports */
|
||||
#define HIDPP_REPORT_SHORT_SUPPORTED 1U
|
||||
@@ -15,6 +13,16 @@
|
||||
namespace logid::backend::hidpp
|
||||
{
|
||||
uint8_t getSupportedReports(std::vector<uint8_t>&& rdesc);
|
||||
|
||||
namespace Offset
|
||||
{
|
||||
static constexpr uint8_t Type = 0;
|
||||
static constexpr uint8_t DeviceIndex = 1;
|
||||
static constexpr uint8_t Feature = 2;
|
||||
static constexpr uint8_t Function = 3;
|
||||
static constexpr uint8_t Parameters = 4;
|
||||
}
|
||||
|
||||
class Report
|
||||
{
|
||||
public:
|
||||
@@ -24,30 +32,43 @@ namespace logid::backend::hidpp
|
||||
Long = 0x11
|
||||
};
|
||||
|
||||
class InvalidReportID: std::exception
|
||||
class InvalidReportID: public std::exception
|
||||
{
|
||||
InvalidReportID();
|
||||
public:
|
||||
InvalidReportID() = default;
|
||||
virtual const char* what() const noexcept;
|
||||
};
|
||||
|
||||
class InvalidReportLength: std::exception
|
||||
class InvalidReportLength: public std::exception
|
||||
{
|
||||
InvalidReportLength();
|
||||
public:
|
||||
InvalidReportLength() = default;;
|
||||
virtual const char* what() const noexcept;
|
||||
};
|
||||
|
||||
static constexpr std::size_t MaxDataLength = 32;
|
||||
static constexpr std::size_t MaxDataLength = 20;
|
||||
static constexpr uint8_t swIdMask = 0x0f;
|
||||
static constexpr uint8_t functionMask = 0x0f;
|
||||
|
||||
Report(uint8_t report_id, const uint8_t* data, std::size_t length);
|
||||
Report(std::vector<uint8_t> data);
|
||||
Report(Type type, DeviceIndex device_index,
|
||||
uint8_t feature_index,
|
||||
uint8_t function,
|
||||
uint8_t sw_id);
|
||||
explicit Report(const std::vector<uint8_t>& data);
|
||||
|
||||
Type type() const;
|
||||
Type type() const { return static_cast<Type>(_data[Offset::Type]); };
|
||||
void setType(Report::Type type);
|
||||
|
||||
logid::backend::hidpp::DeviceIndex deviceIndex();
|
||||
std::vector<uint8_t>::const_iterator paramBegin() const { return _data.begin() + Offset::Parameters; }
|
||||
std::vector<uint8_t>::const_iterator paramEnd() const { return _data.end(); }
|
||||
void setParams(const std::vector<uint8_t>& _params);
|
||||
|
||||
logid::backend::hidpp::DeviceIndex deviceIndex()
|
||||
{
|
||||
return static_cast<DeviceIndex>(_data[Offset::DeviceIndex]);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> rawReport () const { return _data; }
|
||||
|
||||
private:
|
||||
static constexpr std::size_t HeaderLength = 4;
|
||||
std::vector<uint8_t> _data;
|
||||
|
24
src/logid/backend/hidpp/defs.h
Normal file
24
src/logid/backend/hidpp/defs.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef LOGID_HIDPP_DEFS_H
|
||||
#define LOGID_HIDPP_DEFS_H
|
||||
|
||||
#define LOGID_HIDPP_SOFTWARE_ID 1
|
||||
|
||||
namespace logid::backend::hidpp
|
||||
{
|
||||
enum DeviceIndex: uint8_t
|
||||
{
|
||||
DefaultDevice = 0,
|
||||
WirelessDevice1 = 1,
|
||||
WirelessDevice2 = 2,
|
||||
WirelessDevice3 = 3,
|
||||
WirelessDevice4 = 4,
|
||||
WirelessDevice5 = 5,
|
||||
WirelessDevice6 = 6,
|
||||
CordedDevice = 0xff
|
||||
};
|
||||
|
||||
static constexpr std::size_t ShortParamLength = 3;
|
||||
static constexpr std::size_t LongParamLength = 16;
|
||||
}
|
||||
|
||||
#endif //LOGID_HIDPP_DEFS_H
|
Reference in New Issue
Block a user