parent
47db60fad8
commit
b41649b0de
18 changed files with 819 additions and 26 deletions
@ -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(); |
||||
} |
||||
} |
@ -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
|
@ -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(); |
||||
} |
@ -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
|
@ -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()); |
||||
} |
||||
|
||||
|
||||
|
@ -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
|
@ -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
|
Loading…
Reference in new issue