Implement raw DeviceMonitor

Multiple things have been done in this commit; the base of the new
backend has effectively been created. This branch currently has many
vital parts commented out. Therefore, this branch is currently only
intended for debugging.
This commit is contained in:
pixl 2020-06-16 19:53:38 -04:00
parent 526ffec61a
commit ec4ae56bc4
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
20 changed files with 797 additions and 78 deletions

View File

@ -11,66 +11,29 @@ find_package(PkgConfig REQUIRED)
add_executable(logid
logid.cpp
util.cpp
util.h
Configuration.cpp
Configuration.h
Actions.cpp
Actions.h
Device.cpp
Device.h
DeviceFinder.cpp
DeviceFinder.h
EvdevDevice.cpp
EvdevDevice.h)
DeviceMonitor.cpp
backend/raw/DeviceMonitor.cpp
backend/raw/RawDevice.cpp
backend/hidpp/Device.cpp
backend/hidpp/Report.cpp
backend/dj/Report.cpp)
set_target_properties(logid PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
pkg_check_modules(PC_EVDEV libevdev)
pkg_check_modules(PC_EVDEV libevdev REQUIRED)
pkg_check_modules(SYSTEMD "systemd")
pkg_check_modules(LIBCONFIG libconfig)
find_path(HIDPP_INCLUDE_DIR hidpp)
find_library(HIDPP_LIBRARY libhidpp.so)
pkg_check_modules(LIBCONFIG libconfig REQUIRED)
pkg_check_modules(LIBUDEV libudev REQUIRED)
find_path(EVDEV_INCLUDE_DIR libevdev/libevdev.h
HINTS ${PC_EVDEV_INCLUDE_DIRS} ${PC_EVDEV_INCLUDEDIR})
find_library(EVDEV_LIBRARY
NAMES evdev libevdev)
if((NOT HIDPP_INCLUDE_DIR) OR (NOT EXISTS ${HIDPP_INCLUDE_DIR}) OR (NOT HIDPP_LIBRARY) OR FORCE_BUILD_HIDPP)
message("Could not find libhidpp include dir, getting submodule")
include_directories(${HIDPP_INCLUDE_DIR} ${EVDEV_INCLUDE_DIR} ${DBUSCXX_INCLUDE_DIR} ${LIBUDEV_INCLUDE_DIRECTORIES})
execute_process(COMMAND git submodule update --init -- hidpp
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(DEFAULT_HID_BACKEND "linux")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(DEFAULT_HID_BACKEND "windows")
else()
message(WARNING "System is not supported")
endif()
set(HID_BACKEND "${DEFAULT_HID_BACKEND}" CACHE STRING "Backend used for accessing HID devices")
set_property(CACHE HID_BACKEND PROPERTY STRINGS linux windows)
if("${HID_BACKEND}" STREQUAL "linux")
pkg_check_modules(LIBUDEV libudev REQUIRED)
elseif("${HID_BACKEND}" STREQUAL "windows")
add_definitions(-DUNICODE -D_UNICODE)
add_definitions(-D_WIN32_WINNT=0x0600) # Use vista or later
else()
message(FATAL_ERROR "HID_BACKEND is invalid.")
endif()
add_subdirectory(hidpp/src/libhidpp)
set(HIDPP_INCLUDE_DIR "hidpp/src/libhidpp/")
set(HIDPP_LIBRARY hidpp)
else()
set(HIDPP_INCLUDE_DIR ${HIDPP_INCLUDE_DIR}/hidpp)
endif()
include_directories(${HIDPP_INCLUDE_DIR} ${EVDEV_INCLUDE_DIR})
target_link_libraries(logid ${CMAKE_THREAD_LIBS_INIT} ${EVDEV_LIBRARY} config++
${DBUSCXX_LIBRARIES} ${LIBUDEV_LIBRARIES})
target_link_libraries(logid ${CMAKE_THREAD_LIBS_INIT} ${EVDEV_LIBRARY} config++ ${HIDPP_LIBRARY})

View File

@ -2,7 +2,7 @@
#define LOGID_DEVICE_H
#include "Actions.h"
#include "DeviceFinder.h"
#include "DeviceMonitor.h"
#include "Configuration.h"
#include <map>

126
src/logid/DeviceMonitor.cpp Normal file
View File

@ -0,0 +1,126 @@
#include <thread>
#include <sstream>
#include "DeviceMonitor.h"
#include "util.h"
#define NON_WIRELESS_DEV(index) (index) == HIDPP::DefaultDevice ? "default" : "corded"
using namespace logid;
using namespace logid::backend;
/*
void stopAndDeleteConnectedDevice (ConnectedDevice &connected_device)
{
if(!connected_device.device->waiting_for_receiver)
log_printf(INFO, "%s (Device %d on %s) disconnected", connected_device.device->name.c_str(),
connected_device.device->index, connected_device.device->path.c_str());
connected_device.device->stop();
connected_device.associatedThread.join();
delete(connected_device.device);
}
DeviceMonitor::~DeviceMonitor()
{
this->devices_mutex.lock();
for (auto it = this->devices.begin(); it != this->devices.end(); it++) {
for (auto jt = it->second.begin(); jt != it->second.end(); jt++) {
stopAndDeleteConnectedDevice(jt->second);
}
}
this->devices_mutex.unlock();
}
Device* DeviceMonitor::insertNewDevice(const std::string &path, HIDPP::DeviceIndex index)
{
auto device = new Device(path, index);
device->init();
this->devices_mutex.lock();
log_printf(INFO, "%s detected: device %d on %s", device->name.c_str(), index, path.c_str());
auto path_bucket = this->devices.emplace(path, std::map<HIDPP::DeviceIndex, ConnectedDevice>()).first;
path_bucket->second.emplace(index, ConnectedDevice{
device,
std::thread([device]() {
device->start();
})
});
this->devices_mutex.unlock();
return device;
}
Device* DeviceMonitor::insertNewReceiverDevice(const std::string &path, HIDPP::DeviceIndex index)
{
auto *device = new Device(path, index);
this->devices_mutex.lock();
auto path_bucket = this->devices.emplace(path, std::map<HIDPP::DeviceIndex, ConnectedDevice>()).first;
path_bucket->second.emplace(index, ConnectedDevice{
device,
std::thread([device]() {
device->waitForReceiver();
})
});
this->devices_mutex.unlock();
return device;
}
void DeviceMonitor::stopAndDeleteAllDevicesIn (const std::string &path)
{
this->devices_mutex.lock();
auto path_bucket = this->devices.find(path);
if (path_bucket != this->devices.end())
{
for (auto& index_bucket : path_bucket->second) {
stopAndDeleteConnectedDevice(index_bucket.second);
}
this->devices.erase(path_bucket);
}
this->devices_mutex.unlock();
}
void DeviceMonitor::stopAndDeleteDevice (const std::string &path, HIDPP::DeviceIndex index)
{
this->devices_mutex.lock();
auto path_bucket = this->devices.find(path);
if (path_bucket != this->devices.end())
{
auto index_bucket = path_bucket->second.find(index);
if (index_bucket != path_bucket->second.end())
{
stopAndDeleteConnectedDevice(index_bucket->second);
path_bucket->second.erase(index_bucket);
}
}
this->devices_mutex.unlock();
log_printf(WARN, "Attempted to disconnect not previously connected device %d on %s", index, path.c_str());
}
*/
void DeviceMonitor::addDevice(std::string path)
{
try {
backend::hidpp::Device device(path, hidpp::DeviceIndex::DefaultDevice);
log_printf(DEBUG, "Detected HID++ device at %s", path.c_str());
}
catch(backend::hidpp::Device::InvalidDevice &e)
{
log_printf(DEBUG, "Detected device at %s but %s", path.c_str(), e.what());
}
catch(std::system_error &e)
{
log_printf(WARN, "Failed to open %s: %s", path.c_str(), e.what());
}
}
void DeviceMonitor::removeDevice(std::string path)
{
log_printf(DEBUG, "Device %s disconnected", path.c_str());
/*
ipc_server->removeReceiver(path);
this->stopAndDeleteAllDevicesIn(std::string(path));
*/
}

View File

@ -1,16 +1,12 @@
#ifndef LOGID_DEVICEFINDER_H
#define LOGID_DEVICEFINDER_H
#ifndef LOGID_DEVICEMONITOR_H
#define LOGID_DEVICEMONITOR_H
#include <hid/DeviceMonitor.h>
#include <hidpp/SimpleDispatcher.h>
#include <hidpp10/Device.h>
#include <hidpp10/IReceiver.h>
#include <hidpp20/IReprogControls.h>
#include <map>
#include <thread>
#include <mutex>
#include "Device.h"
#include "backend/raw/DeviceMonitor.h"
#include "backend/hidpp/Device.h"
#define MAX_CONNECTION_TRIES 10
#define TIME_BETWEEN_CONNECTION_TRIES 500ms
@ -25,24 +21,26 @@ namespace logid
std::thread associatedThread;
};
class DeviceFinder : public HID::DeviceMonitor
class DeviceMonitor : public backend::raw::DeviceMonitor
{
public:
~DeviceFinder();
~DeviceMonitor();
/*
Device* insertNewDevice (const std::string &path, HIDPP::DeviceIndex index);
Device* insertNewReceiverDevice (const std::string &path, HIDPP::DeviceIndex index);
void stopAndDeleteAllDevicesIn (const std::string &path);
void stopAndDeleteDevice (const std::string &path, HIDPP::DeviceIndex index);
*/
protected:
void addDevice(const char* path);
void removeDevice(const char* path);
void addDevice(std::string path) override;
void removeDevice(std::string path) override;
private:
std::mutex devices_mutex;
std::map<std::string, std::map<HIDPP::DeviceIndex, ConnectedDevice>> devices;
std::map<std::string, std::map<backend::hidpp::DeviceIndex, ConnectedDevice>> devices;
};
extern DeviceFinder* finder;
extern DeviceMonitor* finder;
}
#endif //LOGID_DEVICEFINDER_H

View File

@ -0,0 +1,32 @@
#include <array>
#include <algorithm>
#include "Report.h"
using namespace logid::backend::dj;
using namespace logid::backend;
static const std::array<uint8_t, 35> DJReportDesc = {
0xA1, 0x01, // Collection (Application)
0x85, 0x20, // Report ID (32)
0x95, 0x0E, // Report Count (14)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x41, // Usage (0x41)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x41, // Usage (0x41)
0x91, 0x00, // Output (Data, Array, Absolute)
0x85, 0x21, // Report ID (33)
0x95, 0x1F, // Report Count (31)
0x09, 0x42, // Usage (0x42)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x42, // Usage (0x42)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
bool dj::supportsDjReports(std::vector<uint8_t>& rdesc)
{
auto it = std::search(rdesc.begin(), rdesc.end(), DJReportDesc.begin(), DJReportDesc.end());
return it != rdesc.end();
}

View File

@ -0,0 +1,20 @@
#ifndef LOGID_BACKEND_DJ_REPORT_H
#define LOGID_BACKEND_DJ_REPORT_H
#include <cstdint>
#include "../raw/RawDevice.h"
namespace logid::backend::dj
{
bool supportsDjReports(std::vector<uint8_t>& rawDevice);
class Report
{
enum Type: uint8_t
{
Short = 0x20, // Short DJ reports use 12 byte parameters
Long = 0x21 // Long DJ reports use 29 byte parameters
};
};
}
#endif //LOGID_BACKEND_DJ_REPORT_H

View File

@ -0,0 +1,30 @@
#include "Device.h"
#include "Report.h"
using namespace logid::backend;
using namespace logid::backend::hidpp;
const char* Device::InvalidDevice::what() const noexcept
{
switch(_reason)
{
case NoHIDPPReport:
return "Invalid HID++ device";
case InvalidRawDevice:
return "Invalid raw device";
}
}
Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
{
return _reason;
}
/// TODO: Initialize a single RawDevice for each path.
Device::Device(std::string path, DeviceIndex index):
raw_device (std::make_shared<raw::RawDevice>(path)), path (path), index (index)
{
supported_reports = getSupportedReports(raw_device->reportDescriptor());
if(!supported_reports)
throw InvalidDevice(InvalidDevice::NoHIDPPReport);
}

View File

@ -0,0 +1,51 @@
#ifndef LOGID_HIDPP_DEVICE_H
#define LOGID_HIDPP_DEVICE_H
#include <string>
#include <memory>
#include "../raw/RawDevice.h"
namespace logid::backend::hidpp
{
enum DeviceIndex: uint8_t
{
DefaultDevice = 0,
WirelessDevice1 = 1,
WirelessDevice2 = 2,
WirelessDevice3 = 3,
WirelessDevice4 = 4,
WirelessDevice5 = 5,
WirelessDevice6 = 6,
CordedDevice = 0xff
};
class Device
{
public:
class InvalidDevice : std::exception
{
public:
enum Reason
{
NoHIDPPReport,
InvalidRawDevice
};
InvalidDevice(Reason reason) : _reason (reason) {}
virtual const char *what() const noexcept;
virtual Reason code() const noexcept;
private:
Reason _reason;
};
Device(std::string path, DeviceIndex index);
std::string devicePath() const { return path; }
DeviceIndex deviceIndex() const { return index; }
private:
std::shared_ptr<logid::backend::raw::RawDevice> raw_device;
std::string path;
DeviceIndex index;
uint8_t supported_reports;
};
}
#endif //LOGID_HIDPP_DEVICE_H

View File

View File

View File

@ -0,0 +1,83 @@
#include <array>
#include <algorithm>
#include "Report.h"
using namespace logid::backend::hidpp;
using namespace logid::backend;
/* Report descriptors were sourced from cvuchener/hidpp */
static const std::array<uint8_t, 22> ShortReportDesc = {
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
static const std::array<uint8_t, 22> LongReportDesc = {
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x75, 0x08, // Report Size (8)
0x95, 0x13, // Report Count (19)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
/* Alternative versions from the G602 */
static const std::array<uint8_t, 22> ShortReportDesc2 = {
0xA1, 0x01, // Collection (Application)
0x85, 0x10, // Report ID (16)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x01, // Usage (0001 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x01, // Usage (0001 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
static const std::array<uint8_t, 22> LongReportDesc2 = {
0xA1, 0x01, // Collection (Application)
0x85, 0x11, // Report ID (17)
0x95, 0x13, // Report Count (19)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0002 - Vendor)
0x81, 0x00, // Input (Data, Array, Absolute)
0x09, 0x02, // Usage (0002 - Vendor)
0x91, 0x00, // Output (Data, Array, Absolute)
0xC0 // End Collection
};
uint8_t hidpp::getSupportedReports(std::vector<uint8_t>&& rdesc)
{
uint8_t ret = 0;
auto it = std::search(rdesc.begin(), rdesc.end(), ShortReportDesc.begin(), ShortReportDesc.end());
if(it == rdesc.end())
it = std::search(rdesc.begin(), rdesc.end(), ShortReportDesc2.begin(), ShortReportDesc2.end());
if(it != rdesc.end())
ret |= HIDPP_REPORT_SHORT_SUPPORTED;
it = std::search(rdesc.begin(), rdesc.end(), LongReportDesc.begin(), LongReportDesc2.end());
if(it == rdesc.end())
it = std::search(rdesc.begin(), rdesc.end(), LongReportDesc2.begin(), LongReportDesc2.end());
if(it != rdesc.end())
ret |= HIDPP_REPORT_LONG_SUPPORTED;
return ret;
}

View File

@ -0,0 +1,57 @@
#ifndef LOGID_BACKEND_HIDPP_REPORT_H
#define LOGID_BACKEND_HIDPP_REPORT_H
#include <cstdint>
#include "../raw/RawDevice.h"
#include "Device.h"
#define LOGID_HIDPP_SW_ID 0x0f
/* Some devices only support a subset of these reports */
#define HIDPP_REPORT_SHORT_SUPPORTED 1U
#define HIDPP_REPORT_LONG_SUPPORTED 1U<<1U
/* Very long reports exist, however they have not been encountered so far */
namespace logid::backend::hidpp
{
uint8_t getSupportedReports(std::vector<uint8_t>&& rdesc);
class Report
{
public:
enum Type: uint8_t
{
Short = 0x10,
Long = 0x11
};
class InvalidReportID: std::exception
{
InvalidReportID();
virtual const char* what() const noexcept;
};
class InvalidReportLength: std::exception
{
InvalidReportLength();
virtual const char* what() const noexcept;
};
static constexpr std::size_t MaxDataLength = 32;
Report(uint8_t report_id, const uint8_t* data, std::size_t length);
Report(std::vector<uint8_t> data);
Type type() const;
void setType(Report::Type type);
logid::backend::hidpp::DeviceIndex deviceIndex();
std::vector<uint8_t> rawReport () const { return _data; }
private:
static constexpr std::size_t HeaderLength = 4;
std::vector<uint8_t> _data;
};
}
#endif //LOGID_BACKEND_HIDPP_REPORT_H

View File

@ -0,0 +1,133 @@
#include "DeviceMonitor.h"
#include <thread>
#include <system_error>
extern "C"
{
#include <unistd.h>
#include <libudev.h>
}
using namespace logid::backend::raw;
DeviceMonitor::DeviceMonitor()
{
if(-1 == pipe(monitor_pipe))
throw std::system_error(errno, std::system_category(), "pipe creation failed");
udev_context = udev_new();
if(!udev_context)
throw std::runtime_error("udev_new failed");
}
DeviceMonitor::~DeviceMonitor()
{
bool is_running = running.try_lock();
if(is_running)
running.unlock();
else
this->stop();
udev_unref(udev_context);
for(int i : monitor_pipe)
close(i);
}
void DeviceMonitor::run()
{
int ret;
const std::lock_guard<std::mutex> run_lock(running);
struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev_context, "udev");
if(!monitor)
throw std::runtime_error("udev_monitor_new_from_netlink failed");
ret = udev_monitor_filter_add_match_subsystem_devtype(monitor, "hidraw", nullptr);
if (0 != ret)
throw std::system_error (-ret, std::system_category (),
"udev_monitor_filter_add_match_subsystem_devtype");
ret = udev_monitor_enable_receiving(monitor);
if(0 != ret)
throw std::system_error(-ret, std::system_category(),
"udev_moniotr_enable_receiving");
this->enumerate();
int fd = udev_monitor_get_fd(monitor);
while (true) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(monitor_pipe[0], &fds);
FD_SET(fd, &fds);
if (-1 == select (std::max (monitor_pipe[0], fd)+1, &fds, nullptr, nullptr, nullptr)) {
if (errno == EINTR)
continue;
throw std::system_error (errno, std::system_category(), "udev_monitor select");
}
if (FD_ISSET(fd, &fds)) {
struct udev_device *device = udev_monitor_receive_device(monitor);
std::string action = udev_device_get_action(device);
std::string devnode = udev_device_get_devnode(device);
if (action == "add")
std::thread([this](const std::string name) {
this->addDevice(name);
}, devnode).detach();
else if (action == "remove")
std::thread([this](const std::string name) {
this->removeDevice(name);
}, devnode).detach();
udev_device_unref (device);
}
if (FD_ISSET(monitor_pipe[0], &fds)) {
char c;
if (-1 == read(monitor_pipe[0], &c, sizeof (char)))
throw std::system_error (errno, std::system_category (),
"read pipe");
break;
}
}
}
void DeviceMonitor::stop()
{
}
void DeviceMonitor::enumerate()
{
int ret;
struct udev_enumerate* udev_enum = udev_enumerate_new(udev_context);
ret = udev_enumerate_add_match_subsystem(udev_enum, "hidraw");
if(0 != ret)
throw std::system_error(-ret, std::system_category(),
"udev_enumerate_add_match_subsystem");
ret = udev_enumerate_scan_devices(udev_enum);
if(0 != ret)
throw std::system_error(-ret, std::system_category(),
"udev_enumerate_scan_devices");
struct udev_list_entry* udev_enum_entry;
udev_list_entry_foreach(udev_enum_entry,
udev_enumerate_get_list_entry(udev_enum))
{
const char* name = udev_list_entry_get_name(udev_enum_entry);
struct udev_device* device = udev_device_new_from_syspath(udev_context,
name);
if(!device)
throw std::runtime_error("udev_device_new_from_syspath failed");
std::string devnode = udev_device_get_devnode(device);
udev_device_unref(device);
std::thread([this](const std::string name) {
this->addDevice(name);
}, devnode).detach();
}
udev_enumerate_unref(udev_enum);
}

View File

@ -0,0 +1,32 @@
#ifndef LOGID_BACKEND_RAW_DEVICEMONITOR_H
#define LOGID_BACKEND_RAW_DEVICEMONITOR_H
#include <string>
#include <mutex>
extern "C"
{
#include <libudev.h>
}
namespace logid::backend::raw
{
class DeviceMonitor
{
public:
void enumerate();
void run();
void stop();
protected:
DeviceMonitor();
~DeviceMonitor();
virtual void addDevice(std::string device) = 0;
virtual void removeDevice(std::string device) = 0;
private:
struct udev* udev_context;
int monitor_pipe[2];
std::mutex running;
};
}
#endif //LOGID_BACKEND_RAW_DEVICEMONITOR_H

View File

@ -0,0 +1,147 @@
#include "RawDevice.h"
#include <string>
#include <system_error>
#include <utility>
extern "C"
{
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/hidraw.h>
}
using namespace logid::backend::raw;
using namespace std::chrono;
RawDevice::RawDevice(std::string path) : path (path)
{
int ret;
fd = ::open(path.c_str(), O_RDWR);
if (fd == -1)
throw std::system_error(errno, std::system_category(), "RawDevice open failed");
hidraw_devinfo devinfo{};
if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo))
{
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWINFO failed");
}
vid = devinfo.vendor;
pid = devinfo.product;
char name_buf[256];
if (-1 == (ret = ::ioctl(fd, HIDIOCGRAWNAME(sizeof(name_buf)), name_buf)))
{
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWNAME failed");
}
name.assign(name_buf, ret - 1);
hidraw_report_descriptor _rdesc{};
if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &_rdesc.size))
{
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESCSIZE failed");
}
if (-1 == ::ioctl(fd, HIDIOCGRDESC, &_rdesc))
{
int err = errno;
::close(fd);
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESC failed");
}
rdesc = std::vector<uint8_t>(_rdesc.value, _rdesc.value + _rdesc.size);
if (-1 == ::pipe(dev_pipe))
{
int err = errno;
close(fd);
throw std::system_error(err, std::system_category(), "RawDevice pipe open failed");
}
}
RawDevice::~RawDevice()
{
if(fd != -1)
{
::close(fd);
::close(dev_pipe[0]);
::close(dev_pipe[1]);
}
}
void RawDevice::sendReport(std::vector<uint8_t> report)
{
_sendReport(std::move(report));
}
std::vector<uint8_t> RawDevice::readReport(std::size_t maxDataLength)
{
return _readReport(maxDataLength);
}
void RawDevice::_sendReport(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");
}
std::vector<uint8_t> RawDevice::_readReport(std::size_t maxDataLength)
{
std::lock_guard<std::mutex> lock(dev_io);
int ret;
std::vector<uint8_t> report(maxDataLength);
timeval timeout = { duration_cast<milliseconds>(HIDPP_IO_TIMEOUT).count(),
duration_cast<microseconds>(HIDPP_IO_TIMEOUT).count() };
fd_set fds;
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
FD_SET(dev_pipe[0], &fds);
ret = select(std::max(fd, dev_pipe[0]) + 1,
&fds, nullptr, nullptr,
(HIDPP_IO_TIMEOUT.count() > 0 ? nullptr : &timeout));
} while(ret == -1 && errno == EINTR);
if(ret == -1)
throw std::system_error(errno, std::system_category(), "_readReport select failed");
if(FD_ISSET(fd, &fds))
{
ret = read(fd, report.data(), report.size());
if(ret == -1)
throw std::system_error(errno, std::system_category(), "_readReport read failed");
report.resize(ret);
}
if(FD_ISSET(dev_pipe[0], &fds))
{
char c;
ret = read(dev_pipe[0], &c, sizeof(char));
if(ret == -1)
throw std::system_error(errno, std::system_category(), "_readReport read pipe failed");
}
return report;
}
void RawDevice::interruptRead()
{
char c = 0;
if(-1 == write(dev_pipe[1], &c, sizeof(char)))
throw std::system_error(errno, std::system_category(), "interruptRead write pipe failed");
// Ensure I/O has halted
std::lock_guard<std::mutex> lock(dev_io);
}

View File

@ -0,0 +1,41 @@
#ifndef LOGID_BACKEND_RAWDEVICE_H
#define LOGID_BACKEND_RAWDEVICE_H
#include <string>
#include <vector>
#include <mutex>
#define HIDPP_IO_TIMEOUT std::chrono::seconds(2)
namespace logid::backend::raw
{
class RawDevice
{
public:
RawDevice(std::string path);
~RawDevice();
std::string hidrawPath() const { return path; }
std::vector<uint8_t> reportDescriptor() const { return rdesc; }
/// TODO: Process reports in a queue.
void sendReport(std::vector<uint8_t> report);
std::vector<uint8_t> readReport(std::size_t maxDataLength);
void interruptRead();
private:
std::mutex dev_io;
std::string path;
int fd;
int dev_pipe[2];
uint16_t vid;
uint16_t pid;
std::string name;
std::vector<uint8_t> rdesc;
/* These will only be used internally and processed with a queue */
void _sendReport(std::vector<uint8_t> report);
std::vector<uint8_t> _readReport(std::size_t maxDataLength);
};
}
#endif //LOGID_BACKEND_RAWDEVICE_H

View File

@ -4,12 +4,7 @@
#include <mutex>
#include "util.h"
#include "Device.h"
#include "Actions.h"
#include "Configuration.h"
#include "EvdevDevice.h"
#include "DeviceFinder.h"
#include "IPCServer.h"
#include "DeviceMonitor.h"
#include "logid.h"
#define evdev_name "logid"
@ -25,9 +20,8 @@ using namespace logid;
std::string config_file = DEFAULT_CONFIG_FILE;
LogLevel logid::global_verbosity = INFO;
Configuration* logid::global_config;
EvdevDevice* logid::global_evdev;
DeviceFinder* logid::finder;
// Configuration* logid::global_config;
DeviceMonitor* logid::finder;
bool logid::kill_logid = false;
std::mutex logid::finder_reloading;
@ -41,6 +35,7 @@ enum class Option
Version
};
/*
void logid::reload()
{
log_printf(INFO, "Reloading logid...");
@ -50,9 +45,10 @@ void logid::reload()
global_config = new Configuration(config_file.c_str());
delete(old_config);
delete(finder);
finder = new DeviceFinder();
finder = new DeviceMonitor();
finder_reloading.unlock();
}
*/
void read_cli_options(int argc, char** argv)
{
@ -153,10 +149,12 @@ int main(int argc, char** argv)
{
read_cli_options(argc, argv);
/*
// Read config
try { global_config = new Configuration(config_file.c_str()); }
catch (std::exception &e) { global_config = new Configuration(); }
//Create an evdev device called 'logid'
try { global_evdev = new EvdevDevice(evdev_name); }
catch(std::system_error& e)
@ -165,8 +163,10 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
*/
// Scan devices, create listeners, handlers, etc.
finder = new DeviceFinder();
finder = new DeviceMonitor();
while(!kill_logid)
{

View File

@ -5,7 +5,7 @@
namespace logid
{
void reload();
// void reload();
extern bool kill_logid;
extern std::mutex finder_reloading;

View File

@ -4,6 +4,7 @@
#include <cstdarg>
#include <cmath>
#include <algorithm>
#include <stdexcept>
#include "util.h"
@ -34,6 +35,7 @@ const char* logid::level_prefix(LogLevel level)
return "DEBUG";
}
/*
Direction logid::getDirection(int x, int y)
{
if(x == 0 && y == 0) return Direction::None;
@ -111,6 +113,8 @@ Action logid::stringToAction(std::string s)
throw std::invalid_argument(original_str + " is an invalid action.");
}
*/
LogLevel logid::stringToLogLevel(std::string s)
{
std::string original_str = s;

View File

@ -1,7 +1,7 @@
#ifndef LOGID_UTIL_H
#define LOGID_UTIL_H
#include "Actions.h"
//#include "Actions.h"
namespace logid
{
@ -19,10 +19,12 @@ namespace logid
const char* level_prefix(LogLevel level);
/*
Direction getDirection(int x, int y);
Direction stringToDirection(std::string s);
GestureMode stringToGestureMode(std::string s);
Action stringToAction(std::string s);
*/
LogLevel stringToLogLevel(std::string s);
}