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.
master
pixl 4 years ago
parent 526ffec61a
commit ec4ae56bc4
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
  1. 63
      src/logid/CMakeLists.txt
  2. 2
      src/logid/Device.h
  3. 126
      src/logid/DeviceMonitor.cpp
  4. 28
      src/logid/DeviceMonitor.h
  5. 32
      src/logid/backend/dj/Report.cpp
  6. 20
      src/logid/backend/dj/Report.h
  7. 30
      src/logid/backend/hidpp/Device.cpp
  8. 51
      src/logid/backend/hidpp/Device.h
  9. 0
      src/logid/backend/hidpp/Error.cpp
  10. 0
      src/logid/backend/hidpp/Error.h
  11. 83
      src/logid/backend/hidpp/Report.cpp
  12. 57
      src/logid/backend/hidpp/Report.h
  13. 133
      src/logid/backend/raw/DeviceMonitor.cpp
  14. 32
      src/logid/backend/raw/DeviceMonitor.h
  15. 147
      src/logid/backend/raw/RawDevice.cpp
  16. 41
      src/logid/backend/raw/RawDevice.h
  17. 22
      src/logid/logid.cpp
  18. 2
      src/logid/logid.h
  19. 4
      src/logid/util.cpp
  20. 4
      src/logid/util.h

@ -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")
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} ${DBUSCXX_INCLUDE_DIR} ${LIBUDEV_INCLUDE_DIRECTORIES})
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})

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

@ -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));
*/
}

@ -1,16 +1,12 @@
#ifndef LOGID_DEVICEFINDER_H
#define LOGID_DEVICEFINDER_H
#include <hid/DeviceMonitor.h>
#include <hidpp/SimpleDispatcher.h>
#include <hidpp10/Device.h>
#include <hidpp10/IReceiver.h>
#include <hidpp20/IReprogControls.h>
#ifndef LOGID_DEVICEMONITOR_H
#define LOGID_DEVICEMONITOR_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

@ -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();
}

@ -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

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

@ -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

@ -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;
}

@ -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

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

@ -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

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

@ -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

@ -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)
{

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

@ -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;

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

Loading…
Cancel
Save