Eliminate global variables

global_loglevel is kept for the time being and will be replaced
alongside the current logger.
This commit is contained in:
pixl 2022-01-07 19:43:41 -05:00
parent 23291ec382
commit 65fc252607
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
36 changed files with 277 additions and 144 deletions

View File

@ -58,7 +58,6 @@ namespace logid
libconfig::Config _config; libconfig::Config _config;
}; };
extern std::shared_ptr<Configuration> global_config;
} }
#endif //LOGID_CONFIGURATION_H #endif //LOGID_CONFIGURATION_H

View File

@ -20,6 +20,7 @@
#include "util/log.h" #include "util/log.h"
#include "features/DPI.h" #include "features/DPI.h"
#include "Device.h" #include "Device.h"
#include "DeviceManager.h"
#include "Receiver.h" #include "Receiver.h"
#include "features/SmartShift.h" #include "features/SmartShift.h"
#include "features/RemapButton.h" #include "features/RemapButton.h"
@ -31,24 +32,37 @@
using namespace logid; using namespace logid;
using namespace logid::backend; 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 (std::move(path)), _index (index), const std::shared_ptr<DeviceManager>& manager) :
_config (global_config, this), _receiver (nullptr) _hidpp20 (path, index,
manager->config()->ioTimeout(), manager->workQueue()),
_path (std::move(path)), _index (index),
_config (manager->config(), this),
_receiver (nullptr),
_manager (manager)
{ {
_init(); _init();
} }
Device::Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device, Device::Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
hidpp::DeviceIndex index) : _hidpp20(raw_device, index), _path hidpp::DeviceIndex index,
(raw_device->hidrawPath()), _index (index), const std::shared_ptr<DeviceManager>& manager) :
_config (global_config, this), _receiver (nullptr) _hidpp20(raw_device, index),
_path (raw_device->hidrawPath()), _index (index),
_config (manager->config(), this),
_receiver (nullptr),
_manager (manager)
{ {
_init(); _init();
} }
Device::Device(Receiver* receiver, hidpp::DeviceIndex index) : _hidpp20 Device::Device(Receiver* receiver, hidpp::DeviceIndex index,
(receiver->rawReceiver(), index), _path (receiver->path()), _index (index), const std::shared_ptr<DeviceManager>& manager) :
_config (global_config, this), _receiver (receiver) _hidpp20 (receiver->rawReceiver(), index),
_path (receiver->path()), _index (index),
_config (manager->config(), this),
_receiver (receiver),
_manager (manager)
{ {
_init(); _init();
} }
@ -111,6 +125,30 @@ void Device::reset()
"available.", _path.c_str(), _index); "available.", _path.c_str(), _index);
} }
std::shared_ptr<workqueue> Device::workQueue() const {
if(auto manager = _manager.lock()) {
return manager->workQueue();
} else {
logPrintf(ERROR, "Device manager lost");
logPrintf(ERROR,
"Fatal error occurred, file a bug report,"
" the program will now exit.");
std::terminate();
}
}
std::shared_ptr<InputDevice> Device::virtualInput() const {
if(auto manager = _manager.lock()) {
return manager->virtualInput();
} else {
logPrintf(ERROR, "Device manager lost");
logPrintf(ERROR,
"Fatal error occurred, file a bug report,"
" the program will now exit.");
std::terminate();
}
}
DeviceConfig& Device::config() DeviceConfig& Device::config()
{ {
return _config; return _config;

View File

@ -27,8 +27,10 @@
namespace logid namespace logid
{ {
class DeviceManager;
class Device; class Device;
class Receiver; class Receiver;
class InputDevice;
class DeviceConfig class DeviceConfig
{ {
@ -49,10 +51,13 @@ namespace logid
class Device class Device
{ {
public: public:
Device(std::string path, backend::hidpp::DeviceIndex index); Device(std::string path, backend::hidpp::DeviceIndex index,
const std::shared_ptr<DeviceManager>& manager);
Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device, Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
backend::hidpp::DeviceIndex index); backend::hidpp::DeviceIndex index,
Device(Receiver* receiver, 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(); std::string name();
uint16_t pid(); uint16_t pid();
@ -65,6 +70,10 @@ namespace logid
void reset(); void reset();
[[nodiscard]] std::shared_ptr<workqueue> workQueue() const;
[[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const;
template<typename T> template<typename T>
std::shared_ptr<T> getFeature(std::string name) { std::shared_ptr<T> getFeature(std::string name) {
auto it = _features.find(name); auto it = _features.find(name);
@ -100,6 +109,7 @@ namespace logid
DeviceConfig _config; DeviceConfig _config;
Receiver* _receiver; Receiver* _receiver;
const std::weak_ptr<DeviceManager> _manager;
void _makeResetMechanism(); void _makeResetMechanism();
std::unique_ptr<std::function<void()>> _reset_mechanism; std::unique_ptr<std::function<void()>> _reset_mechanism;

View File

@ -18,16 +18,55 @@
#include <thread> #include <thread>
#include <sstream> #include <sstream>
#include <utility>
#include "DeviceManager.h" #include "DeviceManager.h"
#include "Receiver.h" #include "Receiver.h"
#include "util/log.h" #include "util/log.h"
#include "util/workqueue.h"
#include "backend/hidpp10/Error.h" #include "backend/hidpp10/Error.h"
#include "backend/Error.h" #include "backend/Error.h"
using namespace logid; using namespace logid;
using namespace logid::backend; using namespace logid::backend;
namespace logid {
class _DeviceManager : public logid::DeviceManager
{
public:
template <typename... Args>
explicit _DeviceManager(Args... args) :
DeviceManager(std::forward<Args>(args)...) { }
};
}
DeviceManager::DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<InputDevice> virtual_input) :
backend::raw::DeviceMonitor(config->workerCount()),
_config (std::move(config)),
_virtual_input (std::move(virtual_input))
{
}
std::shared_ptr<DeviceManager> DeviceManager::make(
const std::shared_ptr<Configuration>& config,
const std::shared_ptr<InputDevice>& virtual_input)
{
auto ret = std::make_shared<_DeviceManager>(config, virtual_input);
ret->_self = ret;
return ret;
}
std::shared_ptr<Configuration> DeviceManager::config() const
{
return _config;
}
std::shared_ptr<InputDevice> DeviceManager::virtualInput() const
{
return _virtual_input;
}
void DeviceManager::addDevice(std::string path) void DeviceManager::addDevice(std::string path)
{ {
bool defaultExists = true; bool defaultExists = true;
@ -35,8 +74,8 @@ void DeviceManager::addDevice(std::string path)
// Check if device is ignored before continuing // Check if device is ignored before continuing
{ {
raw::RawDevice raw_dev(path); raw::RawDevice raw_dev(path, config()->ioTimeout(), workQueue());
if(global_config->isIgnored(raw_dev.productId())) { if(config()->isIgnored(raw_dev.productId())) {
logPrintf(DEBUG, "%s: Device 0x%04x ignored.", logPrintf(DEBUG, "%s: Device 0x%04x ignored.",
path.c_str(), raw_dev.productId()); path.c_str(), raw_dev.productId());
return; return;
@ -44,7 +83,8 @@ void DeviceManager::addDevice(std::string path)
} }
try { try {
hidpp::Device device(path, hidpp::DefaultDevice); hidpp::Device device(path, hidpp::DefaultDevice,
config()->ioTimeout(), workQueue());
isReceiver = device.version() == std::make_tuple(1, 0); isReceiver = device.version() == std::make_tuple(1, 0);
} catch(hidpp10::Error &e) { } catch(hidpp10::Error &e) {
if(e.code() != hidpp10::Error::UnknownDevice) if(e.code() != hidpp10::Error::UnknownDevice)
@ -62,19 +102,20 @@ void DeviceManager::addDevice(std::string path)
if(isReceiver) { if(isReceiver) {
logPrintf(INFO, "Detected receiver at %s", path.c_str()); logPrintf(INFO, "Detected receiver at %s", path.c_str());
auto receiver = std::make_shared<Receiver>(path); auto receiver = std::make_shared<Receiver>(path, _self.lock());
receiver->run(); receiver->run();
_receivers.emplace(path, receiver); _receivers.emplace(path, receiver);
} else { } else {
/* TODO: Can non-receivers only contain 1 device? /* TODO: Can non-receivers only contain 1 device?
* If the device exists, it is guaranteed to be an HID++ 2.0 device */ * If the device exists, it is guaranteed to be an HID++ 2.0 device */
if(defaultExists) { if(defaultExists) {
auto device = std::make_shared<Device>(path, hidpp::DefaultDevice); auto device = std::make_shared<Device>(path, hidpp::DefaultDevice,
_self.lock());
_devices.emplace(path, device); _devices.emplace(path, device);
} else { } else {
try { try {
auto device = std::make_shared<Device>(path, auto device = std::make_shared<Device>(path,
hidpp::CordedDevice); hidpp::CordedDevice, _self.lock());
_devices.emplace(path, device); _devices.emplace(path, device);
} catch(hidpp10::Error &e) { } catch(hidpp10::Error &e) {
if(e.code() != hidpp10::Error::UnknownDevice) if(e.code() != hidpp10::Error::UnknownDevice)

View File

@ -30,21 +30,31 @@
namespace logid namespace logid
{ {
class workqueue;
class InputDevice;
class DeviceManager : public backend::raw::DeviceMonitor class DeviceManager : public backend::raw::DeviceMonitor
{ {
public: public:
DeviceManager() = default; static std::shared_ptr<DeviceManager> make(
const std::shared_ptr<Configuration>& config,
const std::shared_ptr<InputDevice>& virtual_input);
[[nodiscard]] std::shared_ptr<Configuration> config() const;
[[nodiscard]] std::shared_ptr<InputDevice> virtualInput() const;
protected: protected:
void addDevice(std::string path) override; void addDevice(std::string path) final;
void removeDevice(std::string path) override; void removeDevice(std::string path) final;
private: private:
friend class _DeviceManager;
DeviceManager(std::shared_ptr<Configuration> config,
std::shared_ptr<InputDevice> virtual_input);
std::weak_ptr<DeviceManager> _self;
std::shared_ptr<Configuration> _config;
std::shared_ptr<InputDevice> _virtual_input;
std::map<std::string, std::shared_ptr<Device>> _devices; std::map<std::string, std::shared_ptr<Device>> _devices;
std::map<std::string, std::shared_ptr<Receiver>> _receivers; std::map<std::string, std::shared_ptr<Receiver>> _receivers;
}; };
extern std::unique_ptr<DeviceManager> device_manager;
} }
#endif //LOGID_DEVICEMANAGER_H #endif //LOGID_DEVICEMANAGER_H

View File

@ -65,8 +65,6 @@ namespace logid
libevdev* device; libevdev* device;
libevdev_uinput* ui_device{}; libevdev_uinput* ui_device{};
}; };
extern std::unique_ptr<InputDevice> virtual_input;
} }
#endif //LOGID_INPUTDEVICE_H #endif //LOGID_INPUTDEVICE_H

View File

@ -17,6 +17,7 @@
*/ */
#include "Receiver.h" #include "Receiver.h"
#include "DeviceManager.h"
#include "util/log.h" #include "util/log.h"
#include "backend/hidpp10/Error.h" #include "backend/hidpp10/Error.h"
#include "backend/hidpp20/Error.h" #include "backend/hidpp20/Error.h"
@ -25,17 +26,30 @@
using namespace logid; using namespace logid;
using namespace logid::backend; using namespace logid::backend;
Receiver::Receiver(const std::string& path) : Receiver::Receiver(const std::string& path,
dj::ReceiverMonitor(path), _path (path) const std::shared_ptr<DeviceManager>& manager) :
dj::ReceiverMonitor(path,
manager->config()->ioTimeout(),
manager->workQueue()),
_path (path), _manager (manager)
{ {
} }
void Receiver::addDevice(hidpp::DeviceConnectionEvent event) void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
{ {
std::unique_lock<std::mutex> lock(_devices_change); std::unique_lock<std::mutex> lock(_devices_change);
auto manager = _manager.lock();
if(!manager) {
logPrintf(ERROR, "Orphan Receiver, missing DeviceManager");
logPrintf(ERROR,
"Fatal error, file a bug report. Program will now exit.");
std::terminate();
}
try { try {
// Check if device is ignored before continuing // Check if device is ignored before continuing
if(global_config->isIgnored(event.pid)) { if(manager->config()->isIgnored(event.pid)) {
logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.", logPrintf(DEBUG, "%s:%d: Device 0x%04x ignored.",
_path.c_str(), event.index, event.pid); _path.c_str(), event.index, event.pid);
return; return;
@ -64,7 +78,7 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
} }
std::shared_ptr<Device> device = std::make_shared<Device>(this, std::shared_ptr<Device> device = std::make_shared<Device>(this,
event.index); event.index, manager);
_devices.emplace(event.index, device); _devices.emplace(event.index, device);

View File

@ -28,7 +28,8 @@ namespace logid
class Receiver : public backend::dj::ReceiverMonitor class Receiver : public backend::dj::ReceiverMonitor
{ {
public: public:
explicit Receiver(const std::string& path); explicit Receiver(const std::string& path,
const std::shared_ptr<DeviceManager>& manager);
const std::string& path() const; const std::string& path() const;
std::shared_ptr<backend::dj::Receiver> rawReceiver(); std::shared_ptr<backend::dj::Receiver> rawReceiver();
protected: protected:
@ -38,6 +39,7 @@ namespace logid
std::mutex _devices_change; std::mutex _devices_change;
std::map<backend::hidpp::DeviceIndex, std::shared_ptr<Device>> _devices; std::map<backend::hidpp::DeviceIndex, std::shared_ptr<Device>> _devices;
std::string _path; std::string _path;
std::weak_ptr<DeviceManager> _manager;
}; };
} }

View File

@ -39,7 +39,8 @@ void ChangeDPI::press()
{ {
_pressed = true; _pressed = true;
if(_dpi) { if(_dpi) {
task::spawn([this]{ task::spawn(_device->workQueue(),
[this]{
try { try {
uint16_t last_dpi = _dpi->getDPI(_config.sensor()); uint16_t last_dpi = _dpi->getDPI(_config.sensor());
_dpi->setDPI(last_dpi + _config.interval(), _config.sensor()); _dpi->setDPI(last_dpi + _config.interval(), _config.sensor());

View File

@ -44,7 +44,8 @@ void ChangeHostAction::press()
void ChangeHostAction::release() void ChangeHostAction::release()
{ {
if(_change_host) { if(_change_host) {
task::spawn([this] { task::spawn(_device->workQueue(),
[this] {
auto host_info = _change_host->getHostInfo(); auto host_info = _change_host->getHostInfo();
auto next_host = _config.nextHost(host_info); auto next_host = _config.nextHost(host_info);
if(next_host != host_info.currentHost) if(next_host != host_info.currentHost)

View File

@ -40,7 +40,8 @@ void CycleDPI::press()
{ {
_pressed = true; _pressed = true;
if(_dpi && !_config.empty()) { if(_dpi && !_config.empty()) {
task::spawn([this](){ task::spawn(_device->workQueue(),
[this](){
uint16_t dpi = _config.nextDPI(); uint16_t dpi = _config.nextDPI();
try { try {
_dpi->setDPI(dpi, _config.sensor()); _dpi->setDPI(dpi, _config.sensor());

View File

@ -16,6 +16,7 @@
* *
*/ */
#include "KeypressAction.h" #include "KeypressAction.h"
#include "../Device.h"
#include "../util/log.h" #include "../util/log.h"
#include "../InputDevice.h" #include "../InputDevice.h"
#include "../backend/hidpp20/features/ReprogControls.h" #include "../backend/hidpp20/features/ReprogControls.h"
@ -32,14 +33,14 @@ void KeypressAction::press()
{ {
_pressed = true; _pressed = true;
for(auto& key : _config.keys()) for(auto& key : _config.keys())
virtual_input->pressKey(key); _device->virtualInput()->pressKey(key);
} }
void KeypressAction::release() void KeypressAction::release()
{ {
_pressed = false; _pressed = false;
for(auto& key : _config.keys()) for(auto& key : _config.keys())
virtual_input->releaseKey(key); _device->virtualInput()->releaseKey(key);
} }
uint8_t KeypressAction::reprogFlags() const uint8_t KeypressAction::reprogFlags() const
@ -64,11 +65,13 @@ KeypressAction::Config::Config(Device* device, libconfig::Setting& config) :
auto& key = keys[i]; auto& key = keys[i];
if(key.isNumber()) { if(key.isNumber()) {
_keys.push_back(key); _keys.push_back(key);
virtual_input->registerKey(key); _device->virtualInput()->registerKey(key);
} else if(key.getType() == libconfig::Setting::TypeString) { } else if(key.getType() == libconfig::Setting::TypeString) {
try { try {
_keys.push_back(virtual_input->toKeyCode(key)); _keys.push_back(
virtual_input->registerKey(virtual_input->toKeyCode(key)); _device->virtualInput()->toKeyCode(key));
_device->virtualInput()->registerKey(
_device->virtualInput()->toKeyCode(key));
} catch(InputDevice::InvalidEventCode& e) { } catch(InputDevice::InvalidEventCode& e) {
logPrintf(WARN, "Line %d: Invalid keycode %s, skipping." logPrintf(WARN, "Line %d: Invalid keycode %s, skipping."
, key.getSourceLine(), key.c_str()); , key.getSourceLine(), key.c_str());

View File

@ -38,7 +38,8 @@ void ToggleHiresScroll::press()
_pressed = true; _pressed = true;
if(_hires_scroll) if(_hires_scroll)
{ {
task::spawn([hires=this->_hires_scroll](){ task::spawn(_device->workQueue(),
[hires=this->_hires_scroll](){
auto mode = hires->getMode(); auto mode = hires->getMode();
mode ^= backend::hidpp20::HiresScroll::HiRes; mode ^= backend::hidpp20::HiresScroll::HiRes;
hires->setMode(mode); hires->setMode(mode);

View File

@ -37,7 +37,8 @@ void ToggleSmartShift::press()
{ {
_pressed = true; _pressed = true;
if(_smartshift) { if(_smartshift) {
task::spawn([ss=this->_smartshift](){ task::spawn(_device->workQueue(),
[ss=this->_smartshift](){
auto status = ss->getStatus(); auto status = ss->getStatus();
status.setActive = true; status.setActive = true;
status.active = !status.active; status.active = !status.active;

View File

@ -17,6 +17,7 @@
*/ */
#include <cmath> #include <cmath>
#include "AxisGesture.h" #include "AxisGesture.h"
#include "../../Device.h"
#include "../../InputDevice.h" #include "../../InputDevice.h"
#include "../../util/log.h" #include "../../util/log.h"
@ -69,19 +70,19 @@ void AxisGesture::move(int16_t axis)
if(low_res_axis != -1) { if(low_res_axis != -1) {
int lowres_movement = 0, hires_movement = move_floor; int lowres_movement = 0, hires_movement = move_floor;
virtual_input->moveAxis(_config.axis(), hires_movement); _device->virtualInput()->moveAxis(_config.axis(), hires_movement);
hires_remainder += hires_movement; hires_remainder += hires_movement;
if(abs(hires_remainder) >= 60) { if(abs(hires_remainder) >= 60) {
lowres_movement = hires_remainder/120; lowres_movement = hires_remainder/120;
if(lowres_movement == 0) if(lowres_movement == 0)
lowres_movement = hires_remainder > 0 ? 1 : -1; lowres_movement = hires_remainder > 0 ? 1 : -1;
hires_remainder -= lowres_movement*120; hires_remainder -= lowres_movement*120;
virtual_input->moveAxis(low_res_axis, lowres_movement); _device->virtualInput()->moveAxis(low_res_axis, lowres_movement);
} }
_hires_remainder = hires_remainder; _hires_remainder = hires_remainder;
} else { } else {
virtual_input->moveAxis(_config.axis(), move_floor); _device->virtualInput()->moveAxis(_config.axis(), move_floor);
} }
} }
_axis = new_axis; _axis = new_axis;
@ -104,11 +105,11 @@ AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) :
auto& axis = setting.lookup("axis"); auto& axis = setting.lookup("axis");
if(axis.isNumber()) { if(axis.isNumber()) {
_axis = axis; _axis = axis;
virtual_input->registerAxis(_axis); _device->virtualInput()->registerAxis(_axis);
} else if(axis.getType() == libconfig::Setting::TypeString) { } else if(axis.getType() == libconfig::Setting::TypeString) {
try { try {
_axis = virtual_input->toAxisCode(axis); _axis = _device->virtualInput()->toAxisCode(axis);
virtual_input->registerAxis(_axis); _device->virtualInput()->registerAxis(_axis);
} catch(InputDevice::InvalidEventCode& e) { } catch(InputDevice::InvalidEventCode& e) {
logPrintf(WARN, "Line %d: Invalid axis %s, skipping." logPrintf(WARN, "Line %d: Invalid axis %s, skipping."
, axis.getSourceLine(), axis.c_str()); , axis.getSourceLine(), axis.c_str());
@ -143,7 +144,7 @@ AxisGesture::Config::Config(Device *device, libconfig::Setting &setting) :
int low_res_axis = InputDevice::getLowResAxis(_axis); int low_res_axis = InputDevice::getLowResAxis(_axis);
if(low_res_axis != -1) { if(low_res_axis != -1) {
_multiplier *= 120; _multiplier *= 120;
virtual_input->registerAxis(low_res_axis); _device->virtualInput()->registerAxis(low_res_axis);
} }
} }

View File

@ -44,8 +44,11 @@ InvalidReceiver::Reason InvalidReceiver::code() const noexcept
return _reason; return _reason;
} }
Receiver::Receiver(std::string path) : Receiver::Receiver(std::string path,
_raw_device (std::make_shared<raw::RawDevice>(std::move(path))), const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq) :
_raw_device (std::make_shared<raw::RawDevice>(
std::move(path), io_timeout, wq)),
_hidpp10_device (_raw_device, hidpp::DefaultDevice) _hidpp10_device (_raw_device, hidpp::DefaultDevice)
{ {
if(!supportsDjReports(_raw_device->reportDescriptor())) if(!supportsDjReports(_raw_device->reportDescriptor()))

View File

@ -52,7 +52,9 @@ namespace dj
class Receiver final class Receiver final
{ {
public: public:
explicit Receiver(std::string path); Receiver(std::string path,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq);
enum DjEvents : uint8_t enum DjEvents : uint8_t
{ {

View File

@ -25,8 +25,12 @@
using namespace logid::backend::dj; using namespace logid::backend::dj;
ReceiverMonitor::ReceiverMonitor(std::string path) : _receiver ( ReceiverMonitor::ReceiverMonitor(
std::make_shared<Receiver>(std::move(path))) std::string path,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq) :
_workqueue (wq),
_receiver (std::make_shared<Receiver>(std::move(path), io_timeout, wq))
{ {
assert(_receiver->hidppEventHandlers().find("RECVMON") == assert(_receiver->hidppEventHandlers().find("RECVMON") ==
_receiver->hidppEventHandlers().end()); _receiver->hidppEventHandlers().end());
@ -62,14 +66,15 @@ void ReceiverMonitor::run()
/* Running in a new thread prevents deadlocks since the /* Running in a new thread prevents deadlocks since the
* receiver may be enumerating. * receiver may be enumerating.
*/ */
task::spawn({[this, report]() { task::spawn(_workqueue,
[this, report]() {
if (report.subId() == Receiver::DeviceConnection) if (report.subId() == Receiver::DeviceConnection)
this->addDevice(this->_receiver->deviceConnectionEvent this->addDevice(this->_receiver->deviceConnectionEvent
(report)); (report));
else if (report.subId() == Receiver::DeviceDisconnection) else if (report.subId() == Receiver::DeviceDisconnection)
this->removeDevice(this->_receiver-> this->removeDevice(this->_receiver->
deviceDisconnectionEvent(report)); deviceDisconnectionEvent(report));
}}, {[report, path=this->_receiver->rawDevice()->hidrawPath()] }, {[report, path=this->_receiver->rawDevice()->hidrawPath()]
(std::exception& e) { (std::exception& e) {
if(report.subId() == Receiver::DeviceConnection) if(report.subId() == Receiver::DeviceConnection)
logPrintf(ERROR, "Failed to add device %d to receiver " logPrintf(ERROR, "Failed to add device %d to receiver "
@ -117,7 +122,8 @@ void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index)
event.index = index; event.index = index;
event.fromTimeoutCheck = true; event.fromTimeoutCheck = true;
task::spawn({[this, event, nickname]() { task::spawn(_workqueue,
{[this, event, nickname]() {
_receiver->rawDevice()->removeEventHandler(nickname); _receiver->rawDevice()->removeEventHandler(nickname);
this->addDevice(event); this->addDevice(event);
}}, {[path=_receiver->rawDevice()->hidrawPath(), event] }}, {[path=_receiver->rawDevice()->hidrawPath(), event]

View File

@ -32,7 +32,9 @@ namespace dj
class ReceiverMonitor class ReceiverMonitor
{ {
public: public:
explicit ReceiverMonitor(std::string path); ReceiverMonitor(std::string path,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq);
virtual ~ReceiverMonitor(); virtual ~ReceiverMonitor();
void enumerate(); void enumerate();
@ -53,6 +55,7 @@ namespace dj
std::shared_ptr<Receiver> receiver() const; std::shared_ptr<Receiver> receiver() const;
private: private:
std::shared_ptr<workqueue> _workqueue;
std::shared_ptr<Receiver> _receiver; std::shared_ptr<Receiver> _receiver;
}; };

View File

@ -49,9 +49,11 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
return _reason; return _reason;
} }
Device::Device(const std::string& path, DeviceIndex index): Device::Device(const std::string& path, DeviceIndex index,
_raw_device (std::make_shared<raw::RawDevice>(path)), _receiver (nullptr), const std::chrono::milliseconds& io_timeout,
_path (path), _index (index) const std::shared_ptr<workqueue>& wq):
_raw_device (std::make_shared<raw::RawDevice>(path, io_timeout, wq)),
_receiver (nullptr), _path (path), _index (index)
{ {
_init(); _init();
} }

View File

@ -61,7 +61,9 @@ namespace hidpp
Reason _reason; Reason _reason;
}; };
explicit Device(const std::string& path, DeviceIndex index); Device(const std::string& path, DeviceIndex index,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq);
Device(std::shared_ptr<raw::RawDevice> raw_device, Device(std::shared_ptr<raw::RawDevice> raw_device,
DeviceIndex index); DeviceIndex index);
Device(std::shared_ptr<dj::Receiver> receiver, Device(std::shared_ptr<dj::Receiver> receiver,

View File

@ -24,8 +24,10 @@
using namespace logid::backend; using namespace logid::backend;
using namespace logid::backend::hidpp10; using namespace logid::backend::hidpp10;
Device::Device(const std::string &path, hidpp::DeviceIndex index) : Device::Device(const std::string &path, hidpp::DeviceIndex index,
hidpp::Device(path, index) const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq) :
hidpp::Device(path, index, io_timeout, wq)
{ {
assert(version() == std::make_tuple(1, 0)); assert(version() == std::make_tuple(1, 0));
} }

View File

@ -28,7 +28,9 @@ namespace hidpp10
class Device : public hidpp::Device class Device : public hidpp::Device
{ {
public: public:
Device(const std::string& path, hidpp::DeviceIndex index); Device(const std::string& path, hidpp::DeviceIndex index,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq);
Device(std::shared_ptr<raw::RawDevice> raw_dev, Device(std::shared_ptr<raw::RawDevice> raw_dev,
hidpp::DeviceIndex index); hidpp::DeviceIndex index);
Device(std::shared_ptr<dj::Receiver> receiver, Device(std::shared_ptr<dj::Receiver> receiver,

View File

@ -23,13 +23,16 @@
using namespace logid::backend::hidpp20; using namespace logid::backend::hidpp20;
Device::Device(std::string path, hidpp::DeviceIndex index) Device::Device(std::string path, hidpp::DeviceIndex index,
: hidpp::Device(path, index) const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq) :
hidpp::Device(path, index, io_timeout, wq)
{ {
assert(std::get<0>(version()) >= 2); assert(std::get<0>(version()) >= 2);
} }
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index) Device::Device(std::shared_ptr<raw::RawDevice> raw_device,
hidpp::DeviceIndex index)
: hidpp::Device(raw_device, index) : hidpp::Device(raw_device, index)
{ {
assert(std::get<0>(version()) >= 2); assert(std::get<0>(version()) >= 2);

View File

@ -28,7 +28,9 @@ namespace hidpp20 {
class Device : public hidpp::Device class Device : public hidpp::Device
{ {
public: public:
Device(std::string path, hidpp::DeviceIndex index); Device(std::string path, hidpp::DeviceIndex index,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq);
Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index); Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index);
Device(std::shared_ptr<dj::Receiver> receiver, hidpp::DeviceIndex Device(std::shared_ptr<dj::Receiver> receiver, hidpp::DeviceIndex
index); index);

View File

@ -18,6 +18,7 @@
#include "DeviceMonitor.h" #include "DeviceMonitor.h"
#include "../../util/task.h" #include "../../util/task.h"
#include "../../util/workqueue.h"
#include "../../util/log.h" #include "../../util/log.h"
#include "RawDevice.h" #include "RawDevice.h"
#include "../hidpp/Device.h" #include "../hidpp/Device.h"
@ -31,9 +32,11 @@ extern "C"
#include <libudev.h> #include <libudev.h>
} }
using namespace logid;
using namespace logid::backend::raw; using namespace logid::backend::raw;
DeviceMonitor::DeviceMonitor() DeviceMonitor::DeviceMonitor(int worker_count) :
_workqueue (std::make_shared<workqueue>(worker_count))
{ {
if(-1 == pipe(_pipe)) if(-1 == pipe(_pipe))
throw std::system_error(errno, std::system_category(), throw std::system_error(errno, std::system_category(),
@ -100,7 +103,8 @@ void DeviceMonitor::run()
std::string devnode = udev_device_get_devnode(device); std::string devnode = udev_device_get_devnode(device);
if (action == "add") if (action == "add")
task::spawn([this, name=devnode]() { task::spawn(_workqueue,
[this, name=devnode]() {
// Wait for device to initialise // Wait for device to initialise
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto supported_reports = backend::hidpp::getSupportedReports( auto supported_reports = backend::hidpp::getSupportedReports(
@ -115,7 +119,8 @@ void DeviceMonitor::run()
name.c_str(), e.what()); name.c_str(), e.what());
}); });
else if (action == "remove") else if (action == "remove")
task::spawn([this, name=devnode]() { task::spawn(_workqueue,
[this, name=devnode]() {
this->removeDevice(name); this->removeDevice(name);
}, [name=devnode](std::exception& e){ }, [name=devnode](std::exception& e){
logPrintf(WARN, "Error removing device %s: %s", logPrintf(WARN, "Error removing device %s: %s",
@ -167,7 +172,8 @@ void DeviceMonitor::enumerate()
std::string devnode = udev_device_get_devnode(device); std::string devnode = udev_device_get_devnode(device);
udev_device_unref(device); udev_device_unref(device);
task::spawn([this, name=devnode]() { task::spawn(_workqueue,
[this, name=devnode]() {
auto supported_reports = backend::hidpp::getSupportedReports( auto supported_reports = backend::hidpp::getSupportedReports(
RawDevice::getReportDescriptor(name)); RawDevice::getReportDescriptor(name));
if(supported_reports) if(supported_reports)
@ -182,4 +188,8 @@ void DeviceMonitor::enumerate()
} }
udev_enumerate_unref(udev_enum); udev_enumerate_unref(udev_enum);
} }
std::shared_ptr<workqueue> DeviceMonitor::workQueue() const {
return _workqueue;
}

View File

@ -22,13 +22,12 @@
#include <string> #include <string>
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <memory>
extern "C" struct udev;
{
#include <libudev.h>
}
namespace logid { namespace logid {
class workqueue;
namespace backend { namespace backend {
namespace raw namespace raw
{ {
@ -38,8 +37,10 @@ namespace raw
void enumerate(); void enumerate();
void run(); void run();
void stop(); void stop();
std::shared_ptr<workqueue> workQueue() const;
protected: protected:
DeviceMonitor(); explicit DeviceMonitor(int worker_count);
virtual ~DeviceMonitor(); virtual ~DeviceMonitor();
virtual void addDevice(std::string device) = 0; virtual void addDevice(std::string device) = 0;
virtual void removeDevice(std::string device) = 0; virtual void removeDevice(std::string device) = 0;
@ -48,6 +49,7 @@ namespace raw
int _pipe[2]; int _pipe[2];
std::atomic<bool> _run_monitor; std::atomic<bool> _run_monitor;
std::mutex _running; std::mutex _running;
std::shared_ptr<workqueue> _workqueue;
}; };
}}} }}}

View File

@ -64,8 +64,13 @@ bool RawDevice::supportedReport(uint8_t id, uint8_t length)
} }
} }
RawDevice::RawDevice(std::string path) : _path (std::move(path)), RawDevice::RawDevice(std::string path,
_continue_listen (false), _continue_respond (false) const milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq) :
_path (std::move(path)),
_continue_listen (false), _continue_respond (false),
_io_timeout (io_timeout),
_workqueue (wq)
{ {
int ret; int ret;
@ -189,7 +194,7 @@ std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
_io_queue.push(task); _io_queue.push(task);
interruptRead(false); // Alert listener to prioritise interruptRead(false); // Alert listener to prioritise
cv.wait(lock, [&top_of_queue]{ return top_of_queue; }); cv.wait(lock, [&top_of_queue]{ return top_of_queue; });
auto status = f.wait_for(global_config->ioTimeout()); auto status = f.wait_for(_io_timeout);
if(status == std::future_status::timeout) { if(status == std::future_status::timeout) {
_continue_respond = false; _continue_respond = false;
interruptRead(); interruptRead();
@ -210,9 +215,9 @@ std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
_exception = std::make_exception_ptr(e); _exception = std::make_exception_ptr(e);
} }
}); });
global_workqueue->queue(t); _workqueue->queue(t);
t->waitStart(); t->waitStart();
auto status = t->waitFor(global_config->ioTimeout()); auto status = t->waitFor(_io_timeout);
if(_exception) if(_exception)
std::rethrow_exception(_exception); std::rethrow_exception(_exception);
if(status == std::future_status::timeout) { if(status == std::future_status::timeout) {
@ -257,7 +262,7 @@ std::vector<uint8_t> RawDevice::_respondToReport
while(_continue_respond) { while(_continue_respond) {
std::vector<uint8_t> response; std::vector<uint8_t> response;
auto current_point = std::chrono::steady_clock::now(); auto current_point = std::chrono::steady_clock::now();
auto timeout = global_config->ioTimeout() - std::chrono::duration_cast auto timeout = _io_timeout - std::chrono::duration_cast
<std::chrono::milliseconds>(current_point - start_point); <std::chrono::milliseconds>(current_point - start_point);
if(timeout.count() <= 0) if(timeout.count() <= 0)
throw TimeoutError(); throw TimeoutError();
@ -337,7 +342,7 @@ int RawDevice::_sendReport(const std::vector<uint8_t>& report)
int RawDevice::_readReport(std::vector<uint8_t> &report, int RawDevice::_readReport(std::vector<uint8_t> &report,
std::size_t maxDataLength) std::size_t maxDataLength)
{ {
return _readReport(report, maxDataLength, global_config->ioTimeout()); return _readReport(report, maxDataLength, _io_timeout);
} }
int RawDevice::_readReport(std::vector<uint8_t> &report, int RawDevice::_readReport(std::vector<uint8_t> &report,
@ -348,10 +353,10 @@ int RawDevice::_readReport(std::vector<uint8_t> &report,
report.resize(maxDataLength); report.resize(maxDataLength);
timeval timeout_tv{}; timeval timeout_tv{};
timeout_tv.tv_sec = duration_cast<seconds>(global_config->ioTimeout()) timeout_tv.tv_sec = duration_cast<seconds>(_io_timeout)
.count(); .count();
timeout_tv.tv_usec = duration_cast<microseconds>( timeout_tv.tv_usec = duration_cast<microseconds>(
global_config->ioTimeout()).count() % _io_timeout).count() %
duration_cast<microseconds>(seconds(1)).count(); duration_cast<microseconds>(seconds(1)).count();
auto timeout_ms = duration_cast<milliseconds>(timeout).count(); auto timeout_ms = duration_cast<milliseconds>(timeout).count();

View File

@ -31,6 +31,8 @@
#include "../../util/mutex_queue.h" #include "../../util/mutex_queue.h"
namespace logid { namespace logid {
class workqueue;
namespace backend { namespace backend {
namespace raw namespace raw
{ {
@ -39,7 +41,9 @@ namespace raw
public: public:
static bool supportedReport(uint8_t id, uint8_t length); static bool supportedReport(uint8_t id, uint8_t length);
explicit RawDevice(std::string path); explicit RawDevice(std::string path,
const std::chrono::milliseconds& io_timeout,
const std::shared_ptr<workqueue>& wq);
~RawDevice(); ~RawDevice();
std::string hidrawPath() const; std::string hidrawPath() const;
@ -80,6 +84,9 @@ namespace raw
std::atomic<bool> _continue_respond; std::atomic<bool> _continue_respond;
std::condition_variable _listen_condition; std::condition_variable _listen_condition;
const std::chrono::milliseconds _io_timeout;
const std::shared_ptr<workqueue> _workqueue;
std::map<std::string, std::shared_ptr<RawEventHandler>> std::map<std::string, std::shared_ptr<RawEventHandler>>
_event_handlers; _event_handlers;
std::mutex _event_handler_lock; std::mutex _event_handler_lock;

View File

@ -62,7 +62,7 @@ void DeviceStatus::listen()
auto event = hidpp20::WirelessDeviceStatus::statusBroadcastEvent( auto event = hidpp20::WirelessDeviceStatus::statusBroadcastEvent(
report); report);
if(event.reconfNeeded) if(event.reconfNeeded)
task::spawn([dev](){ dev->wakeup(); }); task::spawn(dev->workQueue(), [dev](){ dev->wakeup(); });
}; };
_device->hidpp20().addEventHandler(EVENTHANDLER_NAME, handler); _device->hidpp20().addEventHandler(EVENTHANDLER_NAME, handler);

View File

@ -23,7 +23,6 @@
#include "util/log.h" #include "util/log.h"
#include "DeviceManager.h" #include "DeviceManager.h"
#include "logid.h"
#include "InputDevice.h" #include "InputDevice.h"
#include "util/workqueue.h" #include "util/workqueue.h"
@ -43,13 +42,6 @@ struct CmdlineOptions
}; };
LogLevel logid::global_loglevel = INFO; LogLevel logid::global_loglevel = INFO;
std::shared_ptr<Configuration> logid::global_config;
std::unique_ptr<DeviceManager> logid::device_manager;
std::unique_ptr<InputDevice> logid::virtual_input;
std::shared_ptr<workqueue> logid::global_workqueue;
bool logid::kill_logid = false;
std::mutex logid::device_manager_reload;
enum class Option enum class Option
{ {
@ -162,16 +154,16 @@ int main(int argc, char** argv)
{ {
CmdlineOptions options{}; CmdlineOptions options{};
readCliOptions(argc, argv, options); readCliOptions(argc, argv, options);
std::shared_ptr<Configuration> config;
std::shared_ptr<InputDevice> virtual_input;
// Read config // Read config
try { try {
global_config = std::make_shared<Configuration>(options.config_file); config = std::make_shared<Configuration>(options.config_file);
} }
catch (std::exception &e) { catch (std::exception &e) {
global_config = std::make_shared<Configuration>(); config = std::make_shared<Configuration>();
} }
global_workqueue = std::make_shared<workqueue>(
global_config->workerCount());
//Create a virtual input device //Create a virtual input device
try { try {
@ -182,13 +174,9 @@ int main(int argc, char** argv)
} }
// Scan devices, create listeners, handlers, etc. // Scan devices, create listeners, handlers, etc.
device_manager = std::make_unique<DeviceManager>(); auto device_manager = DeviceManager::make(config, virtual_input);
while(!kill_logid) { device_manager->run();
device_manager_reload.lock();
device_manager_reload.unlock();
device_manager->run();
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,32 +0,0 @@
/*
* Copyright 2019-2020 PixlOne
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LOGID_LOGID_H
#define LOGID_LOGID_H
#include <mutex>
namespace logid
{
// void reload();
extern bool kill_logid;
extern std::mutex device_manager_reload;
}
#endif //LOGID_LOGID_H

View File

@ -22,6 +22,8 @@
namespace logid namespace logid
{ {
/// TODO: Replace with a safer object-oriented logger
enum LogLevel enum LogLevel
{ {
RAWREPORT, RAWREPORT,

View File

@ -72,9 +72,10 @@ std::future_status task::waitFor(std::chrono::milliseconds ms)
return _future.wait_for(ms); return _future.wait_for(ms);
} }
void task::spawn(const std::function<void ()>& function, void task::spawn(std::shared_ptr<workqueue> wq,
const std::function<void (std::exception &)>& exception_handler) const std::function<void ()>& function,
const std::function<void (std::exception&)>& exception_handler)
{ {
auto t = std::make_shared<task>(function, exception_handler); auto t = std::make_shared<task>(function, exception_handler);
global_workqueue->queue(t); wq->queue(t);
} }

View File

@ -25,6 +25,8 @@
namespace logid namespace logid
{ {
class workqueue;
class task class task
{ {
public: public:
@ -50,7 +52,8 @@ namespace logid
/* This function spawns a new task into the least used worker queue /* This function spawns a new task into the least used worker queue
* and forgets about it. * and forgets about it.
*/ */
static void spawn(const std::function<void()>& function, static void spawn(std::shared_ptr<workqueue> wq,
const std::function<void()>& function,
const std::function<void(std::exception&)>& const std::function<void(std::exception&)>&
exception_handler={[](std::exception& e) exception_handler={[](std::exception& e)
{ExceptionHandler::Default(e);}}); {ExceptionHandler::Default(e);}});

View File

@ -52,7 +52,6 @@ namespace logid
std::size_t _worker_count; std::size_t _worker_count;
}; };
extern std::shared_ptr<workqueue> global_workqueue;
} }
#endif //LOGID_WORKQUEUE_H #endif //LOGID_WORKQUEUE_H