Monitor all HID++ reports on wireless device 1

Again, many things were done in this commit such as implementing an
I/O queue, a mutex_queue, and implementing the hidpp::Report class.

I'm expecting commits to be like this until I can get a clean
codebase for the backend.
This commit is contained in:
pixl
2020-06-17 02:43:53 -04:00
parent 1de722b935
commit 6b895b3015
14 changed files with 442 additions and 55 deletions

View File

@@ -1,9 +1,11 @@
#include "RawDevice.h"
#include "../Error.h"
#include <string>
#include <system_error>
#include <utility>
#include <cassert>
#define MAX_DATA_LENGTH 32
extern "C"
{
@@ -76,29 +78,43 @@ RawDevice::~RawDevice()
}
}
void RawDevice::sendReport(std::vector<uint8_t> report)
std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
{
_sendReport(std::move(report));
std::packaged_task<std::vector<uint8_t>()> task(
[=]() {
_sendReport(report);
std::vector<uint8_t> response;
_readReport(response, MAX_DATA_LENGTH);
return response;
});
/* If the listener will stop, handle I/O manually.
* Otherwise, push to queue and wait for result. */
if(continue_listen)
{
auto f = task.get_future();
write_queue.push(&task);
return f.get();
}
else
return task.get_future().get();
}
std::vector<uint8_t> RawDevice::readReport(std::size_t maxDataLength)
{
return _readReport(maxDataLength);
}
void RawDevice::_sendReport(std::vector<uint8_t> report)
int RawDevice::_sendReport(const 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");
return ret;
}
std::vector<uint8_t> RawDevice::_readReport(std::size_t maxDataLength)
int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLength)
{
std::lock_guard<std::mutex> lock(dev_io);
int ret;
std::vector<uint8_t> report(maxDataLength);
report.resize(maxDataLength);
timeval timeout = { duration_cast<milliseconds>(HIDPP_IO_TIMEOUT).count(),
duration_cast<microseconds>(HIDPP_IO_TIMEOUT).count() };
@@ -133,7 +149,10 @@ std::vector<uint8_t> RawDevice::_readReport(std::size_t maxDataLength)
throw std::system_error(errno, std::system_category(), "_readReport read pipe failed");
}
return report;
if(0 == ret)
throw backend::TimeoutError();
return ret;
}
void RawDevice::interruptRead()
@@ -144,4 +163,62 @@ void RawDevice::interruptRead()
// Ensure I/O has halted
std::lock_guard<std::mutex> lock(dev_io);
}
}
void RawDevice::listen()
{
std::lock_guard<std::mutex> lock(listening);
continue_listen = true;
while(continue_listen)
{
while(!write_queue.empty())
{
auto task = write_queue.front();
(*task)();
write_queue.pop();
}
std::vector<uint8_t> report;
_readReport(report, MAX_DATA_LENGTH);
std::thread([this](std::vector<uint8_t> report) {
this->handleEvent(report);
}, report).detach();
}
continue_listen = false;
}
void RawDevice::stopListener()
{
continue_listen = false;
interruptRead();
}
void RawDevice::addEventHandler(const std::string &nickname, RawEventHandler &handler)
{
auto it = event_handlers.find(nickname);
assert(it == event_handlers.end());
event_handlers.emplace(nickname, handler);
}
void RawDevice::removeEventHandler(const std::string &nickname)
{
event_handlers.erase(nickname);
}
void RawDevice::handleEvent(std::vector<uint8_t> &report)
{
for(auto& handler : event_handlers)
if(handler.second.condition(report))
handler.second.callback(report);
}
bool RawDevice::isListening()
{
bool ret = listening.try_lock();
if(ret)
listening.unlock();
return ret;
}

View File

@@ -4,10 +4,18 @@
#include <string>
#include <vector>
#include <mutex>
#include <map>
#include <atomic>
#include <future>
#include "../defs.h"
#include "../../util/mutex_queue.h"
#define HIDPP_IO_TIMEOUT std::chrono::seconds(2)
namespace logid::backend::raw
namespace logid {
namespace backend {
namespace raw
{
class RawDevice
{
@@ -18,12 +26,18 @@ namespace logid::backend::raw
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);
std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
void interruptRead();
void listen();
void stopListener();
bool isListening();
void addEventHandler(const std::string& nickname, RawEventHandler& handler);
void removeEventHandler(const std::string& nickname);
private:
std::mutex dev_io;
std::mutex dev_io, listening;
std::string path;
int fd;
int dev_pipe[2];
@@ -32,10 +46,17 @@ namespace logid::backend::raw
std::string name;
std::vector<uint8_t> rdesc;
std::atomic<bool> continue_listen;
std::map<std::string, backend::RawEventHandler> event_handlers;
void handleEvent(std::vector<uint8_t>& report);
/* 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);
int _sendReport(const std::vector<uint8_t>& report);
int _readReport(std::vector<uint8_t>& report, std::size_t maxDataLength);
mutex_queue<std::packaged_task<std::vector<uint8_t>()>*> write_queue;
};
}
}}}
#endif //LOGID_BACKEND_RAWDEVICE_H