From 918ea63755a66d69373d7da431b61203fa878b41 Mon Sep 17 00:00:00 2001 From: pixl Date: Sat, 8 Jan 2022 00:05:32 -0500 Subject: [PATCH] Add Device and Receiver signals to DeviceManager --- src/ipcgull | 2 +- src/logid/Device.cpp | 89 ++++++++++++++++-- src/logid/Device.h | 59 ++++++++++-- src/logid/DeviceManager.cpp | 175 ++++++++++++++++++++++++++++++++++-- src/logid/DeviceManager.h | 51 ++++++++++- src/logid/InputDevice.cpp | 7 +- src/logid/Receiver.cpp | 67 ++++++++++++-- src/logid/Receiver.h | 40 ++++++++- src/logid/logid.cpp | 18 +++- 9 files changed, 467 insertions(+), 41 deletions(-) diff --git a/src/ipcgull b/src/ipcgull index 89c6103..0d53465 160000 --- a/src/ipcgull +++ b/src/ipcgull @@ -1 +1 @@ -Subproject commit 89c6103af33705320494043da86c4709cc938b32 +Subproject commit 0d53465fe70ab07e07f9f9d853413a6cc82704c6 diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 5788b95..5bfd7f4 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -32,37 +32,106 @@ using namespace logid; using namespace logid::backend; +DeviceNickname::DeviceNickname(const std::shared_ptr& 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 lock(manager->_nick_lock); + manager->_device_nicknames.erase(_nickname); + } +} + +namespace logid { + class _Device : public Device { + public: + template + _Device(Args... args) : Device(std::forward(args)...) { } + }; +} + +std::shared_ptr Device::make( + std::string path, backend::hidpp::DeviceIndex index, + std::shared_ptr 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(ret.get()); + return ret; +} + +std::shared_ptr Device::make( + std::shared_ptr raw_device, + backend::hidpp::DeviceIndex index, + std::shared_ptr 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(ret.get()); + return ret; +} + +std::shared_ptr Device::make( + Receiver* receiver, backend::hidpp::DeviceIndex index, + std::shared_ptr 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(ret.get()); + return ret; +} + Device::Device(std::string path, backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager) : + std::shared_ptr 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& raw_device, +Device::Device(std::shared_ptr raw_device, hidpp::DeviceIndex index, - const std::shared_ptr& manager) : + std::shared_ptr 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& manager) : + std::shared_ptr 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& config, Device* device) : _device (device), _config (config) { diff --git a/src/logid/Device.h b/src/logid/Device.h index fdb8c33..dcb1f53 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -19,6 +19,8 @@ #ifndef LOGID_DEVICE_H #define LOGID_DEVICE_H +#include +#include #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& manager); + DeviceNickname() = delete; + DeviceNickname(const DeviceNickname&) = delete; + ~DeviceNickname(); + + operator std::string() const; + private: + const int _nickname; + const std::weak_ptr _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& manager); - Device(const std::shared_ptr& raw_device, - backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager); - Device(Receiver* receiver, backend::hidpp::DeviceIndex index, - const std::shared_ptr& manager); - std::string name(); uint16_t pid(); DeviceConfig& config(); backend::hidpp20::Device& hidpp20(); + static std::shared_ptr make( + std::string path, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + static std::shared_ptr make( + std::shared_ptr raw_device, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + static std::shared_ptr make( + Receiver* receiver, + backend::hidpp::DeviceIndex index, + std::shared_ptr 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 manager); + Device(std::shared_ptr raw_device, + backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + Device(Receiver* receiver, backend::hidpp::DeviceIndex index, + std::shared_ptr manager); + void _init(); /* Adds a feature without calling an error if unsupported */ @@ -113,6 +142,18 @@ namespace logid void _makeResetMechanism(); std::unique_ptr> _reset_mechanism; + + const DeviceNickname _nickname; + std::shared_ptr _ipc_node; + + class DeviceIPC : public ipcgull::interface { + public: + DeviceIPC(Device* device); + }; + + std::shared_ptr _ipc_interface; + + std::weak_ptr _self; }; } diff --git a/src/logid/DeviceManager.cpp b/src/logid/DeviceManager.cpp index 37402d0..2cc806f 100644 --- a/src/logid/DeviceManager.cpp +++ b/src/logid/DeviceManager.cpp @@ -41,18 +41,28 @@ namespace logid { } DeviceManager::DeviceManager(std::shared_ptr config, - std::shared_ptr virtual_input) : + std::shared_ptr virtual_input, + std::shared_ptr 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(); + _ipc_receivers = _root_node->make_interface(); + _device_node->add_server(_server); + _receiver_node->add_server(_server); + _root_node->add_server(_server); } std::shared_ptr DeviceManager::make( const std::shared_ptr& config, - const std::shared_ptr& virtual_input) + const std::shared_ptr& virtual_input, + const std::shared_ptr& 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 DeviceManager::virtualInput() const return _virtual_input; } +std::shared_ptr DeviceManager::devicesNode() const +{ + return _device_node; +} + +std::shared_ptr 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(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(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(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 &d) +{ + _ipc_devices->deviceAdded(d); +} + +void DeviceManager::removeExternalDevice(const std::shared_ptr &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>( + {"device"})}, + {"deviceRemoved", + ipcgull::make_signal>( + {"device"})} + } + ) +{ +} + +void DeviceManager::DevicesIPC::deviceAdded( + const std::shared_ptr& d) { + emit_signal("deviceAdded", d); +} + +void DeviceManager::DevicesIPC::deviceRemoved( + const std::shared_ptr& d) { + emit_signal("deviceRemoved", d); +} + +DeviceManager::ReceiversIPC::ReceiversIPC() : ipcgull::interface( + "pizza.pixl.LogiOps.Receivers", + {}, + {}, + { + {"receiverAdded", + ipcgull::make_signal>( + {"device"})}, + {"receiverRemoved", + ipcgull::make_signal>( + {"device"})} + }) +{ +} + +void DeviceManager::ReceiversIPC::receiverAdded( + const std::shared_ptr& r) { + emit_signal("receiverAdded", r); +} + +void DeviceManager::ReceiversIPC::receiverRemoved( + const std::shared_ptr& r) { + emit_signal("receiverRemoved", r); +} + +int DeviceManager::newDeviceNickname() +{ + std::lock_guard 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 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; +} diff --git a/src/logid/DeviceManager.h b/src/logid/DeviceManager.h index 55c53f5..56e180e 100644 --- a/src/logid/DeviceManager.h +++ b/src/logid/DeviceManager.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "backend/raw/DeviceMonitor.h" #include "backend/hidpp/Device.h" @@ -38,23 +40,66 @@ namespace logid public: static std::shared_ptr make( const std::shared_ptr& config, - const std::shared_ptr& virtual_input); + const std::shared_ptr& virtual_input, + const std::shared_ptr& server); [[nodiscard]] std::shared_ptr config() const; [[nodiscard]] std::shared_ptr virtualInput() const; + [[nodiscard]] std::shared_ptr devicesNode() const; + [[nodiscard]] std::shared_ptr + receiversNode() const; + + void addExternalDevice(const std::shared_ptr& d); + void removeExternalDevice(const std::shared_ptr& 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& d); + void deviceRemoved(const std::shared_ptr& d); + }; + + class ReceiversIPC : public ipcgull::interface { + public: + ReceiversIPC(); + void receiverAdded(const std::shared_ptr& r); + void receiverRemoved(const std::shared_ptr& r); + }; + friend class _DeviceManager; DeviceManager(std::shared_ptr config, - std::shared_ptr virtual_input); + std::shared_ptr virtual_input, + std::shared_ptr server); + std::weak_ptr _self; + std::shared_ptr _server; std::shared_ptr _config; std::shared_ptr _virtual_input; + + std::shared_ptr _root_node; + + std::shared_ptr _device_node; + std::shared_ptr _receiver_node; + + std::shared_ptr _ipc_devices; + std::shared_ptr _ipc_receivers; + std::map> _devices; std::map> _receivers; + + friend class DeviceNickname; + friend class ReceiverNickname; + + [[nodiscard]] int newDeviceNickname(); + [[nodiscard]] int newReceiverNickname(); + + std::mutex _nick_lock; + std::set _device_nicknames; + std::set _receiver_nicknames; }; } -#endif //LOGID_DEVICEMANAGER_H \ No newline at end of file +#endif //LOGID_DEVICEMANAGER_H diff --git a/src/logid/InputDevice.cpp b/src/logid/InputDevice.cpp index 8bc93dc..131514c 100644 --- a/src/logid/InputDevice.cpp +++ b/src/logid/InputDevice.cpp @@ -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; } diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index 98a6459..cfd2f8f 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -26,15 +26,61 @@ using namespace logid; using namespace logid::backend; +ReceiverNickname::ReceiverNickname( + const std::shared_ptr& 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 lock(manager->_nick_lock); + manager->_receiver_nicknames.erase(_nickname); + } +} + +namespace logid { + class _Receiver : public Receiver { + public: + template + _Receiver(Args... args) : Receiver(std::forward(args)...) { } + }; +} + +std::shared_ptr Receiver::make( + const std::string &path, + const std::shared_ptr &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& 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(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 lock(_devices_change); @@ -77,10 +123,9 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) return; } - std::shared_ptr device = std::make_shared(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 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 @@ -111,4 +161,9 @@ const std::string& Receiver::path() const std::shared_ptr Receiver::rawReceiver() { return receiver(); -} \ No newline at end of file +} + +Receiver::ReceiverIPC::ReceiverIPC(Receiver *receiver) : + ipcgull::interface("pizza.pixl.LogiOps.Receiver", {}, {}, {}) +{ +} diff --git a/src/logid/Receiver.h b/src/logid/Receiver.h index 509113f..61c65c9 100644 --- a/src/logid/Receiver.h +++ b/src/logid/Receiver.h @@ -25,21 +25,55 @@ namespace logid { - class Receiver : public backend::dj::ReceiverMonitor + class ReceiverNickname { + public: + explicit ReceiverNickname(const std::shared_ptr& manager); + ReceiverNickname() = delete; + ReceiverNickname(const ReceiverNickname&) = delete; + ~ReceiverNickname(); + + operator std::string() const; + private: + const int _nickname; + const std::weak_ptr _manager; + }; + + class Receiver : public backend::dj::ReceiverMonitor, + public ipcgull::object { public: - explicit Receiver(const std::string& path, - const std::shared_ptr& manager); + ~Receiver(); + + static std::shared_ptr make( + const std::string& path, + const std::shared_ptr& manager); const std::string& path() const; std::shared_ptr 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& manager); + std::mutex _devices_change; std::map> _devices; std::string _path; std::weak_ptr _manager; + + const ReceiverNickname _nickname; + std::shared_ptr _ipc_node; + + class ReceiverIPC : public ipcgull::interface { + public: + ReceiverIPC(Receiver* receiver); + }; + + std::shared_ptr _ipc_interface; + + std::weak_ptr _self; }; } diff --git a/src/logid/logid.cpp b/src/logid/logid.cpp index 0352b1f..340fece 100644 --- a/src/logid/logid.cpp +++ b/src/logid/logid.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "util/log.h" #include "DeviceManager.h" @@ -157,6 +158,19 @@ int main(int argc, char** argv) std::shared_ptr config; std::shared_ptr 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(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; }