Implement dj::Receiver class
Again, many things were done here.
This commit is contained in:
parent
47db60fad8
commit
b41649b0de
|
@ -15,9 +15,12 @@ add_executable(logid
|
|||
backend/Error.cpp
|
||||
backend/raw/DeviceMonitor.cpp
|
||||
backend/raw/RawDevice.cpp
|
||||
backend/dj/Receiver.cpp
|
||||
backend/dj/Error.cpp
|
||||
backend/hidpp/Device.cpp
|
||||
backend/hidpp/Report.cpp
|
||||
backend/hidpp10/Error.cpp
|
||||
backend/hidpp10/Device.cpp
|
||||
backend/hidpp20/Device.cpp
|
||||
backend/hidpp20/Error.cpp
|
||||
backend/hidpp20/Feature.cpp
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "DeviceMonitor.h"
|
||||
#include "util.h"
|
||||
#include "backend/hidpp10/Error.h"
|
||||
#include "backend/dj/Receiver.h"
|
||||
|
||||
#define NON_WIRELESS_DEV(index) (index) == HIDPP::DefaultDevice ? "default" : "corded"
|
||||
|
||||
|
@ -103,12 +104,26 @@ void DeviceMonitor::stopAndDeleteDevice (const std::string &path, HIDPP::DeviceI
|
|||
void DeviceMonitor::addDevice(std::string path)
|
||||
{
|
||||
try {
|
||||
auto device = std::make_shared<backend::hidpp::Device>(path, hidpp::DeviceIndex::WirelessDevice1);
|
||||
log_printf(DEBUG, "Detected HID++ device at %s", path.c_str());
|
||||
std::tuple<uint8_t, uint8_t> version;
|
||||
try
|
||||
{
|
||||
hidpp::Device device(path, hidpp::DefaultDevice);
|
||||
|
||||
auto version = device->version();
|
||||
log_printf(DEBUG, "HID++ version: %d.%d", std::get<0>(version), std::get<1>(version));
|
||||
log_printf(DEBUG, "Detected HID++ device at %s", path.c_str());
|
||||
|
||||
version = device.version();
|
||||
log_printf(DEBUG, "HID++ version: %d.%d", std::get<0>(version), std::get<1>(version));
|
||||
} catch(std::system_error &e) { }
|
||||
|
||||
if(version == std::make_tuple(1, 0))
|
||||
{
|
||||
// This is a receiver
|
||||
dj::Receiver receiver(path);
|
||||
receiver.enumerate();
|
||||
receiver.listen();
|
||||
while(true) {}
|
||||
}
|
||||
/*
|
||||
auto eventHandler = std::make_shared<backend::hidpp::EventHandler>();
|
||||
eventHandler->condition = [device](backend::hidpp::Report& report)->bool
|
||||
{
|
||||
|
@ -125,9 +140,9 @@ void DeviceMonitor::addDevice(std::string path)
|
|||
|
||||
device->addEventHandler("MONITOR_ALL", eventHandler);
|
||||
|
||||
devices.push_back(device);
|
||||
devices.push_back(device);*/
|
||||
|
||||
std::thread([device]() { device->listen(); }).detach();
|
||||
//std::thread([device]() { device->listen(); }).detach();
|
||||
}
|
||||
catch(hidpp10::Error &e)
|
||||
{
|
||||
|
@ -139,10 +154,11 @@ void DeviceMonitor::addDevice(std::string path)
|
|||
{
|
||||
log_printf(DEBUG, "Detected device at %s but %s", path.c_str(), e.what());
|
||||
}
|
||||
/*
|
||||
catch(std::system_error &e)
|
||||
{
|
||||
log_printf(WARN, "Failed to open %s: %s", path.c_str(), e.what());
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
void DeviceMonitor::removeDevice(std::string path)
|
||||
|
|
21
src/logid/backend/dj/Error.cpp
Normal file
21
src/logid/backend/dj/Error.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "Error.h"
|
||||
|
||||
using namespace logid::backend::dj;
|
||||
|
||||
Error::Error(uint8_t code) : _code (code)
|
||||
{
|
||||
}
|
||||
|
||||
const char* Error::what() const noexcept
|
||||
{
|
||||
switch(_code)
|
||||
{
|
||||
case Unknown:
|
||||
return "Unknown";
|
||||
case KeepAliveTimeout:
|
||||
return "Keep-alive timeout";
|
||||
default:
|
||||
return std::string("Reserved error code " + std::to_string(_code))
|
||||
.c_str();
|
||||
}
|
||||
}
|
30
src/logid/backend/dj/Error.h
Normal file
30
src/logid/backend/dj/Error.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef LOGID_HIDPP_BACKEND_DJ_ERROR_H
|
||||
#define LOGID_HIDPP_BACKEND_DJ_ERROR_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace logid {
|
||||
namespace backend {
|
||||
namespace dj
|
||||
{
|
||||
class Error : public std::exception
|
||||
{
|
||||
public:
|
||||
enum ErrorCode : uint8_t
|
||||
{
|
||||
Unknown = 0x00,
|
||||
KeepAliveTimeout = 0x01
|
||||
};
|
||||
|
||||
Error(uint8_t code);
|
||||
|
||||
virtual const char* what() const noexcept;
|
||||
uint8_t code() const noexcept;
|
||||
|
||||
private:
|
||||
uint8_t _code;
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif //LOGID_HIDPP_BACKEND_DJ_ERROR_H
|
255
src/logid/backend/dj/Receiver.cpp
Normal file
255
src/logid/backend/dj/Receiver.cpp
Normal file
|
@ -0,0 +1,255 @@
|
|||
#include <cassert>
|
||||
#include "Report.h"
|
||||
#include "Receiver.h"
|
||||
#include "Error.h"
|
||||
|
||||
using namespace logid::backend::dj;
|
||||
using namespace logid::backend;
|
||||
|
||||
InvalidReceiver::InvalidReceiver(Reason reason) : _reason (reason)
|
||||
{
|
||||
}
|
||||
|
||||
const char* InvalidReceiver::what() const noexcept
|
||||
{
|
||||
return "Invalid receiver";
|
||||
}
|
||||
|
||||
InvalidReceiver::Reason InvalidReceiver::code() const noexcept
|
||||
{
|
||||
return _reason;
|
||||
}
|
||||
|
||||
Receiver::Receiver(std::string path) :
|
||||
raw_device (std::make_shared<raw::RawDevice>(path)),
|
||||
_hidpp10_device (raw_device, hidpp::DefaultDevice)
|
||||
{
|
||||
if(!supportsDjReports(raw_device->reportDescriptor()))
|
||||
throw InvalidReceiver(InvalidReceiver::NoDJReports);
|
||||
|
||||
|
||||
// Pass all HID++ events on DefaultDevice to handleHidppEvent
|
||||
RawEventHandler hidppRawEventHandler;
|
||||
hidppRawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
|
||||
report[hidpp::Offset::Type] == hidpp::Report::Type::Long) &&
|
||||
(report[hidpp::Offset::DeviceIndex] == hidpp::DefaultDevice);
|
||||
};
|
||||
hidppRawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
hidpp::Report _report(report);
|
||||
this->handleHidppEvent(_report);
|
||||
};
|
||||
|
||||
// Pass all DJ events with device index to handleHidppEvent
|
||||
RawEventHandler djRawEventHandler;
|
||||
djRawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[Offset::Type] == Report::Type::Short ||
|
||||
report[Offset::Type] == Report::Type::Long);
|
||||
};
|
||||
djRawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
Report _report(report);
|
||||
this->handleDjEvent(_report);
|
||||
};
|
||||
|
||||
raw_device->addEventHandler("RECV_HIDPP", hidppRawEventHandler);
|
||||
raw_device->addEventHandler("RECV_DJ", djRawEventHandler);
|
||||
}
|
||||
|
||||
void Receiver::enumerate()
|
||||
{
|
||||
sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
|
||||
}
|
||||
|
||||
Receiver::notification_flags Receiver::getHidppNotifications()
|
||||
{
|
||||
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {});
|
||||
|
||||
notification_flags flags{};
|
||||
|
||||
flags.device_battery_status = response[0] & (1 << 4);
|
||||
flags.receiver_wireless_notifications = response[1] & (1 << 0);
|
||||
flags.receiver_software_present = response[1] & (1 << 3);
|
||||
}
|
||||
|
||||
void Receiver::enableHidppNotifications(notification_flags flags)
|
||||
{
|
||||
std::vector<uint8_t> request(3);
|
||||
|
||||
if(flags.device_battery_status)
|
||||
request[0] |= (1 << 4);
|
||||
if(flags.receiver_wireless_notifications)
|
||||
request[1] |= (1 << 0);
|
||||
if(flags.receiver_software_present)
|
||||
request[1] |= (1 << 3);
|
||||
|
||||
_hidpp10_device.setRegister(EnableHidppNotifications, request);
|
||||
}
|
||||
|
||||
///TODO: Investigate usage
|
||||
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
|
||||
{
|
||||
auto response = _hidpp10_device.setRegister(ConnectionState, {index});
|
||||
|
||||
return response[0];
|
||||
}
|
||||
|
||||
void Receiver::startPairing(uint8_t timeout)
|
||||
{
|
||||
///TODO: Device number == Device index?
|
||||
std::vector<uint8_t> request(3);
|
||||
|
||||
request[0] = 1;
|
||||
request[1] = hidpp::DefaultDevice;
|
||||
request[2] = timeout;
|
||||
|
||||
_hidpp10_device.setRegister(DevicePairing, request);
|
||||
}
|
||||
|
||||
void Receiver::stopPairing()
|
||||
{
|
||||
///TODO: Device number == Device index?
|
||||
std::vector<uint8_t> request(3);
|
||||
|
||||
request[0] = 2;
|
||||
request[1] = hidpp::DefaultDevice;
|
||||
|
||||
_hidpp10_device.setRegister(DevicePairing, request);
|
||||
}
|
||||
|
||||
void Receiver::disconnect(hidpp::DeviceIndex index)
|
||||
{
|
||||
///TODO: Device number == Device index?
|
||||
std::vector<uint8_t> request(3);
|
||||
|
||||
request[0] = 3;
|
||||
request[1] = index;
|
||||
|
||||
_hidpp10_device.setRegister(DevicePairing, request);
|
||||
}
|
||||
|
||||
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
|
||||
{
|
||||
auto response = _hidpp10_device.getRegister(DeviceActivity, {});
|
||||
|
||||
std::map<hidpp::DeviceIndex, uint8_t> device_activity;
|
||||
for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
|
||||
device_activity[static_cast<hidpp::DeviceIndex>(i)] = response[i];
|
||||
|
||||
return device_activity;
|
||||
}
|
||||
|
||||
Receiver::pairing_info Receiver::getPairingInfo(hidpp::DeviceIndex index)
|
||||
{
|
||||
std::vector<uint8_t> request(1);
|
||||
request[0] = index;
|
||||
request[0] += 0x19;
|
||||
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
||||
|
||||
pairing_info info{};
|
||||
info.destination_id = response[0];
|
||||
info.report_interval = response[1];
|
||||
info.pid = response[2];
|
||||
info.pid |= (response[3] << 8);
|
||||
info.device_type = response[6];
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Receiver::extended_pairing_info
|
||||
Receiver::getExtendedPairingInfo(hidpp::DeviceIndex index)
|
||||
{
|
||||
std::vector<uint8_t> request(1);
|
||||
request[0] = index;
|
||||
request[0] += 0x29;
|
||||
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
||||
|
||||
extended_pairing_info info{};
|
||||
|
||||
info.serial_number = 0;
|
||||
for(uint8_t i = 0; i < 4; i++)
|
||||
info.serial_number |= (response[i] << 8*i);
|
||||
|
||||
for(uint8_t i = 0; i < 4; i++)
|
||||
info.report_types[i] = response[i + 4];
|
||||
|
||||
info.power_switch_location = response[8] & 0xf;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::string Receiver::getDeviceName(hidpp::DeviceIndex index)
|
||||
{
|
||||
std::vector<uint8_t> request(1);
|
||||
request[0] = index;
|
||||
request[0] += 0x39;
|
||||
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
||||
|
||||
uint8_t size = response[0];
|
||||
assert(size <= 14);
|
||||
|
||||
std::string name(size, ' ');
|
||||
for(std::size_t i = 0; i < size; i++)
|
||||
name[i] = response[i + 1];
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
hidpp::DeviceIndex Receiver::deviceConnectionEvent(hidpp::Report &report)
|
||||
{
|
||||
assert(report.subId() == DeviceConnection);
|
||||
return report.deviceIndex();
|
||||
}
|
||||
|
||||
hidpp::DeviceIndex Receiver::deviceDisconnectionEvent(hidpp::Report& report)
|
||||
{
|
||||
assert(report.subId() == DeviceDisconnection);
|
||||
return report.deviceIndex();
|
||||
}
|
||||
|
||||
void Receiver::handleDjEvent(Report& report)
|
||||
{
|
||||
if(report.feature() == DeviceConnection ||
|
||||
report.feature() == DeviceDisconnection ||
|
||||
report.feature() == ConnectionStatus)
|
||||
{
|
||||
printf("%s DJ IN: ", raw_device->hidrawPath().c_str());
|
||||
for(auto &i: report.rawData())
|
||||
printf("%02x ", i);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Receiver::handleHidppEvent(hidpp::Report &report)
|
||||
{
|
||||
printf("%s HID++ IN: ", raw_device->hidrawPath().c_str());
|
||||
for(auto &i: report.rawReport())
|
||||
printf("%02x ", i);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
|
||||
const std::vector<uint8_t>&& params)
|
||||
{
|
||||
assert(params.size() <= LongParamLength);
|
||||
|
||||
Report::Type type = params.size() <= ShortParamLength ?
|
||||
ReportType::Short : ReportType::Long;
|
||||
|
||||
Report request(type, index, function);
|
||||
|
||||
std::copy(params.begin(), params.end(), request.paramBegin());
|
||||
|
||||
raw_device->sendReportNoResponse(request.rawData());
|
||||
}
|
||||
|
||||
void Receiver::listen()
|
||||
{
|
||||
std::thread{[=]() { raw_device->listen(); }}.detach();
|
||||
}
|
125
src/logid/backend/dj/Receiver.h
Normal file
125
src/logid/backend/dj/Receiver.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
#ifndef LOGID_BACKEND_DJ_RECEIVER_H
|
||||
#define LOGID_BACKEND_DJ_RECEIVER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "../raw/RawDevice.h"
|
||||
#include "Report.h"
|
||||
#include "../hidpp/Report.h"
|
||||
#include "../hidpp10/Device.h"
|
||||
|
||||
namespace logid {
|
||||
namespace backend {
|
||||
namespace dj
|
||||
{
|
||||
class InvalidReceiver : public std::exception
|
||||
{
|
||||
public:
|
||||
enum Reason
|
||||
{
|
||||
NoDJReports
|
||||
};
|
||||
explicit InvalidReceiver(Reason reason);
|
||||
virtual const char* what() const noexcept;
|
||||
Reason code() const noexcept;
|
||||
private:
|
||||
Reason _reason;
|
||||
};
|
||||
|
||||
class Receiver
|
||||
{
|
||||
public:
|
||||
explicit Receiver(std::string path);
|
||||
|
||||
enum DjEvents : uint8_t
|
||||
{
|
||||
DeviceDisconnection = 0x40,
|
||||
DeviceConnection = 0x41,
|
||||
ConnectionStatus = 0x42
|
||||
};
|
||||
|
||||
enum DjCommands : uint8_t
|
||||
{
|
||||
SwitchAndKeepAlive = 0x80,
|
||||
GetPairedDevices = 0x81
|
||||
};
|
||||
|
||||
void enumerate();
|
||||
|
||||
/* The following functions deal with HID++ 1.0 features.
|
||||
* While these are not technically DJ functions, it is redundant
|
||||
* to have a separate hidpp10::Receiver class for these functions.
|
||||
*/
|
||||
|
||||
enum HidppEvents : uint8_t
|
||||
{
|
||||
// These events are identical to their DJ counterparts
|
||||
// DeviceDisconnection = 0x40,
|
||||
// DeviceConnection = 0x41,
|
||||
LockingChange = 0x4a
|
||||
};
|
||||
|
||||
enum HidppRegisters : uint8_t
|
||||
{
|
||||
EnableHidppNotifications = 0x00,
|
||||
ConnectionState = 0x02,
|
||||
DevicePairing = 0xb2,
|
||||
DeviceActivity = 0xb3,
|
||||
PairingInfo = 0xb5
|
||||
};
|
||||
|
||||
struct notification_flags
|
||||
{
|
||||
bool device_battery_status;
|
||||
bool receiver_wireless_notifications;
|
||||
bool receiver_software_present;
|
||||
};
|
||||
|
||||
notification_flags getHidppNotifications();
|
||||
void enableHidppNotifications(notification_flags flags);
|
||||
|
||||
///TODO: Understand output of this function
|
||||
uint8_t getConnectionState(hidpp::DeviceIndex index);
|
||||
|
||||
void startPairing(uint8_t timeout = 0);
|
||||
void stopPairing();
|
||||
void disconnect(hidpp::DeviceIndex index);
|
||||
|
||||
std::map<hidpp::DeviceIndex, uint8_t> getDeviceActivity();
|
||||
|
||||
struct pairing_info
|
||||
{
|
||||
uint8_t destination_id;
|
||||
uint8_t report_interval;
|
||||
uint16_t pid;
|
||||
uint8_t device_type; ///TODO: Create enum for DeviceType
|
||||
};
|
||||
|
||||
struct extended_pairing_info
|
||||
{
|
||||
uint32_t serial_number;
|
||||
uint8_t report_types[4];
|
||||
uint8_t power_switch_location; ///TODO: Create enum
|
||||
};
|
||||
|
||||
pairing_info getPairingInfo(hidpp::DeviceIndex index);
|
||||
extended_pairing_info getExtendedPairingInfo(hidpp::DeviceIndex index);
|
||||
|
||||
std::string getDeviceName(hidpp::DeviceIndex index);
|
||||
|
||||
hidpp::DeviceIndex deviceConnectionEvent(hidpp::Report& report);
|
||||
hidpp::DeviceIndex deviceDisconnectionEvent(hidpp::Report& report);
|
||||
|
||||
void handleDjEvent(dj::Report& report);
|
||||
void handleHidppEvent(hidpp::Report& report);
|
||||
|
||||
void listen();
|
||||
private:
|
||||
void sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
|
||||
const std::vector<uint8_t>&& params);
|
||||
|
||||
std::shared_ptr<raw::RawDevice> raw_device;
|
||||
hidpp10::Device _hidpp10_device;
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif //LOGID_BACKEND_DJ_RECEIVER_H
|
|
@ -1,11 +1,12 @@
|
|||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include "Report.h"
|
||||
|
||||
using namespace logid::backend::dj;
|
||||
using namespace logid::backend;
|
||||
|
||||
static const std::array<uint8_t, 35> DJReportDesc = {
|
||||
static const std::array<uint8_t, 34> DJReportDesc = {
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x20, // Report ID (32)
|
||||
0x95, 0x0E, // Report Count (14)
|
||||
|
@ -25,8 +26,68 @@ static const std::array<uint8_t, 35> DJReportDesc = {
|
|||
0xC0 // End Collection
|
||||
};
|
||||
|
||||
bool dj::supportsDjReports(std::vector<uint8_t>& rdesc)
|
||||
bool dj::supportsDjReports(std::vector<uint8_t>&& rdesc)
|
||||
{
|
||||
auto it = std::search(rdesc.begin(), rdesc.end(), DJReportDesc.begin(), DJReportDesc.end());
|
||||
return it != rdesc.end();
|
||||
}
|
||||
}
|
||||
|
||||
Report::Report(std::vector<uint8_t>& data) : _data (data)
|
||||
{
|
||||
switch(data[Offset::Type])
|
||||
{
|
||||
case ReportType::Short:
|
||||
_data.resize(HeaderLength+ShortParamLength);
|
||||
break;
|
||||
case ReportType::Long:
|
||||
_data.resize(HeaderLength+LongParamLength);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
Report::Report(Report::Type type, hidpp::DeviceIndex index, uint8_t feature)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ReportType::Short:
|
||||
_data.resize(HeaderLength+ShortParamLength);
|
||||
break;
|
||||
case ReportType::Long:
|
||||
_data.resize(HeaderLength+LongParamLength);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
_data[Offset::Type] = type;
|
||||
_data[Offset::DeviceIndex] = index;
|
||||
_data[Offset::Feature] = feature;
|
||||
}
|
||||
|
||||
|
||||
Report::Type Report::type() const
|
||||
{
|
||||
return static_cast<Type>(_data[Offset::Type]);
|
||||
}
|
||||
|
||||
hidpp::DeviceIndex Report::index() const
|
||||
{
|
||||
return static_cast<hidpp::DeviceIndex>(_data[Offset::DeviceIndex]);
|
||||
}
|
||||
|
||||
uint8_t Report::feature() const
|
||||
{
|
||||
return _data[Offset::Feature];
|
||||
}
|
||||
|
||||
std::vector<uint8_t>::iterator Report::paramBegin()
|
||||
{
|
||||
return _data.begin() + Offset::Parameters;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Report::rawData() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
|
|
@ -3,17 +3,35 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include "../raw/RawDevice.h"
|
||||
#include "defs.h"
|
||||
#include "../hidpp/defs.h"
|
||||
|
||||
namespace logid::backend::dj
|
||||
{
|
||||
bool supportsDjReports(std::vector<uint8_t>& rawDevice);
|
||||
namespace Offset
|
||||
{
|
||||
static constexpr uint8_t Type = 0;
|
||||
static constexpr uint8_t DeviceIndex = 1;
|
||||
static constexpr uint8_t Feature = 2;
|
||||
static constexpr uint8_t Parameters = 3;
|
||||
}
|
||||
|
||||
bool supportsDjReports(std::vector<uint8_t>&& rdesc);
|
||||
class Report
|
||||
{
|
||||
enum Type: uint8_t
|
||||
{
|
||||
Short = 0x20, // Short DJ reports use 12 byte parameters
|
||||
Long = 0x21 // Long DJ reports use 29 byte parameters
|
||||
};
|
||||
public:
|
||||
typedef ReportType::ReportType Type;
|
||||
|
||||
explicit Report(std::vector<uint8_t>& data);
|
||||
Report(Type type, hidpp::DeviceIndex index, uint8_t feature);
|
||||
|
||||
Type type() const;
|
||||
hidpp::DeviceIndex index() const;
|
||||
uint8_t feature() const;
|
||||
std::vector<uint8_t>::iterator paramBegin();
|
||||
std::vector<uint8_t> rawData() const;
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@ namespace dj
|
|||
Long = 0x21
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr uint8_t ErrorFeature = 0x7f;
|
||||
|
||||
static constexpr std::size_t HeaderLength = 3;
|
||||
static constexpr std::size_t ShortParamLength = 12;
|
||||
static constexpr std::size_t LongParamLength = 29;
|
||||
}}}
|
||||
|
||||
#endif //LOGID_BACKEND_DJ_DEFS_H
|
|
@ -26,7 +26,19 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
|
|||
|
||||
/// TODO: Initialize a single RawDevice for each path.
|
||||
Device::Device(const std::string& path, DeviceIndex index):
|
||||
raw_device (std::make_shared<raw::RawDevice>(path)), path (path), index (index)
|
||||
raw_device (std::make_shared<raw::RawDevice>(path)), path (path),
|
||||
_index (index)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index) :
|
||||
raw_device (raw_device), _index (index)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
void Device::_init()
|
||||
{
|
||||
supported_reports = getSupportedReports(raw_device->reportDescriptor());
|
||||
if(!supported_reports)
|
||||
|
@ -34,8 +46,9 @@ Device::Device(const std::string& path, DeviceIndex index):
|
|||
|
||||
try
|
||||
{
|
||||
Report versionRequest(Report::Type::Short, index, hidpp20::FeatureID::ROOT,
|
||||
hidpp20::Root::Ping, LOGID_HIDPP_SOFTWARE_ID);
|
||||
Report versionRequest(Report::Type::Short, _index,
|
||||
hidpp20::FeatureID::ROOT,hidpp20::Root::Ping,
|
||||
LOGID_HIDPP_SOFTWARE_ID);
|
||||
|
||||
auto versionResponse = sendReport(versionRequest);
|
||||
auto versionResponse_params = versionResponse.paramBegin();
|
||||
|
@ -53,10 +66,11 @@ Device::Device(const std::string& path, DeviceIndex index):
|
|||
|
||||
// Pass all HID++ events with device index to this device.
|
||||
RawEventHandler rawEventHandler;
|
||||
rawEventHandler.condition = [index](std::vector<uint8_t>& report)->bool
|
||||
rawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[Offset::Type] == Report::Type::Short ||
|
||||
report[Offset::Type] == Report::Type::Long) && (report[Offset::DeviceIndex] == index);
|
||||
report[Offset::Type] == Report::Type::Long) &&
|
||||
(report[Offset::DeviceIndex] == this->_index);
|
||||
};
|
||||
rawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
|
@ -64,7 +78,15 @@ Device::Device(const std::string& path, DeviceIndex index):
|
|||
this->handleEvent(_report);
|
||||
};
|
||||
|
||||
raw_device->addEventHandler("DEV_" + std::to_string(index), rawEventHandler);
|
||||
raw_device->addEventHandler("DEV_" + std::to_string(_index), rawEventHandler);
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
raw_device->removeEventHandler("DEV_" + std::to_string(_index));
|
||||
///TODO: tmp
|
||||
raw_device->stopListener();
|
||||
raw_device.reset();
|
||||
}
|
||||
|
||||
void Device::addEventHandler(const std::string& nickname, const std::shared_ptr<EventHandler>& handler)
|
||||
|
|
|
@ -37,9 +37,11 @@ namespace hidpp
|
|||
};
|
||||
|
||||
Device(const std::string& path, DeviceIndex index);
|
||||
Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index);
|
||||
~Device();
|
||||
|
||||
std::string devicePath() const { return path; }
|
||||
DeviceIndex deviceIndex() const { return index; }
|
||||
DeviceIndex deviceIndex() const { return _index; }
|
||||
std::tuple<uint8_t, uint8_t> version() const { return _version; }
|
||||
|
||||
void listen(); // Runs asynchronously
|
||||
|
@ -52,9 +54,11 @@ namespace hidpp
|
|||
|
||||
void handleEvent(Report& report);
|
||||
private:
|
||||
void _init();
|
||||
|
||||
std::shared_ptr<raw::RawDevice> raw_device;
|
||||
std::string path;
|
||||
DeviceIndex index;
|
||||
DeviceIndex _index;
|
||||
uint8_t supported_reports;
|
||||
|
||||
std::tuple<uint8_t, uint8_t> _version;
|
||||
|
|
|
@ -95,6 +95,27 @@ const char *Report::InvalidReportLength::what() const noexcept
|
|||
return "Invalid report length";
|
||||
}
|
||||
|
||||
Report::Report(Report::Type type, DeviceIndex device_index,
|
||||
uint8_t sub_id, uint8_t address)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Type::Short:
|
||||
_data.resize(HeaderLength + ShortParamLength);
|
||||
break;
|
||||
case Type::Long:
|
||||
_data.resize(HeaderLength + LongParamLength);
|
||||
break;
|
||||
default:
|
||||
throw InvalidReportID();
|
||||
}
|
||||
|
||||
_data[Offset::Type] = type;
|
||||
_data[Offset::DeviceIndex] = device_index;
|
||||
_data[Offset::SubID] = sub_id;
|
||||
_data[Offset::Address] = address;
|
||||
}
|
||||
|
||||
Report::Report(Report::Type type, DeviceIndex device_index,
|
||||
uint8_t feature_index, uint8_t function, uint8_t sw_id)
|
||||
{
|
||||
|
@ -123,6 +144,7 @@ Report::Report(const std::vector<uint8_t>& data)
|
|||
{
|
||||
_data = data;
|
||||
|
||||
// Truncating data is entirely valid here.
|
||||
switch(_data[Offset::Type])
|
||||
{
|
||||
case Type::Short:
|
||||
|
@ -136,6 +158,11 @@ Report::Report(const std::vector<uint8_t>& data)
|
|||
}
|
||||
}
|
||||
|
||||
Report::Type Report::type() const
|
||||
{
|
||||
return static_cast<Report::Type>(_data[Offset::Type]);
|
||||
}
|
||||
|
||||
void Report::setType(Report::Type type)
|
||||
{
|
||||
switch(type)
|
||||
|
@ -153,6 +180,58 @@ void Report::setType(Report::Type type)
|
|||
_data[Offset::Type] = type;
|
||||
}
|
||||
|
||||
uint8_t Report::feature() const
|
||||
{
|
||||
return _data[Offset::Feature];
|
||||
}
|
||||
|
||||
void Report::setFeature(uint8_t feature)
|
||||
{
|
||||
_data[Offset::Parameters] = feature;
|
||||
}
|
||||
|
||||
uint8_t Report::subId() const
|
||||
{
|
||||
return _data[Offset::SubID];
|
||||
}
|
||||
|
||||
void Report::setSubId(uint8_t sub_id)
|
||||
{
|
||||
_data[Offset::SubID] = sub_id;
|
||||
}
|
||||
|
||||
uint8_t Report::function() const
|
||||
{
|
||||
return (_data[Offset::Function] >> 4) & 0x0f;
|
||||
}
|
||||
|
||||
void Report::setFunction(uint8_t function)
|
||||
{
|
||||
_data[Offset::Function] &= 0x0f;
|
||||
_data[Offset::Function] |= (function << 4) & 0x0f;
|
||||
}
|
||||
|
||||
uint8_t Report::swId() const
|
||||
{
|
||||
return _data[Offset::Function] & 0x0f;
|
||||
}
|
||||
|
||||
void Report::setSwId(uint8_t sub_id)
|
||||
{
|
||||
_data[Offset::Function] &= 0x0f;
|
||||
_data[Offset::Function] |= sub_id & 0x0f;
|
||||
}
|
||||
|
||||
uint8_t Report::address() const
|
||||
{
|
||||
return _data[Offset::Address];
|
||||
}
|
||||
|
||||
void Report::setAddress(uint8_t address)
|
||||
{
|
||||
_data[Offset::Address] = address;
|
||||
}
|
||||
|
||||
void Report::setParams(const std::vector<uint8_t>& _params)
|
||||
{
|
||||
assert(_params.size() <= _data.size()-HeaderLength);
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace logid::backend::hidpp
|
|||
static constexpr uint8_t DeviceIndex = 1;
|
||||
static constexpr uint8_t SubID = 2;
|
||||
static constexpr uint8_t Feature = 2;
|
||||
static constexpr uint8_t Address = 3;
|
||||
static constexpr uint8_t Function = 3;
|
||||
static constexpr uint8_t Parameters = 4;
|
||||
}
|
||||
|
@ -47,16 +48,37 @@ namespace logid::backend::hidpp
|
|||
static constexpr uint8_t swIdMask = 0x0f;
|
||||
static constexpr uint8_t functionMask = 0x0f;
|
||||
|
||||
Report(Report::Type type, DeviceIndex device_index,
|
||||
uint8_t sub_id,
|
||||
uint8_t address);
|
||||
Report(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);
|
||||
|
||||
Report::Type type() const { return static_cast<Report::Type>(_data[Offset::Type]); };
|
||||
Report::Type type() const;
|
||||
void setType(Report::Type type);
|
||||
|
||||
std::vector<uint8_t>::iterator paramBegin() { return _data.begin() + Offset::Parameters; }
|
||||
uint8_t feature() const;
|
||||
void setFeature(uint8_t feature);
|
||||
|
||||
uint8_t subId() const;
|
||||
void setSubId(uint8_t sub_id);
|
||||
|
||||
uint8_t function() const;
|
||||
void setFunction(uint8_t function);
|
||||
|
||||
uint8_t swId() const;
|
||||
void setSwId(uint8_t sw_id);
|
||||
|
||||
uint8_t address() const;
|
||||
void setAddress(uint8_t address);
|
||||
|
||||
std::vector<uint8_t>::iterator paramBegin()
|
||||
{
|
||||
return _data.begin() + Offset::Parameters;
|
||||
}
|
||||
std::vector<uint8_t>::iterator paramEnd() { return _data.end(); }
|
||||
void setParams(const std::vector<uint8_t>& _params);
|
||||
|
||||
|
|
62
src/logid/backend/hidpp10/Device.cpp
Normal file
62
src/logid/backend/hidpp10/Device.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "Device.h"
|
||||
#include "defs.h"
|
||||
|
||||
using namespace logid::backend;
|
||||
using namespace logid::backend::hidpp10;
|
||||
|
||||
Device::Device(const std::string &path, hidpp::DeviceIndex index) :
|
||||
hidpp::Device(path, index)
|
||||
{
|
||||
assert(version() == std::make_tuple(1, 0));
|
||||
}
|
||||
|
||||
Device::Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
||||
hidpp::DeviceIndex index) : hidpp::Device(std::move(raw_dev), index)
|
||||
{
|
||||
assert(version() == std::make_tuple(1, 0));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Device::getRegister(uint8_t address,
|
||||
const std::vector<uint8_t>& params)
|
||||
{
|
||||
assert(params.size() <= hidpp::LongParamLength);
|
||||
|
||||
hidpp::Report::Type type = params.size() <= hidpp::ShortParamLength ?
|
||||
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
|
||||
|
||||
uint8_t sub_id = type == hidpp::Report::Type::Short ?
|
||||
GetRegisterShort : GetRegisterLong;
|
||||
|
||||
return accessRegister(sub_id, address, params);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Device::setRegister(uint8_t address,
|
||||
const std::vector<uint8_t>& params)
|
||||
{
|
||||
assert(params.size() <= hidpp::LongParamLength);
|
||||
|
||||
hidpp::Report::Type type = params.size() <= hidpp::ShortParamLength ?
|
||||
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
|
||||
|
||||
uint8_t sub_id = type == hidpp::Report::Type::Short ?
|
||||
SetRegisterShort : SetRegisterLong;
|
||||
|
||||
return accessRegister(sub_id, address, params);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Device::accessRegister(uint8_t sub_id, uint8_t address, const std::vector<uint8_t> ¶ms)
|
||||
{
|
||||
hidpp::Report::Type type = params.size() <= hidpp::ShortParamLength ?
|
||||
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
|
||||
|
||||
hidpp::Report request(type, deviceIndex(), sub_id, address);
|
||||
std::copy(params.begin(), params.end(), request.paramBegin());
|
||||
|
||||
auto response = sendReport(request);
|
||||
return std::vector<uint8_t>(response.paramBegin(), response.paramEnd());
|
||||
}
|
||||
|
||||
|
||||
|
28
src/logid/backend/hidpp10/Device.h
Normal file
28
src/logid/backend/hidpp10/Device.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef LOGID_BACKEND_HIDPP10_DEVICE_H
|
||||
#define LOGID_BACKEND_HIDPP10_DEVICE_H
|
||||
|
||||
#include "../hidpp/Device.h"
|
||||
|
||||
namespace logid {
|
||||
namespace backend {
|
||||
namespace hidpp10
|
||||
{
|
||||
class Device : public hidpp::Device
|
||||
{
|
||||
public:
|
||||
Device(const std::string& path, hidpp::DeviceIndex index);
|
||||
Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
||||
hidpp::DeviceIndex index);
|
||||
|
||||
std::vector<uint8_t> getRegister(uint8_t address,
|
||||
const std::vector<uint8_t>& params);
|
||||
|
||||
std::vector<uint8_t> setRegister(uint8_t address,
|
||||
const std::vector<uint8_t>& params);
|
||||
private:
|
||||
std::vector<uint8_t> accessRegister(uint8_t sub_id,
|
||||
uint8_t address, const std::vector<uint8_t>& params);
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif //LOGID_BACKEND_HIDPP10_DEVICE_H
|
17
src/logid/backend/hidpp10/defs.h
Normal file
17
src/logid/backend/hidpp10/defs.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef LOGID_BACKEND_HIDPP10_DEFS_H
|
||||
#define LOGID_BACKEND_HIDPP10_DEFS_H
|
||||
|
||||
namespace logid {
|
||||
namespace backend {
|
||||
namespace hidpp10
|
||||
{
|
||||
enum SubID: uint8_t
|
||||
{
|
||||
SetRegisterShort = 0x80,
|
||||
GetRegisterShort = 0x81,
|
||||
SetRegisterLong = 0x82,
|
||||
GetRegisterLong = 0x83
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif //LOGID_BACKEND_HIDPP10_DEFS_H
|
|
@ -75,6 +75,8 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
|||
close(fd);
|
||||
throw std::system_error(err, std::system_category(), "RawDevice pipe open failed");
|
||||
}
|
||||
|
||||
continue_listen = false;
|
||||
}
|
||||
|
||||
RawDevice::~RawDevice()
|
||||
|
@ -106,6 +108,27 @@ std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
|
|||
return _respondToReport(report);
|
||||
}
|
||||
|
||||
// DJ commands are not systematically acknowledged, do not expect a result.
|
||||
void RawDevice::sendReportNoResponse(const std::vector<uint8_t>& report)
|
||||
{
|
||||
assert(supportedReportID(report[0]));
|
||||
|
||||
/* If the listener will stop, handle I/O manually.
|
||||
* Otherwise, push to queue and wait for result. */
|
||||
if(continue_listen)
|
||||
{
|
||||
std::packaged_task<std::vector<uint8_t>()> task([this, report]() {
|
||||
this->_sendReport(report);
|
||||
return std::vector<uint8_t>();
|
||||
});
|
||||
auto f = task.get_future();
|
||||
write_queue.push(&task);
|
||||
f.get();
|
||||
}
|
||||
else
|
||||
_sendReport(report);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> RawDevice::_respondToReport
|
||||
(const std::vector<uint8_t>& request)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace raw
|
|||
std::vector<uint8_t> reportDescriptor() const { return rdesc; }
|
||||
|
||||
std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
|
||||
void sendReportNoResponse(const std::vector<uint8_t>& report);
|
||||
void interruptRead();
|
||||
|
||||
void listen();
|
||||
|
|
Loading…
Reference in New Issue
Block a user