Add Device and Receiver signals to DeviceManager

This commit is contained in:
pixl 2022-01-08 00:05:32 -05:00
parent daa8c37c7d
commit 918ea63755
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
9 changed files with 467 additions and 41 deletions

@ -1 +1 @@
Subproject commit 89c6103af33705320494043da86c4709cc938b32
Subproject commit 0d53465fe70ab07e07f9f9d853413a6cc82704c6

View File

@ -32,37 +32,106 @@
using namespace logid;
using namespace logid::backend;
DeviceNickname::DeviceNickname(const std::shared_ptr<DeviceManager>& manager) :
_nickname (manager->newDeviceNickname()), _manager (manager)
{
}
DeviceNickname::operator std::string() const {
return std::to_string(_nickname);
}
DeviceNickname::~DeviceNickname()
{
if(auto manager = _manager.lock()) {
std::lock_guard<std::mutex> lock(manager->_nick_lock);
manager->_device_nicknames.erase(_nickname);
}
}
namespace logid {
class _Device : public Device {
public:
template <typename... Args>
_Device(Args... args) : Device(std::forward<Args>(args)...) { }
};
}
std::shared_ptr<Device> Device::make(
std::string path, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager)
{
auto ret = std::make_shared<_Device>(std::move(path),
index,
std::move(manager));
ret->_self = ret;
ret->_ipc_node->manage(ret);
ret->_ipc_interface = ret->_ipc_node->make_interface<DeviceIPC>(ret.get());
return ret;
}
std::shared_ptr<Device> Device::make(
std::shared_ptr<backend::raw::RawDevice> raw_device,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager)
{
auto ret = std::make_shared<_Device>(std::move(raw_device),
index,
std::move(manager));
ret->_self = ret;
ret->_ipc_node->manage(ret);
ret->_ipc_interface = ret->_ipc_node->make_interface<DeviceIPC>(ret.get());
return ret;
}
std::shared_ptr<Device> Device::make(
Receiver* receiver, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager)
{
auto ret = std::make_shared<_Device>(receiver, index, std::move(manager));
ret->_self = ret;
ret->_ipc_node->manage(ret);
ret->_ipc_interface = ret->_ipc_node->make_interface<DeviceIPC>(ret.get());
return ret;
}
Device::Device(std::string path, backend::hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager) :
std::shared_ptr<DeviceManager> manager) :
_hidpp20 (path, index,
manager->config()->ioTimeout(), manager->workQueue()),
_path (std::move(path)), _index (index),
_config (manager->config(), this),
_receiver (nullptr),
_manager (manager)
_manager (manager),
_nickname (manager),
_ipc_node(manager->devicesNode()->make_child(_nickname))
{
_init();
}
Device::Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
Device::Device(std::shared_ptr<backend::raw::RawDevice> raw_device,
hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager) :
std::shared_ptr<DeviceManager> manager) :
_hidpp20(raw_device, index),
_path (raw_device->hidrawPath()), _index (index),
_config (manager->config(), this),
_receiver (nullptr),
_manager (manager)
_manager (manager),
_nickname (manager),
_ipc_node (manager->devicesNode()->make_child(_nickname))
{
_init();
}
Device::Device(Receiver* receiver, hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager) :
std::shared_ptr<DeviceManager> manager) :
_hidpp20 (receiver->rawReceiver(), index),
_path (receiver->path()), _index (index),
_config (manager->config(), this),
_receiver (receiver),
_manager (manager)
_manager (manager),
_nickname (manager),
_ipc_node (manager->devicesNode()->make_child(_nickname))
{
_init();
}
@ -173,6 +242,12 @@ void Device::_makeResetMechanism()
}
}
Device::DeviceIPC::DeviceIPC(Device* device) :
ipcgull::interface("pizza.pixl.LogiOps.Device", {}, {}, {})
{
}
DeviceConfig::DeviceConfig(const std::shared_ptr<Configuration>& config, Device*
device) : _device (device), _config (config)
{

View File

@ -19,6 +19,8 @@
#ifndef LOGID_DEVICE_H
#define LOGID_DEVICE_H
#include <ipcgull/node.h>
#include <ipcgull/interface.h>
#include "backend/hidpp/defs.h"
#include "backend/hidpp20/Device.h"
#include "features/DeviceFeature.h"
@ -32,6 +34,19 @@ namespace logid
class Receiver;
class InputDevice;
class DeviceNickname {
public:
explicit DeviceNickname(const std::shared_ptr<DeviceManager>& manager);
DeviceNickname() = delete;
DeviceNickname(const DeviceNickname&) = delete;
~DeviceNickname();
operator std::string() const;
private:
const int _nickname;
const std::weak_ptr<DeviceManager> _manager;
};
class DeviceConfig
{
public:
@ -48,23 +63,28 @@ namespace logid
* Currently, the logid::Device class has a hardcoded requirement
* for an HID++ 2.0 device.
*/
class Device
class Device : public ipcgull::object
{
public:
Device(std::string path, backend::hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager);
Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
backend::hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager);
Device(Receiver* receiver, backend::hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager);
std::string name();
uint16_t pid();
DeviceConfig& config();
backend::hidpp20::Device& hidpp20();
static std::shared_ptr<Device> make(
std::string path,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
static std::shared_ptr<Device> make(
std::shared_ptr<backend::raw::RawDevice> raw_device,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
static std::shared_ptr<Device> make(
Receiver* receiver,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
void wakeup();
void sleep();
@ -89,6 +109,15 @@ namespace logid
}
private:
friend class _Device;
Device(std::string path, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
Device(std::shared_ptr<backend::raw::RawDevice> raw_device,
backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
Device(Receiver* receiver, backend::hidpp::DeviceIndex index,
std::shared_ptr<DeviceManager> manager);
void _init();
/* Adds a feature without calling an error if unsupported */
@ -113,6 +142,18 @@ namespace logid
void _makeResetMechanism();
std::unique_ptr<std::function<void()>> _reset_mechanism;
const DeviceNickname _nickname;
std::shared_ptr<ipcgull::node> _ipc_node;
class DeviceIPC : public ipcgull::interface {
public:
DeviceIPC(Device* device);
};
std::shared_ptr<ipcgull::interface> _ipc_interface;
std::weak_ptr<Device> _self;
};
}

View File

@ -41,18 +41,28 @@ namespace logid {
}
DeviceManager::DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<InputDevice> virtual_input) :
std::shared_ptr<InputDevice> virtual_input,
std::shared_ptr<ipcgull::server> server) :
backend::raw::DeviceMonitor(config->workerCount()),
_config (std::move(config)),
_virtual_input (std::move(virtual_input))
_server (std::move(server)), _config (std::move(config)),
_virtual_input (std::move(virtual_input)),
_root_node (ipcgull::node::make_root("")),
_device_node (ipcgull::node::make_root("devices")),
_receiver_node (ipcgull::node::make_root("receivers"))
{
_ipc_devices = _root_node->make_interface<DevicesIPC>();
_ipc_receivers = _root_node->make_interface<ReceiversIPC>();
_device_node->add_server(_server);
_receiver_node->add_server(_server);
_root_node->add_server(_server);
}
std::shared_ptr<DeviceManager> DeviceManager::make(
const std::shared_ptr<Configuration>& config,
const std::shared_ptr<InputDevice>& virtual_input)
const std::shared_ptr<InputDevice>& virtual_input,
const std::shared_ptr<ipcgull::server>& server)
{
auto ret = std::make_shared<_DeviceManager>(config, virtual_input);
auto ret = std::make_shared<_DeviceManager>(config, virtual_input, server);
ret->_self = ret;
return ret;
}
@ -67,6 +77,16 @@ std::shared_ptr<InputDevice> DeviceManager::virtualInput() const
return _virtual_input;
}
std::shared_ptr<const ipcgull::node> DeviceManager::devicesNode() const
{
return _device_node;
}
std::shared_ptr<const ipcgull::node> DeviceManager::receiversNode() const
{
return _receiver_node;
}
void DeviceManager::addDevice(std::string path)
{
bool defaultExists = true;
@ -102,21 +122,24 @@ void DeviceManager::addDevice(std::string path)
if(isReceiver) {
logPrintf(INFO, "Detected receiver at %s", path.c_str());
auto receiver = std::make_shared<Receiver>(path, _self.lock());
auto receiver = Receiver::make(path, _self.lock());
receiver->run();
_receivers.emplace(path, receiver);
_ipc_receivers->receiverAdded(receiver);
} else {
/* TODO: Can non-receivers only contain 1 device?
* If the device exists, it is guaranteed to be an HID++ 2.0 device */
if(defaultExists) {
auto device = std::make_shared<Device>(path, hidpp::DefaultDevice,
_self.lock());
auto device = Device::make(path, hidpp::DefaultDevice,
_self.lock());
_devices.emplace(path, device);
_ipc_devices->deviceAdded(device);
} else {
try {
auto device = std::make_shared<Device>(path,
auto device = Device::make(path,
hidpp::CordedDevice, _self.lock());
_devices.emplace(path, device);
_ipc_devices->deviceAdded(device);
} catch(hidpp10::Error &e) {
if(e.code() != hidpp10::Error::UnknownDevice)
throw;
@ -134,18 +157,152 @@ void DeviceManager::addDevice(std::string path)
}
}
void DeviceManager::addExternalDevice(const std::shared_ptr<Device> &d)
{
_ipc_devices->deviceAdded(d);
}
void DeviceManager::removeExternalDevice(const std::shared_ptr<Device> &d)
{
_ipc_devices->deviceRemoved(d);
}
void DeviceManager::removeDevice(std::string path)
{
auto receiver = _receivers.find(path);
if(receiver != _receivers.end()) {
_ipc_receivers->receiverRemoved(receiver->second);
_receivers.erase(receiver);
logPrintf(INFO, "Receiver on %s disconnected", path.c_str());
} else {
auto device = _devices.find(path);
if(device != _devices.end()) {
_ipc_devices->deviceRemoved(device->second);
_devices.erase(device);
logPrintf(INFO, "Device on %s disconnected", path.c_str());
}
}
}
DeviceManager::DevicesIPC::DevicesIPC() : ipcgull::interface(
"pizza.pixl.LogiOps.Devices",
{},
{},
{
{"deviceAdded",
ipcgull::make_signal<std::shared_ptr<Device>>(
{"device"})},
{"deviceRemoved",
ipcgull::make_signal<std::shared_ptr<Device>>(
{"device"})}
}
)
{
}
void DeviceManager::DevicesIPC::deviceAdded(
const std::shared_ptr<Device>& d) {
emit_signal("deviceAdded", d);
}
void DeviceManager::DevicesIPC::deviceRemoved(
const std::shared_ptr<Device>& d) {
emit_signal("deviceRemoved", d);
}
DeviceManager::ReceiversIPC::ReceiversIPC() : ipcgull::interface(
"pizza.pixl.LogiOps.Receivers",
{},
{},
{
{"receiverAdded",
ipcgull::make_signal<std::shared_ptr<Receiver>>(
{"device"})},
{"receiverRemoved",
ipcgull::make_signal<std::shared_ptr<Receiver>>(
{"device"})}
})
{
}
void DeviceManager::ReceiversIPC::receiverAdded(
const std::shared_ptr<Receiver>& r) {
emit_signal("receiverAdded", r);
}
void DeviceManager::ReceiversIPC::receiverRemoved(
const std::shared_ptr<Receiver>& r) {
emit_signal("receiverRemoved", r);
}
int DeviceManager::newDeviceNickname()
{
std::lock_guard<std::mutex> lock(_nick_lock);
auto begin = _device_nicknames.begin();
if(begin != _device_nicknames.end()) {
if(*begin != 0) {
_device_nicknames.insert(0);
return 0;
}
}
const auto i = std::adjacent_find(_device_nicknames.begin(),
_device_nicknames.end(),
[](int l, int r) { return l + 1 < r; });
if(i == _device_nicknames.end()) {
auto end = _device_nicknames.rbegin();
if(end != _device_nicknames.rend()) {
auto ret = *end + 1;
assert(ret > 0);
_device_nicknames.insert(ret);
return ret;
} else {
_device_nicknames.insert(0);
return 0;
}
}
auto ret = *i + 1;
assert(ret > 0);
_device_nicknames.insert(ret);
return ret;
}
int DeviceManager::newReceiverNickname()
{
std::lock_guard<std::mutex> lock(_nick_lock);
auto begin = _receiver_nicknames.begin();
if(begin != _receiver_nicknames.end()) {
if(*begin != 0) {
_receiver_nicknames.insert(0);
return 0;
}
}
const auto i = std::adjacent_find(_receiver_nicknames.begin(),
_receiver_nicknames.end(),
[](int l, int r) { return l + 1 < r; });
if(i == _receiver_nicknames.end()) {
auto end = _receiver_nicknames.rbegin();
if(end != _receiver_nicknames.rend()) {
auto ret = *end + 1;
assert(ret > 0);
_receiver_nicknames.insert(ret);
return ret;
} else {
_receiver_nicknames.insert(0);
return 0;
}
}
auto ret = *i + 1;
assert(ret > 0);
_receiver_nicknames.insert(ret);
return ret;
}

View File

@ -22,6 +22,8 @@
#include <map>
#include <thread>
#include <mutex>
#include <ipcgull/node.h>
#include <ipcgull/interface.h>
#include "backend/raw/DeviceMonitor.h"
#include "backend/hidpp/Device.h"
@ -38,21 +40,64 @@ namespace logid
public:
static std::shared_ptr<DeviceManager> make(
const std::shared_ptr<Configuration>& config,
const std::shared_ptr<InputDevice>& virtual_input);
const std::shared_ptr<InputDevice>& virtual_input,
const std::shared_ptr<ipcgull::server>& server);
[[nodiscard]] std::shared_ptr<Configuration> config() const;
[[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const;
[[nodiscard]] std::shared_ptr<const ipcgull::node> devicesNode() const;
[[nodiscard]] std::shared_ptr<const ipcgull::node>
receiversNode() const;
void addExternalDevice(const std::shared_ptr<Device>& d);
void removeExternalDevice(const std::shared_ptr<Device>& d);
protected:
void addDevice(std::string path) final;
void removeDevice(std::string path) final;
private:
class DevicesIPC : public ipcgull::interface {
public:
DevicesIPC();
void deviceAdded(const std::shared_ptr<Device>& d);
void deviceRemoved(const std::shared_ptr<Device>& d);
};
class ReceiversIPC : public ipcgull::interface {
public:
ReceiversIPC();
void receiverAdded(const std::shared_ptr<Receiver>& r);
void receiverRemoved(const std::shared_ptr<Receiver>& r);
};
friend class _DeviceManager;
DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<InputDevice> virtual_input);
std::shared_ptr<InputDevice> virtual_input,
std::shared_ptr<ipcgull::server> server);
std::weak_ptr<DeviceManager> _self;
std::shared_ptr<ipcgull::server> _server;
std::shared_ptr<Configuration> _config;
std::shared_ptr<InputDevice> _virtual_input;
std::shared_ptr<ipcgull::node> _root_node;
std::shared_ptr<ipcgull::node> _device_node;
std::shared_ptr<ipcgull::node> _receiver_node;
std::shared_ptr<DevicesIPC> _ipc_devices;
std::shared_ptr<ReceiversIPC> _ipc_receivers;
std::map<std::string, std::shared_ptr<Device>> _devices;
std::map<std::string, std::shared_ptr<Receiver>> _receivers;
friend class DeviceNickname;
friend class ReceiverNickname;
[[nodiscard]] int newDeviceNickname();
[[nodiscard]] int newReceiverNickname();
std::mutex _nick_lock;
std::set<int> _device_nicknames;
std::set<int> _receiver_nicknames;
};
}

View File

@ -56,6 +56,9 @@ InputDevice::InputDevice(const char* name)
}
}
for (unsigned int i = 0; i < REL_CNT; i++)
registered_axis[i] = false;
libevdev_enable_event_type(device, EV_REL);
int err = libevdev_uinput_create_from_device(device,
@ -76,7 +79,7 @@ InputDevice::~InputDevice()
void InputDevice::registerKey(uint code)
{
// TODO: Maybe print error message, if wrong code is passed?
if(registered_keys[code] || code > KEY_CNT) {
if(code >= KEY_CNT || registered_keys[code]) {
return;
}
@ -88,7 +91,7 @@ void InputDevice::registerKey(uint code)
void InputDevice::registerAxis(uint axis)
{
// TODO: Maybe print error message, if wrong code is passed?
if(registered_axis[axis] || axis > REL_CNT) {
if(axis >= REL_CNT || registered_axis[axis]) {
return;
}

View File

@ -26,15 +26,61 @@
using namespace logid;
using namespace logid::backend;
ReceiverNickname::ReceiverNickname(
const std::shared_ptr<DeviceManager>& manager) :
_nickname (manager->newReceiverNickname()), _manager (manager)
{
}
ReceiverNickname::operator std::string() const {
return std::to_string(_nickname);
}
ReceiverNickname::~ReceiverNickname()
{
if(auto manager = _manager.lock()) {
std::lock_guard<std::mutex> lock(manager->_nick_lock);
manager->_receiver_nicknames.erase(_nickname);
}
}
namespace logid {
class _Receiver : public Receiver {
public:
template <typename... Args>
_Receiver(Args... args) : Receiver(std::forward<Args>(args)...) { }
};
}
std::shared_ptr<Receiver> Receiver::make(
const std::string &path,
const std::shared_ptr<DeviceManager> &manager) {
auto ret = std::make_shared<_Receiver>(path, manager);
ret->_self = ret;
ret->_ipc_node->manage(ret);
return ret;
}
Receiver::Receiver(const std::string& path,
const std::shared_ptr<DeviceManager>& manager) :
dj::ReceiverMonitor(path,
manager->config()->ioTimeout(),
manager->workQueue()),
_path (path), _manager (manager)
_path (path), _manager (manager), _nickname (manager),
_ipc_node (manager->receiversNode()->make_child(_nickname)),
_ipc_interface (_ipc_node->make_interface<ReceiverIPC>(this))
{
}
Receiver::~Receiver()
{
if(auto manager = _manager.lock()) {
for(auto& d : _devices)
manager->removeExternalDevice(d.second);
}
}
void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
{
std::unique_lock<std::mutex> lock(_devices_change);
@ -77,10 +123,9 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
return;
}
std::shared_ptr<Device> device = std::make_shared<Device>(this,
event.index, manager);
auto device = Device::make(this, event.index, manager);
_devices.emplace(event.index, device);
manager->addExternalDevice(device);
} catch(hidpp10::Error &e) {
logPrintf(ERROR,
@ -100,7 +145,12 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
void Receiver::removeDevice(hidpp::DeviceIndex index)
{
std::unique_lock<std::mutex> lock(_devices_change);
_devices.erase(index);
auto device = _devices.find(index);
if(device != _devices.end()) {
if(auto manager = _manager.lock())
manager->removeExternalDevice(device->second);
_devices.erase(device);
}
}
const std::string& Receiver::path() const
@ -112,3 +162,8 @@ std::shared_ptr<dj::Receiver> Receiver::rawReceiver()
{
return receiver();
}
Receiver::ReceiverIPC::ReceiverIPC(Receiver *receiver) :
ipcgull::interface("pizza.pixl.LogiOps.Receiver", {}, {}, {})
{
}

View File

@ -25,21 +25,55 @@
namespace logid
{
class Receiver : public backend::dj::ReceiverMonitor
class ReceiverNickname {
public:
explicit ReceiverNickname(const std::shared_ptr<DeviceManager>& manager);
ReceiverNickname() = delete;
ReceiverNickname(const ReceiverNickname&) = delete;
~ReceiverNickname();
operator std::string() const;
private:
const int _nickname;
const std::weak_ptr<DeviceManager> _manager;
};
class Receiver : public backend::dj::ReceiverMonitor,
public ipcgull::object
{
public:
explicit Receiver(const std::string& path,
const std::shared_ptr<DeviceManager>& manager);
~Receiver();
static std::shared_ptr<Receiver> make(
const std::string& path,
const std::shared_ptr<DeviceManager>& manager);
const std::string& path() const;
std::shared_ptr<backend::dj::Receiver> rawReceiver();
protected:
void addDevice(backend::hidpp::DeviceConnectionEvent event) override;
void removeDevice(backend::hidpp::DeviceIndex index) override;
private:
friend class _Receiver;
Receiver(const std::string& path,
const std::shared_ptr<DeviceManager>& manager);
std::mutex _devices_change;
std::map<backend::hidpp::DeviceIndex, std::shared_ptr<Device>> _devices;
std::string _path;
std::weak_ptr<DeviceManager> _manager;
const ReceiverNickname _nickname;
std::shared_ptr<ipcgull::node> _ipc_node;
class ReceiverIPC : public ipcgull::interface {
public:
ReceiverIPC(Receiver* receiver);
};
std::shared_ptr<ipcgull::interface> _ipc_interface;
std::weak_ptr<Receiver> _self;
};
}

View File

@ -20,6 +20,7 @@
#include <cstdio>
#include <cstdlib>
#include <mutex>
#include <ipcgull/exception.h>
#include "util/log.h"
#include "DeviceManager.h"
@ -157,6 +158,19 @@ int main(int argc, char** argv)
std::shared_ptr<Configuration> config;
std::shared_ptr<InputDevice> virtual_input;
auto server = ipcgull::make_server("pizza.pixl.LogiOps",
"/pizza/pixl/logiops",
ipcgull::IPCGULL_USER);
std::thread( [server]() {
try {
server->start();
} catch(ipcgull::connection_failed& e) {
logPrintf(ERROR, "Lost IPC connection, terminating.");
std::terminate();
}
} ).detach();
// Read config
try {
config = std::make_shared<Configuration>(options.config_file);
@ -174,9 +188,11 @@ int main(int argc, char** argv)
}
// Scan devices, create listeners, handlers, etc.
auto device_manager = DeviceManager::make(config, virtual_input);
auto device_manager = DeviceManager::make(config, virtual_input, server);
device_manager->run();
server->stop_sync();
return EXIT_SUCCESS;
}