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:
pixl
2020-06-21 05:33:33 -04:00
parent b05e525bbc
commit e40da5f0c0
24 changed files with 689 additions and 181 deletions

View 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);
}
}

View 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

View 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);
});
}

View 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

View File

@@ -6,31 +6,59 @@ 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);
params[0] = feature_id & 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];
if(!info.feature_id)
throw UnsupportedFeature(feature_id);
info.hidden = response[1] & FeatureFlag::Hidden;
info.obsolete = response[1] & FeatureFlag::Obsolete;
info.internal = response[1] & FeatureFlag::Internal;
info.hidden = response[1] & Root::FeatureFlag::Hidden;
info.obsolete = response[1] & Root::FeatureFlag::Obsolete;
info.internal = response[1] & Root::FeatureFlag::Internal;
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::vector<uint8_t> params(0);
auto response = this->callFunction(Function::Ping, params);
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]);
}

View File

@@ -2,6 +2,7 @@
#define LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
#include "../Feature.h"
#include "../EssentialFeature.h"
#include "../feature_defs.h"
namespace logid {
@@ -24,7 +25,7 @@ namespace hidpp20
feature_info getFeature (uint16_t feature_id);
std::tuple<uint8_t, uint8_t> getVersion();
private:
enum FeatureFlag : uint8_t
{
Obsolete = 1<<7,
@@ -32,6 +33,18 @@ namespace hidpp20
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