Implement receiver HID++ connect/disconnect events
Many changes were made here but that was the biggest one. There's currently a bug where std::system_error: Broken pipe is thrown after launching the daemon with a receiver connector. A workaround for this bug is to simply shake the mouse while starting the daemon. I will investigate this soon.
This commit is contained in:
		@@ -27,7 +27,9 @@ add_executable(logid
 | 
				
			|||||||
        backend/hidpp20/Device.cpp
 | 
					        backend/hidpp20/Device.cpp
 | 
				
			||||||
        backend/hidpp20/Error.cpp
 | 
					        backend/hidpp20/Error.cpp
 | 
				
			||||||
        backend/hidpp20/Feature.cpp
 | 
					        backend/hidpp20/Feature.cpp
 | 
				
			||||||
 | 
					        backend/hidpp20/EssentialFeature.cpp
 | 
				
			||||||
        backend/hidpp20/features/Root.cpp
 | 
					        backend/hidpp20/features/Root.cpp
 | 
				
			||||||
 | 
					        backend/hidpp20/features/DeviceName.cpp
 | 
				
			||||||
        backend/dj/Report.cpp
 | 
					        backend/dj/Report.cpp
 | 
				
			||||||
        util/mutex_queue.h)
 | 
					        util/mutex_queue.h)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
#include "Device.h"
 | 
					#include "Device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace logid;
 | 
					using namespace logid;
 | 
				
			||||||
 | 
					using namespace logid::backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
 | 
					Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
 | 
				
			||||||
    _hidpp20 (path, index), _path (path), _index (index)
 | 
					    _hidpp20 (path, index), _path (path), _index (index)
 | 
				
			||||||
@@ -9,6 +10,13 @@ Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
 | 
				
			|||||||
    log_printf(DEBUG, "logid::Device created on %s:%d", _path.c_str(), _index);
 | 
					    log_printf(DEBUG, "logid::Device created on %s:%d", _path.c_str(), _index);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Device::Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
 | 
				
			||||||
 | 
					        hidpp::DeviceIndex index) : _hidpp20(raw_device, index), _path
 | 
				
			||||||
 | 
					        (raw_device->hidrawPath()), _index (index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    log_printf(DEBUG, "logid::Device created on %s:%d", _path.c_str(), _index);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Device::sleep()
 | 
					void Device::sleep()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    log_printf(INFO, "%s:%d fell asleep.", _path.c_str(), _index);
 | 
					    log_printf(INFO, "%s:%d fell asleep.", _path.c_str(), _index);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,8 @@ namespace logid
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        Device(std::string path, backend::hidpp::DeviceIndex index);
 | 
					        Device(std::string path, backend::hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					        Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
 | 
				
			||||||
 | 
					                backend::hidpp::DeviceIndex index);
 | 
				
			||||||
        void wakeup();
 | 
					        void wakeup();
 | 
				
			||||||
        void sleep();
 | 
					        void sleep();
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ void DeviceManager::addDevice(std::string path)
 | 
				
			|||||||
    if(isReceiver) {
 | 
					    if(isReceiver) {
 | 
				
			||||||
        log_printf(INFO, "Detected receiver at %s", path.c_str());
 | 
					        log_printf(INFO, "Detected receiver at %s", path.c_str());
 | 
				
			||||||
        auto receiver = std::make_shared<Receiver>(path);
 | 
					        auto receiver = std::make_shared<Receiver>(path);
 | 
				
			||||||
 | 
					        receiver->run();
 | 
				
			||||||
        _receivers.emplace(path, receiver);
 | 
					        _receivers.emplace(path, receiver);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        /* TODO: Error check?
 | 
					        /* TODO: Error check?
 | 
				
			||||||
@@ -48,6 +49,9 @@ void DeviceManager::addDevice(std::string path)
 | 
				
			|||||||
            } catch(hidpp10::Error &e) {
 | 
					            } catch(hidpp10::Error &e) {
 | 
				
			||||||
                if(e.code() != hidpp10::Error::UnknownDevice)
 | 
					                if(e.code() != hidpp10::Error::UnknownDevice)
 | 
				
			||||||
                    throw;
 | 
					                    throw;
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    log_printf(WARN, "HID++ 1.0 error while trying to initialize"
 | 
				
			||||||
 | 
					                                     " %s: %s", path.c_str(), e.what());
 | 
				
			||||||
            } catch(hidpp::Device::InvalidDevice &e) { // Ignore
 | 
					            } catch(hidpp::Device::InvalidDevice &e) { // Ignore
 | 
				
			||||||
            } catch(std::system_error &e) {
 | 
					            } catch(std::system_error &e) {
 | 
				
			||||||
                // This error should have been thrown previously
 | 
					                // This error should have been thrown previously
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,50 @@
 | 
				
			|||||||
 | 
					#include <cassert>
 | 
				
			||||||
#include "Receiver.h"
 | 
					#include "Receiver.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					#include "backend/hidpp10/Error.h"
 | 
				
			||||||
 | 
					#include "backend/hidpp20/Error.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace logid;
 | 
					using namespace logid;
 | 
				
			||||||
 | 
					using namespace logid::backend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Receiver::Receiver(std::string path) : _path (path)
 | 
					Receiver::Receiver(std::string path) : dj::ReceiverMonitor(path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    log_printf(DEBUG, "logid::Receiver created on %s", path.c_str());
 | 
					    log_printf(DEBUG, "logid::Receiver created on %s", path.c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        if(!event.linkEstablished)
 | 
				
			||||||
 | 
					            return; // Device is probably asleep, wait until it wakes up
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hidpp::Device hidpp_device(receiver(), event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto version = hidpp_device.version();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(std::get<0>(version) < 2) {
 | 
				
			||||||
 | 
					            log_printf(INFO, "Unsupported HID++ 1.0 device on %s:%d connected.",
 | 
				
			||||||
 | 
					                    _path.c_str(), event.index);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::shared_ptr<Device> device = std::make_shared<Device>(
 | 
				
			||||||
 | 
					                receiver()->rawDevice(), event.index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(_devices.find(event.index) == _devices.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _devices.emplace(event.index, device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } catch(hidpp10::Error &e) {
 | 
				
			||||||
 | 
					        log_printf(ERROR, "Caught HID++ 1.0 error while trying to initialize "
 | 
				
			||||||
 | 
					                          "%s:%d: %s", _path.c_str(), event.index, e.what());
 | 
				
			||||||
 | 
					    } catch(hidpp20::Error &e) {
 | 
				
			||||||
 | 
					        log_printf(ERROR, "Caught HID++ 2.0 error while trying to initialize "
 | 
				
			||||||
 | 
					                          "%s:%d: %s", _path.c_str(), event.index, e.what());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::removeDevice(hidpp::DeviceIndex index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    _devices.erase(index);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,14 +2,21 @@
 | 
				
			|||||||
#define LOGID_RECEIVER_H
 | 
					#define LOGID_RECEIVER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include "backend/dj/ReceiverMonitor.h"
 | 
				
			||||||
 | 
					#include "Device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace logid
 | 
					namespace logid
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class Receiver
 | 
					    class Receiver : public backend::dj::ReceiverMonitor
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        Receiver(std::string path);
 | 
					        Receiver(std::string path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected:
 | 
				
			||||||
 | 
					        virtual void addDevice(backend::hidpp::DeviceConnectionEvent event);
 | 
				
			||||||
 | 
					        virtual void removeDevice(backend::hidpp::DeviceIndex index);
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
 | 
					        std::map<backend::hidpp::DeviceIndex, std::shared_ptr<Device>> _devices;
 | 
				
			||||||
        std::string _path;
 | 
					        std::string _path;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,47 +32,17 @@ Receiver::Receiver(std::string path) :
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    if(!supportsDjReports(raw_device->reportDescriptor()))
 | 
					    if(!supportsDjReports(raw_device->reportDescriptor()))
 | 
				
			||||||
        throw InvalidReceiver(InvalidReceiver::NoDJReports);
 | 
					        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()
 | 
					void Receiver::enumerateDj()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
 | 
					    sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Receiver::notification_flags Receiver::getHidppNotifications()
 | 
					Receiver::notification_flags Receiver::getHidppNotifications()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {});
 | 
					    auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {},
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    notification_flags flags{};
 | 
					    notification_flags flags{};
 | 
				
			||||||
    flags.device_battery_status = response[0] & (1 << 4);
 | 
					    flags.device_battery_status = response[0] & (1 << 4);
 | 
				
			||||||
@@ -89,17 +59,28 @@ void Receiver::enableHidppNotifications(notification_flags flags)
 | 
				
			|||||||
    if(flags.device_battery_status)
 | 
					    if(flags.device_battery_status)
 | 
				
			||||||
        request[0] |= (1 << 4);
 | 
					        request[0] |= (1 << 4);
 | 
				
			||||||
    if(flags.receiver_wireless_notifications)
 | 
					    if(flags.receiver_wireless_notifications)
 | 
				
			||||||
        request[1] |= (1 << 0);
 | 
					        request[1] |= 1;
 | 
				
			||||||
    if(flags.receiver_software_present)
 | 
					    if(flags.receiver_software_present)
 | 
				
			||||||
        request[1] |= (1 << 3);
 | 
					        request[1] |= (1 << 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _hidpp10_device.setRegister(EnableHidppNotifications, request);
 | 
					    _hidpp10_device.setRegister(EnableHidppNotifications, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::enumerateHidpp()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* This isn't in the documentation but this is how solaar does it
 | 
				
			||||||
 | 
					     * All I know is that when (p0 & 2), devices are enumerated
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    _hidpp10_device.setRegister(ConnectionState, {2},
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///TODO: Investigate usage
 | 
					///TODO: Investigate usage
 | 
				
			||||||
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
 | 
					uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto response = _hidpp10_device.setRegister(ConnectionState, {index});
 | 
					    auto response = _hidpp10_device.getRegister(ConnectionState, {index},
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return response[0];
 | 
					    return response[0];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -113,7 +94,8 @@ void Receiver::startPairing(uint8_t timeout)
 | 
				
			|||||||
    request[1] = hidpp::DefaultDevice;
 | 
					    request[1] = hidpp::DefaultDevice;
 | 
				
			||||||
    request[2] = timeout;
 | 
					    request[2] = timeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _hidpp10_device.setRegister(DevicePairing, request);
 | 
					    _hidpp10_device.setRegister(DevicePairing, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Receiver::stopPairing()
 | 
					void Receiver::stopPairing()
 | 
				
			||||||
@@ -124,7 +106,8 @@ void Receiver::stopPairing()
 | 
				
			|||||||
    request[0] = 2;
 | 
					    request[0] = 2;
 | 
				
			||||||
    request[1] = hidpp::DefaultDevice;
 | 
					    request[1] = hidpp::DefaultDevice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _hidpp10_device.setRegister(DevicePairing, request);
 | 
					    _hidpp10_device.setRegister(DevicePairing, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Receiver::disconnect(hidpp::DeviceIndex index)
 | 
					void Receiver::disconnect(hidpp::DeviceIndex index)
 | 
				
			||||||
@@ -135,12 +118,14 @@ void Receiver::disconnect(hidpp::DeviceIndex index)
 | 
				
			|||||||
    request[0] = 3;
 | 
					    request[0] = 3;
 | 
				
			||||||
    request[1] = index;
 | 
					    request[1] = index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _hidpp10_device.setRegister(DevicePairing, request);
 | 
					    _hidpp10_device.setRegister(DevicePairing, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Short);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
 | 
					std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto response = _hidpp10_device.getRegister(DeviceActivity, {});
 | 
					    auto response = _hidpp10_device.getRegister(DeviceActivity, {},
 | 
				
			||||||
 | 
					            hidpp::ReportType::Long);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::map<hidpp::DeviceIndex, uint8_t> device_activity;
 | 
					    std::map<hidpp::DeviceIndex, uint8_t> device_activity;
 | 
				
			||||||
    for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
 | 
					    for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
 | 
				
			||||||
@@ -156,7 +141,8 @@ struct Receiver::PairingInfo
 | 
				
			|||||||
    request[0] = index;
 | 
					    request[0] = index;
 | 
				
			||||||
    request[0] += 0x19;
 | 
					    request[0] += 0x19;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto response = _hidpp10_device.getRegister(PairingInfo, request);
 | 
					    auto response = _hidpp10_device.getRegister(PairingInfo, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Long);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct PairingInfo info{};
 | 
					    struct PairingInfo info{};
 | 
				
			||||||
    info.destinationId = response[0];
 | 
					    info.destinationId = response[0];
 | 
				
			||||||
@@ -175,7 +161,8 @@ struct Receiver::ExtendedPairingInfo
 | 
				
			|||||||
    request[0] = index;
 | 
					    request[0] = index;
 | 
				
			||||||
    request[0] += 0x29;
 | 
					    request[0] += 0x29;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto response = _hidpp10_device.getRegister(PairingInfo, request);
 | 
					    auto response = _hidpp10_device.getRegister(PairingInfo, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Long);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ExtendedPairingInfo info{};
 | 
					    ExtendedPairingInfo info{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,7 +184,8 @@ std::string Receiver::getDeviceName(hidpp::DeviceIndex index)
 | 
				
			|||||||
    request[0] = index;
 | 
					    request[0] = index;
 | 
				
			||||||
    request[0] += 0x39;
 | 
					    request[0] += 0x39;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto response = _hidpp10_device.getRegister(PairingInfo, request);
 | 
					    auto response = _hidpp10_device.getRegister(PairingInfo, request,
 | 
				
			||||||
 | 
					            hidpp::ReportType::Long);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t size = response[0];
 | 
					    uint8_t size = response[0];
 | 
				
			||||||
    assert(size <= 14);
 | 
					    assert(size <= 14);
 | 
				
			||||||
@@ -215,12 +203,12 @@ hidpp::DeviceIndex Receiver::deviceDisconnectionEvent(hidpp::Report& report)
 | 
				
			|||||||
    return report.deviceIndex();
 | 
					    return report.deviceIndex();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
 | 
					hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(
 | 
				
			||||||
        hidpp::Report &report)
 | 
					        hidpp::Report &report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(report.subId() == DeviceConnection);
 | 
					    assert(report.subId() == DeviceConnection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DeviceConnectionEvent event{};
 | 
					    hidpp::DeviceConnectionEvent event{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    event.index = report.deviceIndex();
 | 
					    event.index = report.deviceIndex();
 | 
				
			||||||
    event.unifying = ((report.paramBegin()[0] & 0b111) == 0x04);
 | 
					    event.unifying = ((report.paramBegin()[0] & 0b111) == 0x04);
 | 
				
			||||||
@@ -240,23 +228,54 @@ Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Receiver::handleDjEvent(Report& report)
 | 
					void Receiver::handleDjEvent(Report& report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if(report.feature() == DeviceConnection ||
 | 
					    for(auto& handler : dj_event_handlers)
 | 
				
			||||||
        report.feature() == DeviceDisconnection ||
 | 
					        if(handler.second->condition(report))
 | 
				
			||||||
        report.feature() == ConnectionStatus)
 | 
					            handler.second->callback(report);
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        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)
 | 
					void Receiver::handleHidppEvent(hidpp::Report &report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    printf("%s HID++ IN: ", raw_device->hidrawPath().c_str());
 | 
					    for(auto& handler : hidpp_event_handlers)
 | 
				
			||||||
    for(auto &i: report.rawReport())
 | 
					        if(handler.second->condition(report))
 | 
				
			||||||
        printf("%02x ", i);
 | 
					            handler.second->callback(report);
 | 
				
			||||||
    printf("\n");
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::addDjEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					        const std::shared_ptr<EventHandler>& handler)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto it = dj_event_handlers.find(nickname);
 | 
				
			||||||
 | 
					    assert(it == dj_event_handlers.end());
 | 
				
			||||||
 | 
					    dj_event_handlers.emplace(nickname, handler);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::removeDjEventHandler(const std::string &nickname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dj_event_handlers.erase(nickname);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const std::map<std::string, std::shared_ptr<EventHandler>>&
 | 
				
			||||||
 | 
					Receiver::djEventHandlers()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return dj_event_handlers;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::addHidppEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					        const std::shared_ptr<hidpp::EventHandler>& handler)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto it = hidpp_event_handlers.find(nickname);
 | 
				
			||||||
 | 
					    assert(it == hidpp_event_handlers.end());
 | 
				
			||||||
 | 
					    hidpp_event_handlers.emplace(nickname, handler);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Receiver::removeHidppEventHandler(const std::string &nickname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    hidpp_event_handlers.erase(nickname);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
 | 
				
			||||||
 | 
					Receiver::hidppEventHandlers()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return hidpp_event_handlers;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
 | 
					void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
 | 
				
			||||||
@@ -276,10 +295,56 @@ void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Receiver::listen()
 | 
					void Receiver::listen()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::thread{[=]() { raw_device->listen(); }}.detach();
 | 
					    if(!raw_device->isListening())
 | 
				
			||||||
 | 
					        std::thread{[=]() { raw_device->listen(); }}.detach();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(raw_device->eventHandlers().find("RECV_HIDPP") ==
 | 
				
			||||||
 | 
					        raw_device->eventHandlers().end()) {
 | 
				
			||||||
 | 
					        // Pass all HID++ events on DefaultDevice to handleHidppEvent
 | 
				
			||||||
 | 
					        std::shared_ptr<RawEventHandler> hidppRawEventHandler =
 | 
				
			||||||
 | 
					                std::make_shared<RawEventHandler>();
 | 
				
			||||||
 | 
					        hidppRawEventHandler->condition = [](std::vector<uint8_t>& report)->bool
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
 | 
				
			||||||
 | 
					                    report[hidpp::Offset::Type] == hidpp::Report::Type::Long);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        hidppRawEventHandler->callback = [this](std::vector<uint8_t>& report)->void
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            hidpp::Report _report(report);
 | 
				
			||||||
 | 
					            this->handleHidppEvent(_report);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        raw_device->addEventHandler("RECV_HIDPP", hidppRawEventHandler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(raw_device->eventHandlers().find("RECV_DJ") ==
 | 
				
			||||||
 | 
					       raw_device->eventHandlers().end()) {
 | 
				
			||||||
 | 
					        // Pass all DJ events with device index to handleHidppEvent
 | 
				
			||||||
 | 
					        std::shared_ptr<RawEventHandler> djRawEventHandler =
 | 
				
			||||||
 | 
					                std::make_shared<RawEventHandler>();
 | 
				
			||||||
 | 
					        djRawEventHandler->condition = [](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_DJ", djRawEventHandler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Receiver::stopListening()
 | 
					void Receiver::stopListening()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    raw_device->stopListener();
 | 
					    raw_device->removeEventHandler("RECV_HIDPP");
 | 
				
			||||||
 | 
					    raw_device->removeEventHandler("RECV_DJ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(raw_device->eventHandlers().empty())
 | 
				
			||||||
 | 
					        raw_device->stopListener();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::shared_ptr<raw::RawDevice> Receiver::rawDevice() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return raw_device;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -11,6 +11,12 @@ namespace logid {
 | 
				
			|||||||
namespace backend {
 | 
					namespace backend {
 | 
				
			||||||
namespace dj
 | 
					namespace dj
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    struct EventHandler
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::function<bool(Report&)> condition;
 | 
				
			||||||
 | 
					        std::function<void(Report&)> callback;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class InvalidReceiver : public std::exception
 | 
					    class InvalidReceiver : public std::exception
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
@@ -43,7 +49,7 @@ namespace dj
 | 
				
			|||||||
            GetPairedDevices = 0x81
 | 
					            GetPairedDevices = 0x81
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void enumerate();
 | 
					        void enumerateDj();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* The following functions deal with HID++ 1.0 features.
 | 
					        /* The following functions deal with HID++ 1.0 features.
 | 
				
			||||||
         * While these are not technically DJ functions, it is redundant
 | 
					         * While these are not technically DJ functions, it is redundant
 | 
				
			||||||
@@ -77,7 +83,7 @@ namespace dj
 | 
				
			|||||||
        notification_flags getHidppNotifications();
 | 
					        notification_flags getHidppNotifications();
 | 
				
			||||||
        void enableHidppNotifications(notification_flags flags);
 | 
					        void enableHidppNotifications(notification_flags flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ///TODO: Understand output of this function
 | 
					        void enumerateHidpp();
 | 
				
			||||||
        uint8_t getConnectionState(hidpp::DeviceIndex index);
 | 
					        uint8_t getConnectionState(hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void startPairing(uint8_t timeout = 0);
 | 
					        void startPairing(uint8_t timeout = 0);
 | 
				
			||||||
@@ -107,35 +113,57 @@ namespace dj
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::string getDeviceName(hidpp::DeviceIndex index);
 | 
					        std::string getDeviceName(hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct DeviceConnectionEvent
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            hidpp::DeviceIndex index;
 | 
					 | 
				
			||||||
            uint16_t pid;
 | 
					 | 
				
			||||||
            DeviceType::DeviceType deviceType;
 | 
					 | 
				
			||||||
            bool unifying;
 | 
					 | 
				
			||||||
            bool softwarePresent;
 | 
					 | 
				
			||||||
            bool encrypted;
 | 
					 | 
				
			||||||
            bool linkEstablished;
 | 
					 | 
				
			||||||
            bool withPayload;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static hidpp::DeviceIndex deviceDisconnectionEvent(
 | 
					        static hidpp::DeviceIndex deviceDisconnectionEvent(
 | 
				
			||||||
                hidpp::Report& report);
 | 
					                hidpp::Report& report);
 | 
				
			||||||
        static DeviceConnectionEvent deviceConnectionEvent(
 | 
					        static hidpp::DeviceConnectionEvent deviceConnectionEvent(
 | 
				
			||||||
                hidpp::Report& report);
 | 
					                hidpp::Report& report);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void handleDjEvent(dj::Report& report);
 | 
					 | 
				
			||||||
        void handleHidppEvent(hidpp::Report& report);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void listen();
 | 
					        void listen();
 | 
				
			||||||
        void stopListening();
 | 
					        void stopListening();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void addDjEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					                const std::shared_ptr<EventHandler>& handler);
 | 
				
			||||||
 | 
					        void removeDjEventHandler(const std::string& nickname);
 | 
				
			||||||
 | 
					        const std::map<std::string, std::shared_ptr<EventHandler>>&
 | 
				
			||||||
 | 
					        djEventHandlers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void addHidppEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					                const std::shared_ptr<hidpp::EventHandler>& handler);
 | 
				
			||||||
 | 
					        void removeHidppEventHandler(const std::string& nickname);
 | 
				
			||||||
 | 
					        const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
 | 
				
			||||||
 | 
					            hidppEventHandlers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::shared_ptr<raw::RawDevice> rawDevice() const;
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        void sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
 | 
					        void sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
 | 
				
			||||||
                const std::vector<uint8_t>&& params);
 | 
					                const std::vector<uint8_t>&& params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void handleDjEvent(dj::Report& report);
 | 
				
			||||||
 | 
					        void handleHidppEvent(hidpp::Report& report);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::map<std::string, std::shared_ptr<EventHandler>>
 | 
				
			||||||
 | 
					                dj_event_handlers;
 | 
				
			||||||
 | 
					        std::map<std::string, std::shared_ptr<hidpp::EventHandler>>
 | 
				
			||||||
 | 
					                hidpp_event_handlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::shared_ptr<raw::RawDevice> raw_device;
 | 
					        std::shared_ptr<raw::RawDevice> raw_device;
 | 
				
			||||||
        hidpp10::Device _hidpp10_device;
 | 
					        hidpp10::Device _hidpp10_device;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace hidpp
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct DeviceConnectionEvent
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        hidpp::DeviceIndex index;
 | 
				
			||||||
 | 
					        uint16_t pid;
 | 
				
			||||||
 | 
					        dj::DeviceType::DeviceType deviceType;
 | 
				
			||||||
 | 
					        bool unifying;
 | 
				
			||||||
 | 
					        bool softwarePresent;
 | 
				
			||||||
 | 
					        bool encrypted;
 | 
				
			||||||
 | 
					        bool linkEstablished;
 | 
				
			||||||
 | 
					        bool withPayload;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}}}
 | 
					}}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //LOGID_BACKEND_DJ_RECEIVER_H
 | 
					#endif //LOGID_BACKEND_DJ_RECEIVER_H
 | 
				
			||||||
@@ -1,30 +1,70 @@
 | 
				
			|||||||
#include "ReceiverMonitor.h"
 | 
					#include "ReceiverMonitor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace logid::backend::dj;
 | 
					using namespace logid::backend::dj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ReceiverMonitor::ReceiverMonitor(std::string path) : _reciever (std::move(path))
 | 
					ReceiverMonitor::ReceiverMonitor(std::string path) : _receiver (
 | 
				
			||||||
 | 
					        std::make_shared<Receiver>(std::move(path)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    assert(_receiver->hidppEventHandlers().find("RECVMON") ==
 | 
				
			||||||
 | 
					        _receiver->hidppEventHandlers().end());
 | 
				
			||||||
 | 
					    assert(_receiver->djEventHandlers().find("RECVMON") ==
 | 
				
			||||||
 | 
					           _receiver->djEventHandlers().end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Receiver::notification_flags notification_flags{
 | 
					    Receiver::notification_flags notification_flags{
 | 
				
			||||||
        true,
 | 
					        true,
 | 
				
			||||||
        true,
 | 
					        true,
 | 
				
			||||||
        true};
 | 
					        true};
 | 
				
			||||||
   _reciever.enableHidppNotifications(notification_flags);
 | 
					   _receiver->enableHidppNotifications(notification_flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ReceiverMonitor::run()
 | 
					void ReceiverMonitor::run()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    _reciever.listen();
 | 
					    _receiver->listen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(_receiver->hidppEventHandlers().find("RECVMON") ==
 | 
				
			||||||
 | 
					           _receiver->hidppEventHandlers().end())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::shared_ptr<hidpp::EventHandler> eventHandler =
 | 
				
			||||||
 | 
					                std::make_shared<hidpp::EventHandler>();
 | 
				
			||||||
 | 
					        eventHandler->condition = [](hidpp::Report &report) -> bool {
 | 
				
			||||||
 | 
					            return (report.subId() == Receiver::DeviceConnection ||
 | 
				
			||||||
 | 
					                    report.subId() == Receiver::DeviceDisconnection);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eventHandler->callback = [this](hidpp::Report &report) -> void {
 | 
				
			||||||
 | 
					            /* Running in a new thread prevents deadlocks since the
 | 
				
			||||||
 | 
					             * receiver may be enumerating.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            std::thread{[this](hidpp::Report report) {
 | 
				
			||||||
 | 
					                if (report.subId() == Receiver::DeviceConnection)
 | 
				
			||||||
 | 
					                    this->addDevice(this->_receiver->deviceConnectionEvent(
 | 
				
			||||||
 | 
					                            report));
 | 
				
			||||||
 | 
					                else if (report.subId() == Receiver::DeviceDisconnection)
 | 
				
			||||||
 | 
					                    this->removeDevice(this->_receiver->
 | 
				
			||||||
 | 
					                            deviceDisconnectionEvent(report));
 | 
				
			||||||
 | 
					            }, report}.detach();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _receiver->addHidppEventHandler("RECVMON", eventHandler);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enumerate();
 | 
					    enumerate();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ReceiverMonitor::stop()
 | 
					void ReceiverMonitor::stop()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    _reciever.stopListening();
 | 
					    _receiver->stopListening();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ReceiverMonitor::enumerate()
 | 
					void ReceiverMonitor::enumerate()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    _reciever.enumerate();
 | 
					    _receiver->enumerateHidpp();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::shared_ptr<Receiver> ReceiverMonitor::receiver() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return _receiver;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -21,7 +21,7 @@ namespace dj
 | 
				
			|||||||
        void stop();
 | 
					        void stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected:
 | 
					    protected:
 | 
				
			||||||
        virtual void addDevice(hidpp::DeviceIndex index, uint16_t pid) = 0;
 | 
					        virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0;
 | 
				
			||||||
        virtual void removeDevice(hidpp::DeviceIndex index) = 0;
 | 
					        virtual void removeDevice(hidpp::DeviceIndex index) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Internal methods for derived class
 | 
					        // Internal methods for derived class
 | 
				
			||||||
@@ -29,8 +29,10 @@ namespace dj
 | 
				
			|||||||
        void _stopPairing();
 | 
					        void _stopPairing();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void _unpair();
 | 
					        void _unpair();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::shared_ptr<Receiver> receiver() const;
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        Receiver _reciever;
 | 
					        std::shared_ptr<Receiver> _receiver;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}}}
 | 
					}}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,12 @@
 | 
				
			|||||||
#include <assert.h>
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
#include "Device.h"
 | 
					#include "Device.h"
 | 
				
			||||||
#include "Report.h"
 | 
					#include "Report.h"
 | 
				
			||||||
#include "../hidpp20/features/Root.h"
 | 
					#include "../hidpp20/features/Root.h"
 | 
				
			||||||
 | 
					#include "../hidpp20/features/DeviceName.h"
 | 
				
			||||||
#include "../hidpp20/Error.h"
 | 
					#include "../hidpp20/Error.h"
 | 
				
			||||||
#include "../hidpp10/Error.h"
 | 
					#include "../hidpp10/Error.h"
 | 
				
			||||||
 | 
					#include "../dj/Receiver.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace logid::backend;
 | 
					using namespace logid::backend;
 | 
				
			||||||
using namespace logid::backend::hidpp;
 | 
					using namespace logid::backend::hidpp;
 | 
				
			||||||
@@ -16,6 +19,10 @@ const char* Device::InvalidDevice::what() const noexcept
 | 
				
			|||||||
            return "Invalid HID++ device";
 | 
					            return "Invalid HID++ device";
 | 
				
			||||||
        case InvalidRawDevice:
 | 
					        case InvalidRawDevice:
 | 
				
			||||||
            return "Invalid raw device";
 | 
					            return "Invalid raw device";
 | 
				
			||||||
 | 
					        case Asleep:
 | 
				
			||||||
 | 
					            return "Device asleep";
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return "Invalid device";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,36 +33,41 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// TODO: Initialize a single RawDevice for each path.
 | 
					/// TODO: Initialize a single RawDevice for each path.
 | 
				
			||||||
Device::Device(const std::string& path, DeviceIndex index):
 | 
					Device::Device(const std::string& path, DeviceIndex index):
 | 
				
			||||||
    raw_device (std::make_shared<raw::RawDevice>(path)), path (path),
 | 
					    _raw_device (std::make_shared<raw::RawDevice>(path)),  _receiver (nullptr),
 | 
				
			||||||
    _index (index)
 | 
					    _path (path), _index (index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    _init();
 | 
					    _init();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index) :
 | 
					Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index) :
 | 
				
			||||||
    raw_device (raw_device), _index (index)
 | 
					    _raw_device (std::move(raw_device)), _receiver (nullptr),
 | 
				
			||||||
 | 
					    _path (_raw_device->hidrawPath()), _index (index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    _init();
 | 
					    _init();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Device::Device(std::shared_ptr<dj::Receiver> receiver,
 | 
				
			||||||
 | 
					        hidpp::DeviceConnectionEvent event) :
 | 
				
			||||||
 | 
					    _raw_device (receiver->rawDevice()), _index (event.index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Device will throw an error soon, just do it now
 | 
				
			||||||
 | 
					    if(!event.linkEstablished)
 | 
				
			||||||
 | 
					        throw InvalidDevice(InvalidDevice::Asleep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _pid = event.pid;
 | 
				
			||||||
 | 
					    _init();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Device::_init()
 | 
					void Device::_init()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    supported_reports = getSupportedReports(raw_device->reportDescriptor());
 | 
					    supported_reports = getSupportedReports(_raw_device->reportDescriptor());
 | 
				
			||||||
    if(!supported_reports)
 | 
					    if(!supported_reports)
 | 
				
			||||||
        throw InvalidDevice(InvalidDevice::NoHIDPPReport);
 | 
					        throw InvalidDevice(InvalidDevice::NoHIDPPReport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try
 | 
					    try {
 | 
				
			||||||
    {
 | 
					        hidpp20::EssentialRoot root(this);
 | 
				
			||||||
        Report versionRequest(Report::Type::Short, _index,
 | 
					        _version = root.getVersion();
 | 
				
			||||||
                hidpp20::FeatureID::ROOT,hidpp20::Root::Ping,
 | 
					    } catch(hidpp10::Error &e) {
 | 
				
			||||||
                LOGID_HIDPP_SOFTWARE_ID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto versionResponse = sendReport(versionRequest);
 | 
					 | 
				
			||||||
        auto versionResponse_params = versionResponse.paramBegin();
 | 
					 | 
				
			||||||
        _version = std::make_tuple(versionResponse_params[0], versionResponse_params[1]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(hidpp10::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // Valid HID++ 1.0 devices should send an InvalidSubID error
 | 
					        // Valid HID++ 1.0 devices should send an InvalidSubID error
 | 
				
			||||||
        if(e.code() != hidpp10::Error::InvalidSubID)
 | 
					        if(e.code() != hidpp10::Error::InvalidSubID)
 | 
				
			||||||
            throw;
 | 
					            throw;
 | 
				
			||||||
@@ -64,29 +76,30 @@ void Device::_init()
 | 
				
			|||||||
        _version = std::make_tuple(1, 0);
 | 
					        _version = std::make_tuple(1, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Pass all HID++ events with device index to this device.
 | 
					    if(!_receiver) {
 | 
				
			||||||
    RawEventHandler rawEventHandler;
 | 
					        _pid = _raw_device->productId();
 | 
				
			||||||
    rawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
 | 
					        if(std::get<0>(_version) >= 2) {
 | 
				
			||||||
    {
 | 
					            try {
 | 
				
			||||||
        return (report[Offset::Type] == Report::Type::Short ||
 | 
					                hidpp20::EssentialDeviceName deviceName(this);
 | 
				
			||||||
                report[Offset::Type] == Report::Type::Long) &&
 | 
					                _name = deviceName.getName();
 | 
				
			||||||
                (report[Offset::DeviceIndex] == this->_index);
 | 
					            } catch(hidpp20::UnsupportedFeature &e) {
 | 
				
			||||||
    };
 | 
					                _name = _raw_device->name();
 | 
				
			||||||
    rawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
 | 
					            }
 | 
				
			||||||
    {
 | 
					        } else {
 | 
				
			||||||
        Report _report(report);
 | 
					            _name = _raw_device->name();
 | 
				
			||||||
        this->handleEvent(_report);
 | 
					        }
 | 
				
			||||||
    };
 | 
					    } else {
 | 
				
			||||||
 | 
					        _name = _receiver->getDeviceName(_index);
 | 
				
			||||||
    raw_device->addEventHandler("DEV_" + std::to_string(_index), rawEventHandler);
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Device::~Device()
 | 
					Device::~Device()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    raw_device->removeEventHandler("DEV_" + std::to_string(_index));
 | 
					    _raw_device->removeEventHandler("DEV_" + std::to_string(_index));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Device::addEventHandler(const std::string& nickname, const std::shared_ptr<EventHandler>& handler)
 | 
					void Device::addEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					        const std::shared_ptr<EventHandler>& handler)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto it = event_handlers.find(nickname);
 | 
					    auto it = event_handlers.find(nickname);
 | 
				
			||||||
    assert(it == event_handlers.end());
 | 
					    assert(it == event_handlers.end());
 | 
				
			||||||
@@ -119,7 +132,7 @@ Report Device::sendReport(Report& report)
 | 
				
			|||||||
            assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED);
 | 
					            assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto raw_response = raw_device->sendReport(report.rawReport());
 | 
					    auto raw_response = _raw_device->sendReport(report.rawReport());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Report response(raw_response);
 | 
					    Report response(raw_response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,5 +149,30 @@ Report Device::sendReport(Report& report)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Device::listen()
 | 
					void Device::listen()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    raw_device->listen();
 | 
					    if(!_raw_device->isListening())
 | 
				
			||||||
 | 
					        std::thread{[=]() { _raw_device->listen(); }}.detach();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Pass all HID++ events with device index to this device.
 | 
				
			||||||
 | 
					    std::shared_ptr<RawEventHandler> rawEventHandler;
 | 
				
			||||||
 | 
					    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] == this->_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::stopListening()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    _raw_device->removeEventHandler("DEV_" + std::to_string(_index));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!_raw_device->eventHandlers().empty())
 | 
				
			||||||
 | 
					        _raw_device->stopListener();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -11,8 +11,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace logid {
 | 
					namespace logid {
 | 
				
			||||||
namespace backend {
 | 
					namespace backend {
 | 
				
			||||||
 | 
					namespace dj
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Need to define here for a constructor
 | 
				
			||||||
 | 
					    class Receiver;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
namespace hidpp
 | 
					namespace hidpp
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    struct DeviceConnectionEvent;
 | 
				
			||||||
    struct EventHandler
 | 
					    struct EventHandler
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::function<bool(Report&)> condition;
 | 
					        std::function<bool(Report&)> condition;
 | 
				
			||||||
@@ -27,7 +33,8 @@ namespace hidpp
 | 
				
			|||||||
            enum Reason
 | 
					            enum Reason
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                NoHIDPPReport,
 | 
					                NoHIDPPReport,
 | 
				
			||||||
                InvalidRawDevice
 | 
					                InvalidRawDevice,
 | 
				
			||||||
 | 
					                Asleep
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            InvalidDevice(Reason reason) : _reason (reason) {}
 | 
					            InvalidDevice(Reason reason) : _reason (reason) {}
 | 
				
			||||||
            virtual const char *what() const noexcept;
 | 
					            virtual const char *what() const noexcept;
 | 
				
			||||||
@@ -36,18 +43,21 @@ namespace hidpp
 | 
				
			|||||||
            Reason _reason;
 | 
					            Reason _reason;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Device(const std::string& path, DeviceIndex index);
 | 
					        explicit Device(const std::string& path, DeviceIndex index);
 | 
				
			||||||
        Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index);
 | 
					        explicit Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index);
 | 
				
			||||||
 | 
					        explicit Device(std::shared_ptr<dj::Receiver> receiver,
 | 
				
			||||||
 | 
					                hidpp::DeviceConnectionEvent event);
 | 
				
			||||||
        ~Device();
 | 
					        ~Device();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string devicePath() const { return path; }
 | 
					        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; }
 | 
					        std::tuple<uint8_t, uint8_t> version() const { return _version; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void listen(); // Runs asynchronously
 | 
					        void listen(); // Runs asynchronously
 | 
				
			||||||
        void stopListening();
 | 
					        void stopListening();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void addEventHandler(const std::string& nickname, const std::shared_ptr<EventHandler>& handler);
 | 
					        void addEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					                const std::shared_ptr<EventHandler>& handler);
 | 
				
			||||||
        void removeEventHandler(const std::string& nickname);
 | 
					        void removeEventHandler(const std::string& nickname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Report sendReport(Report& report);
 | 
					        Report sendReport(Report& report);
 | 
				
			||||||
@@ -56,12 +66,15 @@ namespace hidpp
 | 
				
			|||||||
    private:
 | 
					    private:
 | 
				
			||||||
        void _init();
 | 
					        void _init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::shared_ptr<raw::RawDevice> raw_device;
 | 
					        std::shared_ptr<raw::RawDevice> _raw_device;
 | 
				
			||||||
        std::string path;
 | 
					        std::shared_ptr<dj::Receiver> _receiver;
 | 
				
			||||||
 | 
					        std::string _path;
 | 
				
			||||||
        DeviceIndex _index;
 | 
					        DeviceIndex _index;
 | 
				
			||||||
        uint8_t supported_reports;
 | 
					        uint8_t supported_reports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::tuple<uint8_t, uint8_t> _version;
 | 
					        std::tuple<uint8_t, uint8_t> _version;
 | 
				
			||||||
 | 
					        uint16_t _pid;
 | 
				
			||||||
 | 
					        std::string _name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::map<std::string, std::shared_ptr<EventHandler>> event_handlers;
 | 
					        std::map<std::string, std::shared_ptr<EventHandler>> event_handlers;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -180,6 +180,16 @@ void Report::setType(Report::Type type)
 | 
				
			|||||||
    _data[Offset::Type] = type;
 | 
					    _data[Offset::Type] = type;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hidpp::DeviceIndex Report::deviceIndex()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return static_cast<hidpp::DeviceIndex>(_data[Offset::DeviceIndex]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Report::setDeviceIndex(hidpp::DeviceIndex index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    _data[Offset::DeviceIndex] = index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t Report::feature() const
 | 
					uint8_t Report::feature() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return _data[Offset::Feature];
 | 
					    return _data[Offset::Feature];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,9 @@ namespace logid::backend::hidpp
 | 
				
			|||||||
        Report::Type type() const;
 | 
					        Report::Type type() const;
 | 
				
			||||||
        void setType(Report::Type type);
 | 
					        void setType(Report::Type type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logid::backend::hidpp::DeviceIndex deviceIndex();
 | 
				
			||||||
 | 
					        void setDeviceIndex(hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        uint8_t feature() const;
 | 
					        uint8_t feature() const;
 | 
				
			||||||
        void setFeature(uint8_t feature);
 | 
					        void setFeature(uint8_t feature);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,11 +99,6 @@ namespace logid::backend::hidpp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        bool isError20(hidpp20_error* error);
 | 
					        bool isError20(hidpp20_error* error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logid::backend::hidpp::DeviceIndex deviceIndex()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return static_cast<DeviceIndex>(_data[Offset::DeviceIndex]);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::vector<uint8_t> rawReport () const { return _data; }
 | 
					        std::vector<uint8_t> rawReport () const { return _data; }
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        static constexpr std::size_t HeaderLength = 4;
 | 
					        static constexpr std::size_t HeaderLength = 4;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,13 +19,10 @@ Device::Device(std::shared_ptr<raw::RawDevice> raw_dev,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<uint8_t> Device::getRegister(uint8_t address,
 | 
					std::vector<uint8_t> Device::getRegister(uint8_t address,
 | 
				
			||||||
        const std::vector<uint8_t>& params)
 | 
					        const std::vector<uint8_t>& params, hidpp::Report::Type type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(params.size() <= hidpp::LongParamLength);
 | 
					    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 ?
 | 
					    uint8_t sub_id = type == hidpp::Report::Type::Short ?
 | 
				
			||||||
            GetRegisterShort : GetRegisterLong;
 | 
					            GetRegisterShort : GetRegisterLong;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,13 +30,11 @@ std::vector<uint8_t> Device::getRegister(uint8_t address,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<uint8_t> Device::setRegister(uint8_t address,
 | 
					std::vector<uint8_t> Device::setRegister(uint8_t address,
 | 
				
			||||||
                                         const std::vector<uint8_t>& params)
 | 
					                                         const std::vector<uint8_t>& params,
 | 
				
			||||||
 | 
					                                         hidpp::Report::Type type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(params.size() <= hidpp::LongParamLength);
 | 
					    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 ?
 | 
					    uint8_t sub_id = type == hidpp::Report::Type::Short ?
 | 
				
			||||||
                     SetRegisterShort : SetRegisterLong;
 | 
					                     SetRegisterShort : SetRegisterLong;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,10 +15,10 @@ namespace hidpp10
 | 
				
			|||||||
                hidpp::DeviceIndex index);
 | 
					                hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<uint8_t> getRegister(uint8_t address,
 | 
					        std::vector<uint8_t> getRegister(uint8_t address,
 | 
				
			||||||
                const std::vector<uint8_t>& params);
 | 
					                const std::vector<uint8_t>& params, hidpp::Report::Type type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<uint8_t> setRegister(uint8_t address,
 | 
					        std::vector<uint8_t> setRegister(uint8_t address,
 | 
				
			||||||
                const std::vector<uint8_t>& params);
 | 
					                const std::vector<uint8_t>& params, hidpp::Report::Type type);
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        std::vector<uint8_t> accessRegister(uint8_t sub_id,
 | 
					        std::vector<uint8_t> accessRegister(uint8_t sub_id,
 | 
				
			||||||
                uint8_t address, const std::vector<uint8_t>& params);
 | 
					                uint8_t address, const std::vector<uint8_t>& params);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								src/logid/backend/hidpp20/EssentialFeature.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/logid/backend/hidpp20/EssentialFeature.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include "EssentialFeature.h"
 | 
				
			||||||
 | 
					#include "feature_defs.h"
 | 
				
			||||||
 | 
					#include "features/Root.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace logid::backend::hidpp20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<uint8_t> EssentialFeature::callFunction(uint8_t function_id,
 | 
				
			||||||
 | 
					        std::vector<uint8_t>& params)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    hidpp::Report::Type type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(params.size() <= hidpp::LongParamLength);
 | 
				
			||||||
 | 
					    if(params.size() <= hidpp::ShortParamLength)
 | 
				
			||||||
 | 
					        type = hidpp::Report::Type::Short;
 | 
				
			||||||
 | 
					    else if(params.size() <= hidpp::LongParamLength)
 | 
				
			||||||
 | 
					        type = hidpp::Report::Type::Long;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hidpp::Report request(type, _device->deviceIndex(), _index, function_id,
 | 
				
			||||||
 | 
					                          LOGID_HIDPP_SOFTWARE_ID);
 | 
				
			||||||
 | 
					    std::copy(params.begin(), params.end(), request.paramBegin());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto response = _device->sendReport(request);
 | 
				
			||||||
 | 
					    return std::vector<uint8_t>(response.paramBegin(), response.paramEnd());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EssentialFeature::EssentialFeature(hidpp::Device* dev, uint16_t _id) :
 | 
				
			||||||
 | 
					    _device (dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    _index = hidpp20::FeatureID::ROOT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(_id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::vector<uint8_t> getFunc_req(2);
 | 
				
			||||||
 | 
					        getFunc_req[0] = (_id >> 8) & 0xff;
 | 
				
			||||||
 | 
					        getFunc_req[1] = _id & 0xff;
 | 
				
			||||||
 | 
					        auto getFunc_resp = this->callFunction(Root::GetFeature, getFunc_req);
 | 
				
			||||||
 | 
					        _index = getFunc_resp[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 0 if not found
 | 
				
			||||||
 | 
					        if(!_index)
 | 
				
			||||||
 | 
					            throw UnsupportedFeature(_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/logid/backend/hidpp20/EssentialFeature.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/logid/backend/hidpp20/EssentialFeature.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#ifndef LOGID_HIDPP20_ESSENTIAL_FEATURE_H
 | 
				
			||||||
 | 
					#define LOGID_HIDPP20_ESSENTIAL_FEATURE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WARNING: UNSAFE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This class is only meant to provide essential HID++ 2.0 features to the
 | 
				
			||||||
 | 
					 * hidpp::Device class. No version checks are provided here
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace logid {
 | 
				
			||||||
 | 
					namespace backend {
 | 
				
			||||||
 | 
					namespace hidpp20
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class EssentialFeature
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        static const uint16_t ID;
 | 
				
			||||||
 | 
					        virtual uint16_t getID() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected:
 | 
				
			||||||
 | 
					        EssentialFeature(hidpp::Device* dev, uint16_t _id);
 | 
				
			||||||
 | 
					        std::vector<uint8_t> callFunction(uint8_t function_id,
 | 
				
			||||||
 | 
					                std::vector<uint8_t>& params);
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        hidpp::Device* _device;
 | 
				
			||||||
 | 
					        uint8_t _index;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //LOGID_HIDPP20_ESSENTIAL_FEATURE_H
 | 
				
			||||||
							
								
								
									
										68
									
								
								src/logid/backend/hidpp20/features/DeviceName.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/logid/backend/hidpp20/features/DeviceName.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					#include "DeviceName.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace logid::backend;
 | 
				
			||||||
 | 
					using namespace logid::backend::hidpp20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceName::DeviceName(Device* dev) : Feature(dev, ID)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t DeviceName::getNameLength()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::vector<uint8_t> params(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto response = this->callFunction(Function::GetLength, params);
 | 
				
			||||||
 | 
					    return response[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string _getName(uint8_t length,
 | 
				
			||||||
 | 
					        const std::function<std::vector<uint8_t>(std::vector<uint8_t>)>& fcall)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t function_calls = length/hidpp::LongParamLength;
 | 
				
			||||||
 | 
					    if(length % hidpp::LongParamLength)
 | 
				
			||||||
 | 
					        function_calls++;
 | 
				
			||||||
 | 
					    std::vector<uint8_t> params(1);
 | 
				
			||||||
 | 
					    std::string name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(uint8_t i = 0; i < function_calls; i++) {
 | 
				
			||||||
 | 
					        params[0] = i*hidpp::LongParamLength;
 | 
				
			||||||
 | 
					        auto name_section = fcall(params);
 | 
				
			||||||
 | 
					        for(std::size_t j = 0; j < hidpp::LongParamLength; j++) {
 | 
				
			||||||
 | 
					            if(params[0] + j >= length)
 | 
				
			||||||
 | 
					                return name;
 | 
				
			||||||
 | 
					            name += name_section[j];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string DeviceName::getName()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return _getName(getNameLength(), [this]
 | 
				
			||||||
 | 
					    (std::vector<uint8_t> params)->std::vector<uint8_t> {
 | 
				
			||||||
 | 
					        return this->callFunction(Function::GetDeviceName, params);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EssentialDeviceName::EssentialDeviceName(hidpp::Device* dev) :
 | 
				
			||||||
 | 
					    EssentialFeature(dev, ID)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t EssentialDeviceName::getNameLength()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::vector<uint8_t> params(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto response = this->callFunction(DeviceName::Function::GetLength, params);
 | 
				
			||||||
 | 
					    return response[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string EssentialDeviceName::getName()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return _getName(getNameLength(), [this]
 | 
				
			||||||
 | 
					    (std::vector<uint8_t> params)->std::vector<uint8_t> {
 | 
				
			||||||
 | 
					        return this->callFunction(DeviceName::Function::GetDeviceName, params);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/logid/backend/hidpp20/features/DeviceName.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/logid/backend/hidpp20/features/DeviceName.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					#ifndef LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H
 | 
				
			||||||
 | 
					#define LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../Feature.h"
 | 
				
			||||||
 | 
					#include "../feature_defs.h"
 | 
				
			||||||
 | 
					#include "../EssentialFeature.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace logid {
 | 
				
			||||||
 | 
					namespace backend {
 | 
				
			||||||
 | 
					namespace hidpp20
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class DeviceName : public Feature
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        static const uint16_t ID = FeatureID::DEVICE_NAME;
 | 
				
			||||||
 | 
					        virtual uint16_t getID() { return ID; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        enum Function : uint8_t
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            GetLength = 0,
 | 
				
			||||||
 | 
					            GetDeviceName = 1
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DeviceName(Device* device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t getNameLength();
 | 
				
			||||||
 | 
					        std::string getName();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class EssentialDeviceName : public EssentialFeature
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        static const uint16_t ID = FeatureID::DEVICE_NAME;
 | 
				
			||||||
 | 
					        virtual uint16_t getID() { return ID; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        EssentialDeviceName(hidpp::Device* device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uint8_t getNameLength();
 | 
				
			||||||
 | 
					        std::string getName();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H
 | 
				
			||||||
@@ -6,27 +6,36 @@ Root::Root(Device* dev) : Feature(dev, ID)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
feature_info Root::getFeature(uint16_t feature_id)
 | 
					std::vector<uint8_t> _genGetFeatureParams(uint16_t feature_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    feature_info info{};
 | 
					 | 
				
			||||||
    std::vector<uint8_t> params(2);
 | 
					    std::vector<uint8_t> params(2);
 | 
				
			||||||
    params[0] = feature_id & 0xff;
 | 
					    params[0] = feature_id & 0xff;
 | 
				
			||||||
    params[1] = (feature_id >> 8) & 0xff;
 | 
					    params[1] = (feature_id >> 8) & 0xff;
 | 
				
			||||||
 | 
					    return params;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto response = this->callFunction(Function::GetFeature, params);
 | 
					feature_info _genGetFeatureInfo(uint16_t feature_id, std::vector<uint8_t> response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    feature_info info{};
 | 
				
			||||||
    info.feature_id = response[0];
 | 
					    info.feature_id = response[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(!info.feature_id)
 | 
					    if(!info.feature_id)
 | 
				
			||||||
        throw UnsupportedFeature(feature_id);
 | 
					        throw UnsupportedFeature(feature_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info.hidden = response[1] & FeatureFlag::Hidden;
 | 
					    info.hidden = response[1] & Root::FeatureFlag::Hidden;
 | 
				
			||||||
    info.obsolete = response[1] & FeatureFlag::Obsolete;
 | 
					    info.obsolete = response[1] & Root::FeatureFlag::Obsolete;
 | 
				
			||||||
    info.internal = response[1] & FeatureFlag::Internal;
 | 
					    info.internal = response[1] & Root::FeatureFlag::Internal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return info;
 | 
					    return info;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					feature_info Root::getFeature(uint16_t feature_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto params = _genGetFeatureParams(feature_id);
 | 
				
			||||||
 | 
					    auto response = this->callFunction(Function::GetFeature, params);
 | 
				
			||||||
 | 
					    return _genGetFeatureInfo(feature_id, response);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::tuple<uint8_t, uint8_t> Root::getVersion()
 | 
					std::tuple<uint8_t, uint8_t> Root::getVersion()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::vector<uint8_t> params(0);
 | 
					    std::vector<uint8_t> params(0);
 | 
				
			||||||
@@ -34,3 +43,22 @@ std::tuple<uint8_t, uint8_t> Root::getVersion()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return std::make_tuple(response[0], response[1]);
 | 
					    return std::make_tuple(response[0], response[1]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EssentialRoot::EssentialRoot(hidpp::Device* dev) : EssentialFeature(dev, ID)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					feature_info EssentialRoot::getFeature(uint16_t feature_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto params = _genGetFeatureParams(feature_id);
 | 
				
			||||||
 | 
					    auto response = this->callFunction(Root::Function::GetFeature, params);
 | 
				
			||||||
 | 
					    return _genGetFeatureInfo(feature_id, response);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::tuple<uint8_t, uint8_t> EssentialRoot::getVersion()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::vector<uint8_t> params(0);
 | 
				
			||||||
 | 
					    auto response = this->callFunction(Root::Function::Ping, params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::make_tuple(response[0], response[1]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
#define LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
 | 
					#define LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../Feature.h"
 | 
					#include "../Feature.h"
 | 
				
			||||||
 | 
					#include "../EssentialFeature.h"
 | 
				
			||||||
#include "../feature_defs.h"
 | 
					#include "../feature_defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace logid {
 | 
					namespace logid {
 | 
				
			||||||
@@ -24,7 +25,7 @@ namespace hidpp20
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        feature_info getFeature (uint16_t feature_id);
 | 
					        feature_info getFeature (uint16_t feature_id);
 | 
				
			||||||
        std::tuple<uint8_t, uint8_t> getVersion();
 | 
					        std::tuple<uint8_t, uint8_t> getVersion();
 | 
				
			||||||
    private:
 | 
					
 | 
				
			||||||
        enum FeatureFlag : uint8_t
 | 
					        enum FeatureFlag : uint8_t
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Obsolete = 1<<7,
 | 
					            Obsolete = 1<<7,
 | 
				
			||||||
@@ -32,6 +33,18 @@ namespace hidpp20
 | 
				
			|||||||
            Internal = 1<<5
 | 
					            Internal = 1<<5
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class EssentialRoot : public EssentialFeature
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        static const uint16_t ID = FeatureID::ROOT;
 | 
				
			||||||
 | 
					        virtual uint16_t getID() { return ID; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        EssentialRoot(hidpp::Device* device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        feature_info getFeature (uint16_t feature_id);
 | 
				
			||||||
 | 
					        std::tuple<uint8_t, uint8_t> getVersion();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}}}
 | 
					}}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
 | 
					#endif //LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
 | 
				
			||||||
@@ -24,8 +24,8 @@ using namespace std::chrono;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool RawDevice::supportedReportID(uint8_t id)
 | 
					bool RawDevice::supportedReportID(uint8_t id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id) ||
 | 
					    return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id)
 | 
				
			||||||
           (dj::ReportType::Short == id) || (dj::ReportType::Long == id);
 | 
					        || (dj::ReportType::Short == id) || (dj::ReportType::Long == id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
 | 
					RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
 | 
				
			||||||
@@ -34,14 +34,16 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fd = ::open(path.c_str(), O_RDWR);
 | 
					    fd = ::open(path.c_str(), O_RDWR);
 | 
				
			||||||
    if (fd == -1)
 | 
					    if (fd == -1)
 | 
				
			||||||
        throw std::system_error(errno, std::system_category(), "RawDevice open failed");
 | 
					        throw std::system_error(errno, std::system_category(),
 | 
				
			||||||
 | 
					                "RawDevice open failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hidraw_devinfo devinfo{};
 | 
					    hidraw_devinfo devinfo{};
 | 
				
			||||||
    if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo))
 | 
					    if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int err = errno;
 | 
					        int err = errno;
 | 
				
			||||||
        ::close(fd);
 | 
					        ::close(fd);
 | 
				
			||||||
        throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWINFO failed");
 | 
					        throw std::system_error(err, std::system_category(),
 | 
				
			||||||
 | 
					                "RawDevice HIDIOCGRAWINFO failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vid = devinfo.vendor;
 | 
					    vid = devinfo.vendor;
 | 
				
			||||||
    pid = devinfo.product;
 | 
					    pid = devinfo.product;
 | 
				
			||||||
@@ -51,22 +53,25 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int err = errno;
 | 
					        int err = errno;
 | 
				
			||||||
        ::close(fd);
 | 
					        ::close(fd);
 | 
				
			||||||
        throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWNAME failed");
 | 
					        throw std::system_error(err, std::system_category(),
 | 
				
			||||||
 | 
					                "RawDevice HIDIOCGRAWNAME failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    name.assign(name_buf, ret - 1);
 | 
					    _name.assign(name_buf, ret - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hidraw_report_descriptor _rdesc{};
 | 
					    hidraw_report_descriptor _rdesc{};
 | 
				
			||||||
    if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &_rdesc.size))
 | 
					    if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &_rdesc.size))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int err = errno;
 | 
					        int err = errno;
 | 
				
			||||||
        ::close(fd);
 | 
					        ::close(fd);
 | 
				
			||||||
        throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESCSIZE failed");
 | 
					        throw std::system_error(err, std::system_category(),
 | 
				
			||||||
 | 
					                "RawDevice HIDIOCGRDESCSIZE failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (-1 == ::ioctl(fd, HIDIOCGRDESC, &_rdesc))
 | 
					    if (-1 == ::ioctl(fd, HIDIOCGRDESC, &_rdesc))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int err = errno;
 | 
					        int err = errno;
 | 
				
			||||||
        ::close(fd);
 | 
					        ::close(fd);
 | 
				
			||||||
        throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESC failed");
 | 
					        throw std::system_error(err, std::system_category(),
 | 
				
			||||||
 | 
					                "RawDevice HIDIOCGRDESC failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    rdesc = std::vector<uint8_t>(_rdesc.value, _rdesc.value + _rdesc.size);
 | 
					    rdesc = std::vector<uint8_t>(_rdesc.value, _rdesc.value + _rdesc.size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,7 +79,8 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int err = errno;
 | 
					        int err = errno;
 | 
				
			||||||
        close(fd);
 | 
					        close(fd);
 | 
				
			||||||
        throw std::system_error(err, std::system_category(), "RawDevice pipe open failed");
 | 
					        throw std::system_error(err, std::system_category(),
 | 
				
			||||||
 | 
					                "RawDevice pipe open failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    continue_listen = false;
 | 
					    continue_listen = false;
 | 
				
			||||||
@@ -92,8 +98,6 @@ RawDevice::~RawDevice()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
 | 
					std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(supportedReportID(report[0]));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* If the listener will stop, handle I/O manually.
 | 
					    /* If the listener will stop, handle I/O manually.
 | 
				
			||||||
     * Otherwise, push to queue and wait for result. */
 | 
					     * Otherwise, push to queue and wait for result. */
 | 
				
			||||||
    if(continue_listen)
 | 
					    if(continue_listen)
 | 
				
			||||||
@@ -189,11 +193,6 @@ std::vector<uint8_t> RawDevice::_respondToReport
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int RawDevice::_sendReport(const std::vector<uint8_t>& report)
 | 
					int RawDevice::_sendReport(const std::vector<uint8_t>& report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(dev_io);
 | 
					 | 
				
			||||||
    int ret = ::write(fd, report.data(), report.size());
 | 
					 | 
				
			||||||
    if(ret == -1)
 | 
					 | 
				
			||||||
        throw std::system_error(errno, std::system_category(), "_sendReport write failed");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(logid::global_verbosity == LogLevel::RAWREPORT) {
 | 
					    if(logid::global_verbosity == LogLevel::RAWREPORT) {
 | 
				
			||||||
        printf("[RAWREPORT] %s OUT: ", path.c_str());
 | 
					        printf("[RAWREPORT] %s OUT: ", path.c_str());
 | 
				
			||||||
        for(auto &i : report)
 | 
					        for(auto &i : report)
 | 
				
			||||||
@@ -201,6 +200,14 @@ int RawDevice::_sendReport(const std::vector<uint8_t>& report)
 | 
				
			|||||||
        printf("\n");
 | 
					        printf("\n");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(supportedReportID(report[0]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::lock_guard<std::mutex> lock(dev_io);
 | 
				
			||||||
 | 
					    int ret = ::write(fd, report.data(), report.size());
 | 
				
			||||||
 | 
					    if(ret == -1)
 | 
				
			||||||
 | 
					        throw std::system_error(errno, std::system_category(),
 | 
				
			||||||
 | 
					                "_sendReport write failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,13 +232,15 @@ int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLeng
 | 
				
			|||||||
    } while(ret == -1 && errno == EINTR);
 | 
					    } while(ret == -1 && errno == EINTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(ret == -1)
 | 
					    if(ret == -1)
 | 
				
			||||||
        throw std::system_error(errno, std::system_category(), "_readReport select failed");
 | 
					        throw std::system_error(errno, std::system_category(),
 | 
				
			||||||
 | 
					                "_readReport select failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(FD_ISSET(fd, &fds))
 | 
					    if(FD_ISSET(fd, &fds))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ret = read(fd, report.data(), report.size());
 | 
					        ret = read(fd, report.data(), report.size());
 | 
				
			||||||
        if(ret == -1)
 | 
					        if(ret == -1)
 | 
				
			||||||
            throw std::system_error(errno, std::system_category(), "_readReport read failed");
 | 
					            throw std::system_error(errno, std::system_category(),
 | 
				
			||||||
 | 
					                    "_readReport read failed");
 | 
				
			||||||
        report.resize(ret);
 | 
					        report.resize(ret);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -240,7 +249,8 @@ int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLeng
 | 
				
			|||||||
        char c;
 | 
					        char c;
 | 
				
			||||||
        ret = read(dev_pipe[0], &c, sizeof(char));
 | 
					        ret = read(dev_pipe[0], &c, sizeof(char));
 | 
				
			||||||
        if(ret == -1)
 | 
					        if(ret == -1)
 | 
				
			||||||
            throw std::system_error(errno, std::system_category(), "_readReport read pipe failed");
 | 
					            throw std::system_error(errno, std::system_category(),
 | 
				
			||||||
 | 
					                    "_readReport read pipe failed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(0 == ret)
 | 
					    if(0 == ret)
 | 
				
			||||||
@@ -260,7 +270,8 @@ void RawDevice::interruptRead()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    char c = 0;
 | 
					    char c = 0;
 | 
				
			||||||
    if(-1 == write(dev_pipe[1], &c, sizeof(char)))
 | 
					    if(-1 == write(dev_pipe[1], &c, sizeof(char)))
 | 
				
			||||||
        throw std::system_error(errno, std::system_category(), "interruptRead write pipe failed");
 | 
					        throw std::system_error(errno, std::system_category(),
 | 
				
			||||||
 | 
					                "interruptRead write pipe failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Ensure I/O has halted
 | 
					    // Ensure I/O has halted
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(dev_io);
 | 
					    std::lock_guard<std::mutex> lock(dev_io);
 | 
				
			||||||
@@ -302,7 +313,8 @@ void RawDevice::stopListener()
 | 
				
			|||||||
    interruptRead();
 | 
					    interruptRead();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RawDevice::addEventHandler(const std::string& nickname, RawEventHandler& handler)
 | 
					void RawDevice::addEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					        const std::shared_ptr<RawEventHandler>& handler)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    auto it = event_handlers.find(nickname);
 | 
					    auto it = event_handlers.find(nickname);
 | 
				
			||||||
    assert(it == event_handlers.end());
 | 
					    assert(it == event_handlers.end());
 | 
				
			||||||
@@ -314,11 +326,17 @@ void RawDevice::removeEventHandler(const std::string &nickname)
 | 
				
			|||||||
    event_handlers.erase(nickname);
 | 
					    event_handlers.erase(nickname);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const std::map<std::string, std::shared_ptr<RawEventHandler>>&
 | 
				
			||||||
 | 
					RawDevice::eventHandlers()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return event_handlers;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RawDevice::handleEvent(std::vector<uint8_t> &report)
 | 
					void RawDevice::handleEvent(std::vector<uint8_t> &report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    for(auto& handler : event_handlers)
 | 
					    for(auto& handler : event_handlers)
 | 
				
			||||||
        if(handler.second.condition(report))
 | 
					        if(handler.second->condition(report))
 | 
				
			||||||
            handler.second.callback(report);
 | 
					            handler.second->callback(report);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool RawDevice::isListening()
 | 
					bool RawDevice::isListening()
 | 
				
			||||||
@@ -328,5 +346,5 @@ bool RawDevice::isListening()
 | 
				
			|||||||
    if(ret)
 | 
					    if(ret)
 | 
				
			||||||
        listening.unlock();
 | 
					        listening.unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return !ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,9 +23,14 @@ namespace raw
 | 
				
			|||||||
    public:
 | 
					    public:
 | 
				
			||||||
        static bool supportedReportID(uint8_t id);
 | 
					        static bool supportedReportID(uint8_t id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        RawDevice(std::string path);
 | 
					        explicit RawDevice(std::string path);
 | 
				
			||||||
        ~RawDevice();
 | 
					        ~RawDevice();
 | 
				
			||||||
        std::string hidrawPath() const { return path; }
 | 
					        std::string hidrawPath() const { return path; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string name() const { return _name; }
 | 
				
			||||||
 | 
					        uint16_t vendorId() const { return vid; }
 | 
				
			||||||
 | 
					        uint16_t productId() const { return pid; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<uint8_t> reportDescriptor() const { return rdesc; }
 | 
					        std::vector<uint8_t> reportDescriptor() const { return rdesc; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
 | 
					        std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
 | 
				
			||||||
@@ -36,8 +41,11 @@ namespace raw
 | 
				
			|||||||
        void stopListener();
 | 
					        void stopListener();
 | 
				
			||||||
        bool isListening();
 | 
					        bool isListening();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void addEventHandler(const std::string& nickname, RawEventHandler& handler);
 | 
					        void addEventHandler(const std::string& nickname,
 | 
				
			||||||
 | 
					                const std::shared_ptr<backend::RawEventHandler>& handler);
 | 
				
			||||||
        void removeEventHandler(const std::string& nickname);
 | 
					        void removeEventHandler(const std::string& nickname);
 | 
				
			||||||
 | 
					        const std::map<std::string, std::shared_ptr<backend::RawEventHandler>>&
 | 
				
			||||||
 | 
					            eventHandlers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        std::mutex dev_io, listening;
 | 
					        std::mutex dev_io, listening;
 | 
				
			||||||
@@ -46,12 +54,13 @@ namespace raw
 | 
				
			|||||||
        int dev_pipe[2];
 | 
					        int dev_pipe[2];
 | 
				
			||||||
        uint16_t vid;
 | 
					        uint16_t vid;
 | 
				
			||||||
        uint16_t pid;
 | 
					        uint16_t pid;
 | 
				
			||||||
        std::string name;
 | 
					        std::string _name;
 | 
				
			||||||
        std::vector<uint8_t> rdesc;
 | 
					        std::vector<uint8_t> rdesc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::atomic<bool> continue_listen;
 | 
					        std::atomic<bool> continue_listen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::map<std::string, backend::RawEventHandler> event_handlers;
 | 
					        std::map<std::string, std::shared_ptr<backend::RawEventHandler>>
 | 
				
			||||||
 | 
					            event_handlers;
 | 
				
			||||||
        void handleEvent(std::vector<uint8_t>& report);
 | 
					        void handleEvent(std::vector<uint8_t>& report);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* These will only be used internally and processed with a queue */
 | 
					        /* These will only be used internally and processed with a queue */
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user