Rewrite logid::DeviceMonitor
This commit is contained in:
		@@ -12,6 +12,8 @@ add_executable(logid
 | 
				
			|||||||
        logid.cpp
 | 
					        logid.cpp
 | 
				
			||||||
        util.cpp
 | 
					        util.cpp
 | 
				
			||||||
        DeviceMonitor.cpp
 | 
					        DeviceMonitor.cpp
 | 
				
			||||||
 | 
					        Device.cpp
 | 
				
			||||||
 | 
					        Receiver.cpp
 | 
				
			||||||
        backend/Error.cpp
 | 
					        backend/Error.cpp
 | 
				
			||||||
        backend/raw/DeviceMonitor.cpp
 | 
					        backend/raw/DeviceMonitor.cpp
 | 
				
			||||||
        backend/raw/RawDevice.cpp
 | 
					        backend/raw/RawDevice.cpp
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,551 +1,20 @@
 | 
				
			|||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <future>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <hidpp/SimpleDispatcher.h>
 | 
					 | 
				
			||||||
#include <hidpp20/IAdjustableDPI.h>
 | 
					 | 
				
			||||||
#include <hidpp20/IFeatureSet.h>
 | 
					 | 
				
			||||||
#include <hidpp20/Error.h>
 | 
					 | 
				
			||||||
#include <hidpp20/IReprogControls.h>
 | 
					 | 
				
			||||||
#include <hidpp20/IReset.h>
 | 
					 | 
				
			||||||
#include <hidpp20/ISmartShift.h>
 | 
					 | 
				
			||||||
#include <hidpp20/Device.h>
 | 
					 | 
				
			||||||
#include <hidpp10/Error.h>
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <cstring>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
#include <set>
 | 
					 | 
				
			||||||
#include <hidpp20/UnsupportedFeature.h>
 | 
					 | 
				
			||||||
#include <hidpp20/IHiresScroll.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Device.h"
 | 
					 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
#include "EvdevDevice.h"
 | 
					#include "Device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace logid;
 | 
					using namespace logid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std::chrono_literals;
 | 
					Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
 | 
				
			||||||
 | 
					    _hidpp20 (path, index), _path (path), _index (index)
 | 
				
			||||||
Device::Device(std::string p, const HIDPP::DeviceIndex i) : path(std::move(p)), index (i)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    disconnected = true;
 | 
					    log_printf(DEBUG, "logid::Device created on %s:%d");
 | 
				
			||||||
    dispatcher = new HIDPP::SimpleDispatcher(path.c_str());
 | 
					 | 
				
			||||||
    listener = new SimpleListener(new HIDPP::SimpleDispatcher(path.c_str()), index);
 | 
					 | 
				
			||||||
    config = new DeviceConfig();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Device::init()
 | 
					void Device::sleep()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Initialise variables
 | 
					    log_printf(INFO, "%s:%d fell asleep.", _path.c_str(), _index);
 | 
				
			||||||
    disconnected = false;
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        hidpp_dev = new HIDPP20::Device(dispatcher, index);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP10::Error &e) { return false; }
 | 
					 | 
				
			||||||
    catch(HIDPP20::Error &e) { return false; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    name = hidpp_dev->name();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(std::find(global_config->blacklist.begin(), global_config->blacklist.end(),
 | 
					 | 
				
			||||||
                 hidpp_dev->productID()) != global_config->blacklist.end())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(INFO, "Ignored blacklisted device %s", name.c_str());
 | 
					 | 
				
			||||||
        throw BlacklistedDevice();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    features = getFeatures();
 | 
					void Device::wakeup()
 | 
				
			||||||
    // Set config, if none is found for this device then use default
 | 
					 | 
				
			||||||
    if(global_config->devices.find(name) == global_config->devices.end())
 | 
					 | 
				
			||||||
        log_printf(INFO, "Device %s not configured, using default config.", hidpp_dev->name().c_str());
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        delete(config);
 | 
					    log_printf(INFO, "%s:%d woke up.", _path.c_str(), _index);
 | 
				
			||||||
        config = global_config->devices.find(name)->second;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    initialized = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Device::~Device()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(!disconnected)
 | 
					 | 
				
			||||||
        this->reset();
 | 
					 | 
				
			||||||
    if(!config->baseConfig)
 | 
					 | 
				
			||||||
        delete(this->config);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::configure()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(config->baseConfig)
 | 
					 | 
				
			||||||
        config = new DeviceConfig(config, this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(!configuring.try_lock())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(DEBUG, "%s %d: skip config task", path.c_str(), index);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    usleep(500000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(disconnected)
 | 
					 | 
				
			||||||
            goto ret;
 | 
					 | 
				
			||||||
        // Divert buttons
 | 
					 | 
				
			||||||
        divert_buttons();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(disconnected)
 | 
					 | 
				
			||||||
            goto ret;
 | 
					 | 
				
			||||||
        // Set DPI if it is configured
 | 
					 | 
				
			||||||
        if(config->dpi != nullptr)
 | 
					 | 
				
			||||||
            setDPI(*config->dpi);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(disconnected)
 | 
					 | 
				
			||||||
            goto ret;
 | 
					 | 
				
			||||||
        // Set Smartshift if it is configured
 | 
					 | 
				
			||||||
        if(config->smartshift != nullptr)
 | 
					 | 
				
			||||||
            setSmartShift(*config->smartshift);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(disconnected)
 | 
					 | 
				
			||||||
            goto ret;
 | 
					 | 
				
			||||||
        // Set Hires Scroll if it is configured
 | 
					 | 
				
			||||||
        if(config->hiresscroll != nullptr)
 | 
					 | 
				
			||||||
            setHiresScroll(*config->hiresscroll);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP10::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(ERROR, "HID++ 1.0 Error whjle configuring %s: %s", name.c_str(), e.what());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ret:
 | 
					 | 
				
			||||||
    configuring.unlock();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::reset()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        HIDPP20::IReset iReset(hidpp_dev);
 | 
					 | 
				
			||||||
        iReset.reset();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP20::UnsupportedFeature &e) { }
 | 
					 | 
				
			||||||
    catch(HIDPP10::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(ERROR, "Failed to reset %s: %s", name.c_str(), e.what());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::divert_buttons()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        HIDPP20::IReprogControls irc = HIDPP20::IReprogControls::auto_version(hidpp_dev);
 | 
					 | 
				
			||||||
        if(disconnected)
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        int controlCount = irc.getControlCount();
 | 
					 | 
				
			||||||
        for(int i = 0; i < controlCount; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(disconnected)
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            uint16_t cid = irc.getControlInfo(i).control_id;
 | 
					 | 
				
			||||||
            uint8_t flags = 0;
 | 
					 | 
				
			||||||
            flags |= HIDPP20::IReprogControls::ChangeTemporaryDivert;
 | 
					 | 
				
			||||||
            flags |= HIDPP20::IReprogControls::ChangeRawXYDivert;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            auto action = config->actions.find(cid);
 | 
					 | 
				
			||||||
            if(action != config->actions.end())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                flags |= HIDPP20::IReprogControls::ChangeTemporaryDivert;
 | 
					 | 
				
			||||||
                flags |= HIDPP20::IReprogControls::TemporaryDiverted;
 | 
					 | 
				
			||||||
                if(action->second->type == Action::Gestures)
 | 
					 | 
				
			||||||
                    flags |= HIDPP20::IReprogControls::RawXYDiverted;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(disconnected)
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            irc.setControlReporting(cid, flags, cid);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP20::UnsupportedFeature &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(DEBUG, "%s does not support Reprog controls, not diverting!", name.c_str());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP20::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(e.errorCode() == HIDPP20::Error::InvalidFunctionID) {
 | 
					 | 
				
			||||||
            // Not really an error, the device does not support diverting buttons
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            log_printf(ERROR, "Could not divert buttons: HID++ 2.0 Error %s!", e.what());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP10::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(DEBUG, "Could not divert buttons: HID++ 1.0 Error %s!", e.what());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::setSmartShift(HIDPP20::ISmartShift::SmartshiftStatus ops)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(disconnected) return;
 | 
					 | 
				
			||||||
        HIDPP20::ISmartShift ss(hidpp_dev);
 | 
					 | 
				
			||||||
        if(disconnected) return;
 | 
					 | 
				
			||||||
        ss.setStatus(ops);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch (HIDPP20::UnsupportedFeature &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(ERROR, "Device does not support SmartShift");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch (HIDPP20::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(ERROR, "Error setting SmartShift options, code %d: %s\n", e.errorCode(), e.what());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::setHiresScroll(uint8_t ops)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(disconnected) return;
 | 
					 | 
				
			||||||
        HIDPP20::IHiresScroll hs(hidpp_dev);
 | 
					 | 
				
			||||||
        if(disconnected) return;
 | 
					 | 
				
			||||||
        hs.setMode(ops);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch (HIDPP20::UnsupportedFeature &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(ERROR, "Device does not support Hires Scrolling");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch (HIDPP20::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(ERROR, "Error setting Hires Scrolling options, code %d: %s\n", e.errorCode(), e.what());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::setDPI(int dpi)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(disconnected) return;
 | 
					 | 
				
			||||||
    HIDPP20::IAdjustableDPI iad(hidpp_dev);
 | 
					 | 
				
			||||||
    if(disconnected) return;
 | 
					 | 
				
			||||||
    try { for(unsigned int i = 0; i < iad.getSensorCount(); i++) iad.setSensorDPI(i, dpi); }
 | 
					 | 
				
			||||||
    catch (HIDPP20::Error &e) { log_printf(ERROR, "Error while setting DPI: %s", e.what()); }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::waitForReceiver()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    while(true)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        waiting_for_receiver = true;
 | 
					 | 
				
			||||||
        listener->addEventHandler(std::make_unique<ReceiverHandler>(this));
 | 
					 | 
				
			||||||
        listener->start();
 | 
					 | 
				
			||||||
        // Listener stopped, check if stopped or ReceiverHandler event
 | 
					 | 
				
			||||||
        if (waiting_for_receiver)
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        usleep(200000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        try
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(this->init()) break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch(BlacklistedDevice& e) { return; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        log_printf(ERROR, "Failed to initialize device %d on %s, waiting for receiver");
 | 
					 | 
				
			||||||
        delete(listener);
 | 
					 | 
				
			||||||
        listener = new SimpleListener(new HIDPP::SimpleDispatcher(path.c_str()), index);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    log_printf(INFO, "%s detected: device %d on %s", name.c_str(), index, path.c_str());
 | 
					 | 
				
			||||||
    this->start();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::printCIDs() {
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        HIDPP20::IReprogControls irc = HIDPP20::IReprogControls::auto_version(hidpp_dev);
 | 
					 | 
				
			||||||
        if(disconnected)
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        int controlCount = irc.getControlCount();
 | 
					 | 
				
			||||||
        for(int i = 0; i < controlCount; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(disconnected)
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            uint16_t cid = irc.getControlInfo(i).control_id;
 | 
					 | 
				
			||||||
            log_printf(DEBUG, "Available CID: 0x%x", cid);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(HIDPP20::UnsupportedFeature &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(DEBUG, "%s does not support Reprog controls, not diverting!", name.c_str());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::start()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    printCIDs();
 | 
					 | 
				
			||||||
    configure();
 | 
					 | 
				
			||||||
    try { listener->addEventHandler(std::make_unique<ButtonHandler>(this)); }
 | 
					 | 
				
			||||||
    catch(HIDPP20::UnsupportedFeature &e) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if(index == HIDPP::DefaultDevice || index == HIDPP::CordedDevice)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        try { listener->addEventHandler( std::make_unique<WirelessStatusHandler>(this) ); }
 | 
					 | 
				
			||||||
        catch(HIDPP20::UnsupportedFeature &e) { }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    listener->start();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Device::testConnection()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i = MAX_CONNECTION_TRIES;
 | 
					 | 
				
			||||||
    do {
 | 
					 | 
				
			||||||
        try
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            HIDPP20::Device _hpp20dev(dispatcher, index);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch(HIDPP10::Error &e)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(e.errorCode() == HIDPP10::Error::ResourceError) // Asleep, wait for next event
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            if(i == MAX_CONNECTION_TRIES-1)
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch(std::exception &e)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if(i == MAX_CONNECTION_TRIES-1)
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        i++;
 | 
					 | 
				
			||||||
    } while(i < MAX_CONNECTION_TRIES);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ButtonHandler::handleEvent (const HIDPP::Report &event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    switch (event.function())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        case HIDPP20::IReprogControls::Event::DivertedButtonEvent:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            new_states = HIDPP20::IReprogControls::divertedButtonEvent(event);
 | 
					 | 
				
			||||||
            if (states.empty())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                for (uint16_t i : new_states)
 | 
					 | 
				
			||||||
                    std::thread{[=]() { dev->pressButton(i); }}.detach();
 | 
					 | 
				
			||||||
                states = new_states;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            std::vector<uint16_t>::iterator it;
 | 
					 | 
				
			||||||
            std::vector<uint16_t> cids(states.size() + new_states.size());
 | 
					 | 
				
			||||||
            it = std::set_union(states.begin(), states.end(), new_states.begin(), new_states.end(), cids.begin());
 | 
					 | 
				
			||||||
            cids.resize((ulong)(it - cids.begin()));
 | 
					 | 
				
			||||||
            for (uint16_t i : cids)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (std::find(new_states.begin(), new_states.end(), i) != new_states.end())
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (std::find(states.begin(), states.end(), i) == states.end())
 | 
					 | 
				
			||||||
                        std::thread{[=]() { dev->pressButton(i); }}.detach();
 | 
					 | 
				
			||||||
                } else
 | 
					 | 
				
			||||||
                    std::thread{[=]() { dev->releaseButton(i); }}.detach();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            states = new_states;
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        case HIDPP20::IReprogControlsV4::Event::DivertedRawXYEvent:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto raw_xy = HIDPP20::IReprogControlsV4::divertedRawXYEvent(event);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for(uint16_t i : states)
 | 
					 | 
				
			||||||
                std::thread{[=]() { dev->moveDiverted(i, raw_xy); }}.detach();
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ReceiverHandler::handleEvent(const HIDPP::Report &event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    switch(event.featureIndex())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        case HIDPP10::IReceiver::DeviceUnpaired:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            log_printf(INFO, "%s (Device %d on %s) unpaired from receiver", dev->name.c_str(), dev->index, dev->path.c_str());
 | 
					 | 
				
			||||||
            std::thread {[=]()
 | 
					 | 
				
			||||||
                         {
 | 
					 | 
				
			||||||
                            finder->stopAndDeleteDevice(dev->path, dev->index);
 | 
					 | 
				
			||||||
                            finder->insertNewReceiverDevice(dev->path, dev->index);
 | 
					 | 
				
			||||||
                         }}.detach();
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        case HIDPP10::IReceiver::DevicePaired:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            log_printf(DEBUG, "Receiver on %s: Device %d paired", dev->path.c_str(), event.deviceIndex());
 | 
					 | 
				
			||||||
            if(dev->waiting_for_receiver)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if(!dev->testConnection()) return;
 | 
					 | 
				
			||||||
                dev->waiting_for_receiver = false;
 | 
					 | 
				
			||||||
                dev->stop();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            //else: Likely an enumeration event, ignore.
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        case HIDPP10::IReceiver::ConnectionStatus:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto status = HIDPP10::IReceiver::connectionStatusEvent(event);
 | 
					 | 
				
			||||||
            if(status == HIDPP10::IReceiver::LinkLoss)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                log_printf(INFO, "Link lost to %s", dev->name.c_str());
 | 
					 | 
				
			||||||
                dev->disconnected = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (status == HIDPP10::IReceiver::ConnectionEstablished)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if(dev->waiting_for_receiver)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    log_printf(DEBUG, "Receiver on %s: Connection established to device %d", dev->path.c_str(), event.deviceIndex());
 | 
					 | 
				
			||||||
                    if(!dev->testConnection()) return;
 | 
					 | 
				
			||||||
                    dev->waiting_for_receiver = false;
 | 
					 | 
				
			||||||
                    std::thread { [=]() { dev->stop(); } }.detach();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if(!dev->initialized) return;
 | 
					 | 
				
			||||||
                    dev->disconnected = false;
 | 
					 | 
				
			||||||
                    dev->configure();
 | 
					 | 
				
			||||||
                    log_printf(INFO, "Connection established to %s", dev->name.c_str());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void WirelessStatusHandler::handleEvent(const HIDPP::Report &event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    switch(event.function())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        case HIDPP20::IWirelessDeviceStatus::StatusBroadcast:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            auto status = HIDPP20::IWirelessDeviceStatus::statusBroadcastEvent(event);
 | 
					 | 
				
			||||||
            if(status.ReconfNeeded)
 | 
					 | 
				
			||||||
                dev->configure();
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            log_printf(DEBUG, "Undocumented event %02x from WirelessDeviceStatus", event.function());
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EventListener::removeEventHandlers ()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    for (const auto &p: iterators)
 | 
					 | 
				
			||||||
        dispatcher->unregisterEventHandler(p.second);
 | 
					 | 
				
			||||||
    handlers.clear();
 | 
					 | 
				
			||||||
    iterators.clear();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EventListener::~EventListener()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    removeEventHandlers();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void EventListener::addEventHandler(std::unique_ptr<EventHandler> &&handler)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    EventHandler *ptr = handler.get();
 | 
					 | 
				
			||||||
    for(uint8_t feature : handler->featureIndices())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        handlers.emplace(feature, std::move(handler));
 | 
					 | 
				
			||||||
        dispatcher->registerEventHandler(index, feature, [=](const HIDPP::Report &report)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ptr->handleEvent(report);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SimpleListener::start()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    bool retry;
 | 
					 | 
				
			||||||
    do
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        retry = false;
 | 
					 | 
				
			||||||
        try { dispatcher->listen(); }
 | 
					 | 
				
			||||||
        catch(std::system_error &e)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            retry = true;
 | 
					 | 
				
			||||||
            usleep(250000);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } while(retry && !stopped);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SimpleListener::stop()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    this->stopped = true;
 | 
					 | 
				
			||||||
    dispatcher->stop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool SimpleListener::event (EventHandler *handler, const HIDPP::Report &report)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    handler->handleEvent (report);
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::stop()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    disconnected = true;
 | 
					 | 
				
			||||||
    listener->stop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::pressButton(uint16_t cid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(config->actions.find(cid) == config->actions.end())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(DEBUG, "0x%x was pressed but no action was found.", cid);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    config->actions.find(cid)->second->press();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::releaseButton(uint16_t cid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if(config->actions.find(cid) == config->actions.end())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        log_printf(DEBUG, "0x%x was released but no action was found.", cid);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    config->actions.find(cid)->second->release();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Device::moveDiverted(uint16_t cid, HIDPP20::IReprogControlsV4::Move m)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    auto action = config->actions.find(cid);
 | 
					 | 
				
			||||||
    if(action == config->actions.end())
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    switch(action->second->type)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        case Action::Gestures:
 | 
					 | 
				
			||||||
            ((GestureAction*)action->second)->move(m);
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::map<uint16_t, uint8_t> Device::getFeatures()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    std::map<uint16_t, uint8_t> _features;
 | 
					 | 
				
			||||||
    HIDPP20::IFeatureSet ifs (hidpp_dev);
 | 
					 | 
				
			||||||
    uint8_t feature_count = ifs.getCount();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(uint8_t i = 0; i < feature_count; i++)
 | 
					 | 
				
			||||||
        _features.insert( {i, ifs.getFeatureID(i) } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return _features;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,172 +1,26 @@
 | 
				
			|||||||
#ifndef LOGID_DEVICE_H
 | 
					#ifndef LOGID_DEVICE_H
 | 
				
			||||||
#define LOGID_DEVICE_H
 | 
					#define LOGID_DEVICE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Actions.h"
 | 
					#include "backend/hidpp/defs.h"
 | 
				
			||||||
#include "DeviceMonitor.h"
 | 
					#include "backend/hidpp20/Device.h"
 | 
				
			||||||
#include "Configuration.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <map>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <hidpp/Dispatcher.h>
 | 
					 | 
				
			||||||
#include <hidpp/SimpleDispatcher.h>
 | 
					 | 
				
			||||||
#include <hidpp10/IReceiver.h>
 | 
					 | 
				
			||||||
#include <hidpp20/IWirelessDeviceStatus.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace logid
 | 
					namespace logid
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class EventListener;
 | 
					    /* TODO: Implement HID++ 1.0 support
 | 
				
			||||||
    class DeviceConfig;
 | 
					     * Currently, the logid::Device class has a hardcoded requirement
 | 
				
			||||||
 | 
					     * for an HID++ 2.0 device.
 | 
				
			||||||
    class BlacklistedDevice : public std::exception
 | 
					     */
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        BlacklistedDevice() = default;
 | 
					 | 
				
			||||||
        virtual const char* what()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return "Blacklisted device";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Device
 | 
					    class Device
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        Device(std::string p, const HIDPP::DeviceIndex i);
 | 
					        Device(std::string path, backend::hidpp::DeviceIndex index);
 | 
				
			||||||
        ~Device();
 | 
					        void wakeup();
 | 
				
			||||||
 | 
					        void sleep();
 | 
				
			||||||
        std::string name;
 | 
					    private:
 | 
				
			||||||
 | 
					        backend::hidpp20::Device _hidpp20;
 | 
				
			||||||
        bool init();
 | 
					        std::string _path;
 | 
				
			||||||
        void configure();
 | 
					        backend::hidpp::DeviceIndex _index;
 | 
				
			||||||
        void reset();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void pressButton(uint16_t cid);
 | 
					 | 
				
			||||||
        void releaseButton(uint16_t cid);
 | 
					 | 
				
			||||||
        void moveDiverted(uint16_t cid, HIDPP20::IReprogControlsV4::Move move);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void waitForReceiver();
 | 
					 | 
				
			||||||
        void start();
 | 
					 | 
				
			||||||
        void stop();
 | 
					 | 
				
			||||||
        bool testConnection();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::map<uint16_t, uint8_t> getFeatures();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::map<uint16_t, uint8_t> features;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const std::string path;
 | 
					 | 
				
			||||||
        const HIDPP::DeviceIndex index;
 | 
					 | 
				
			||||||
        HIDPP::Dispatcher* dispatcher;
 | 
					 | 
				
			||||||
        HIDPP20::Device* hidpp_dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::mutex configuring;
 | 
					 | 
				
			||||||
        std::atomic_bool disconnected;
 | 
					 | 
				
			||||||
        bool initialized = false;
 | 
					 | 
				
			||||||
        bool waiting_for_receiver = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        DeviceConfig* config;
 | 
					 | 
				
			||||||
        EventListener* listener;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        void divert_buttons();
 | 
					 | 
				
			||||||
        void printCIDs();
 | 
					 | 
				
			||||||
        void setSmartShift(HIDPP20::ISmartShift::SmartshiftStatus ops);
 | 
					 | 
				
			||||||
        void setHiresScroll(uint8_t flags);
 | 
					 | 
				
			||||||
        void setDPI(int dpi);
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					 | 
				
			||||||
    class EventHandler
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        virtual const HIDPP20::FeatureInterface *feature() const = 0;
 | 
					 | 
				
			||||||
        virtual const std::vector<uint8_t> featureIndices() const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return {feature()->index()};
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        virtual void handleEvent (const HIDPP::Report &event) = 0;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    class ButtonHandler : public EventHandler
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        ButtonHandler (Device *d) : dev (d), _irc (HIDPP20::IReprogControls::auto_version(d->hidpp_dev)) { }
 | 
					 | 
				
			||||||
        const HIDPP20::FeatureInterface *feature () const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return &_irc;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        void handleEvent (const HIDPP::Report &event);
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        Device* dev;
 | 
					 | 
				
			||||||
        HIDPP20::IReprogControls _irc;
 | 
					 | 
				
			||||||
        std::vector<uint16_t> states;
 | 
					 | 
				
			||||||
        std::vector<uint16_t> new_states;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    class ReceiverHandler : public EventHandler
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        ReceiverHandler (Device *d) : dev (d) { }
 | 
					 | 
				
			||||||
        const HIDPP20::FeatureInterface *feature () const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return nullptr; // This sounds like a horrible idea
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        virtual const std::vector<uint8_t> featureIndices() const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return HIDPP10::IReceiver::Events;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        void handleEvent (const HIDPP::Report &event);
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        Device* dev;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    class WirelessStatusHandler : public EventHandler
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        WirelessStatusHandler (Device *d) : dev (d), _iws (d->hidpp_dev) { }
 | 
					 | 
				
			||||||
        const HIDPP20::FeatureInterface *feature () const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return &_iws;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        void handleEvent (const HIDPP::Report &event);
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        Device* dev;
 | 
					 | 
				
			||||||
        HIDPP20::IWirelessDeviceStatus _iws;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class EventListener
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        HIDPP::Dispatcher *dispatcher;
 | 
					 | 
				
			||||||
        HIDPP::DeviceIndex index;
 | 
					 | 
				
			||||||
        std::map<uint8_t, std::unique_ptr<EventHandler>> handlers;
 | 
					 | 
				
			||||||
        std::map<uint8_t, HIDPP::Dispatcher::listener_iterator> iterators;
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        EventListener (HIDPP::Dispatcher *dispatcher, HIDPP::DeviceIndex index): dispatcher (dispatcher), index (index) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        virtual void removeEventHandlers ();
 | 
					 | 
				
			||||||
        virtual ~EventListener();
 | 
					 | 
				
			||||||
        virtual void addEventHandler (std::unique_ptr<EventHandler> &&handler);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        virtual void start () = 0;
 | 
					 | 
				
			||||||
        virtual void stop () = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        virtual bool event (EventHandler* handler, const HIDPP::Report &report) = 0;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    class SimpleListener : public EventListener
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        HIDPP::SimpleDispatcher *dispatcher;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
        SimpleListener (HIDPP::SimpleDispatcher* dispatcher, HIDPP::DeviceIndex index):
 | 
					 | 
				
			||||||
                EventListener (dispatcher, index),
 | 
					 | 
				
			||||||
                dispatcher (dispatcher)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool stopped = false;
 | 
					 | 
				
			||||||
        virtual void start();
 | 
					 | 
				
			||||||
        virtual void stop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
        virtual bool event (EventHandler* handler, const HIDPP::Report &report);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif //LOGID_DEVICE_H
 | 
					#endif //LOGID_DEVICE_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "DeviceMonitor.h"
 | 
					#include "DeviceMonitor.h"
 | 
				
			||||||
 | 
					#include "Receiver.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
#include "backend/hidpp10/Error.h"
 | 
					#include "backend/hidpp10/Error.h"
 | 
				
			||||||
#include "backend/dj/Receiver.h"
 | 
					#include "backend/dj/Receiver.h"
 | 
				
			||||||
@@ -11,161 +12,65 @@
 | 
				
			|||||||
using namespace logid;
 | 
					using namespace logid;
 | 
				
			||||||
using namespace logid::backend;
 | 
					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)
 | 
					void DeviceMonitor::addDevice(std::string path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    bool defaultExists = true;
 | 
				
			||||||
 | 
					    bool isReceiver = false;
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        std::tuple<uint8_t, uint8_t> version;
 | 
					 | 
				
			||||||
        try
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        hidpp::Device device(path, hidpp::DefaultDevice);
 | 
					        hidpp::Device device(path, hidpp::DefaultDevice);
 | 
				
			||||||
 | 
					        isReceiver = device.version() == std::make_tuple(1, 0);
 | 
				
			||||||
            log_printf(DEBUG, "Detected HID++ device at %s", path.c_str());
 | 
					    } catch(hidpp10::Error &e) {
 | 
				
			||||||
 | 
					        if(e.code() != hidpp10::Error::UnknownDevice)
 | 
				
			||||||
            version = device.version();
 | 
					 | 
				
			||||||
            log_printf(DEBUG, "HID++ version: %d.%d", std::get<0>(version), std::get<1>(version));
 | 
					 | 
				
			||||||
        } catch(std::system_error &e) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(version == std::make_tuple(1, 0))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // This is a receiver
 | 
					 | 
				
			||||||
            dj::Receiver receiver(path);
 | 
					 | 
				
			||||||
            receiver.enumerate();
 | 
					 | 
				
			||||||
            receiver.listen();
 | 
					 | 
				
			||||||
            while(true) {}
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
        auto eventHandler = std::make_shared<backend::hidpp::EventHandler>();
 | 
					 | 
				
			||||||
        eventHandler->condition = [device](backend::hidpp::Report& report)->bool
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        eventHandler->callback = [device](backend::hidpp::Report& report)->void
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            log_printf(DEBUG, "Event on %s:%d", device->devicePath().c_str(),
 | 
					 | 
				
			||||||
                    device->deviceIndex());
 | 
					 | 
				
			||||||
            for(auto& i : report.rawReport())
 | 
					 | 
				
			||||||
                    printf("%02x ", i);
 | 
					 | 
				
			||||||
            printf("\n");
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        device->addEventHandler("MONITOR_ALL", eventHandler);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        devices.push_back(device);*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //std::thread([device]() { device->listen(); }).detach();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch(hidpp10::Error &e)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(e.code() == hidpp10::Error::UnknownDevice) {}
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            throw;
 | 
					            throw;
 | 
				
			||||||
 | 
					    } catch(hidpp::Device::InvalidDevice &e) { // Ignore
 | 
				
			||||||
 | 
					        defaultExists = false;
 | 
				
			||||||
 | 
					    } catch(std::system_error &e) {
 | 
				
			||||||
 | 
					        log_printf(WARN, "I/O error on %s: %s, skipping device.",
 | 
				
			||||||
 | 
					                path.c_str(), e.what());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(isReceiver) {
 | 
				
			||||||
 | 
					        log_printf(INFO, "Detected receiver at %s", path.c_str());
 | 
				
			||||||
 | 
					        auto receiver = std::make_shared<Receiver>(path);
 | 
				
			||||||
 | 
					        _receivers.emplace(path, receiver);
 | 
				
			||||||
 | 
					        // receiver->listen();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        /* TODO: Error check?
 | 
				
			||||||
 | 
					         * TODO: Can non-receivers only contain 1 device?
 | 
				
			||||||
 | 
					         * If the device exists, it is guaranteed to be an HID++ 2.0 device */
 | 
				
			||||||
 | 
					        if(defaultExists) {
 | 
				
			||||||
 | 
					            auto device = std::make_shared<Device>(path, hidpp::DefaultDevice);
 | 
				
			||||||
 | 
					            _devices.emplace(path,  device);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                auto device = std::make_shared<Device>(path, hidpp::CordedDevice);
 | 
				
			||||||
 | 
					                _devices.emplace(path, device);
 | 
				
			||||||
 | 
					            } catch(hidpp10::Error &e) {
 | 
				
			||||||
 | 
					                if(e.code() != hidpp10::Error::UnknownDevice)
 | 
				
			||||||
 | 
					                    throw;
 | 
				
			||||||
 | 
					            } catch(hidpp::Device::InvalidDevice &e) { // Ignore
 | 
				
			||||||
 | 
					            } catch(std::system_error &e) {
 | 
				
			||||||
 | 
					                // This error should have been thrown previously
 | 
				
			||||||
 | 
					                log_printf(WARN, "I/O error on %s: %s", path.c_str(),
 | 
				
			||||||
 | 
					                        e.what());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    catch(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)
 | 
					void DeviceMonitor::removeDevice(std::string path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    log_printf(DEBUG, "Device %s disconnected", path.c_str());
 | 
					    auto receiver = _receivers.find(path);
 | 
				
			||||||
    /*
 | 
					
 | 
				
			||||||
    ipc_server->removeReceiver(path);
 | 
					    if(receiver != _receivers.end()) {
 | 
				
			||||||
    this->stopAndDeleteAllDevicesIn(std::string(path));
 | 
					        _receivers.erase(receiver);
 | 
				
			||||||
     */
 | 
					        log_printf(INFO, "Receiver on %s disconnected", path.c_str());
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        auto device = _devices.find(path);
 | 
				
			||||||
 | 
					        if(device != _devices.find(path)) {
 | 
				
			||||||
 | 
					            _devices.erase(device);
 | 
				
			||||||
 | 
					            log_printf(INFO, "Device on %s disconnected", path.c_str());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,38 +7,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "backend/raw/DeviceMonitor.h"
 | 
					#include "backend/raw/DeviceMonitor.h"
 | 
				
			||||||
#include "backend/hidpp/Device.h"
 | 
					#include "backend/hidpp/Device.h"
 | 
				
			||||||
 | 
					#include "Device.h"
 | 
				
			||||||
#define MAX_CONNECTION_TRIES 10
 | 
					#include "Receiver.h"
 | 
				
			||||||
#define TIME_BETWEEN_CONNECTION_TRIES 500ms
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace logid
 | 
					namespace logid
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Device;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct ConnectedDevice {
 | 
					 | 
				
			||||||
    	Device *device;
 | 
					 | 
				
			||||||
    	std::thread associatedThread;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class DeviceMonitor : public backend::raw::DeviceMonitor
 | 
					    class DeviceMonitor : public backend::raw::DeviceMonitor
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
    	~DeviceMonitor();
 | 
					        DeviceMonitor() = default;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    	/*
 | 
					 | 
				
			||||||
    	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:
 | 
					    protected:
 | 
				
			||||||
        void addDevice(std::string path) override;
 | 
					        void addDevice(std::string path) override;
 | 
				
			||||||
        void removeDevice(std::string path) override;
 | 
					        void removeDevice(std::string path) override;
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
    	std::mutex devices_mutex;
 | 
					
 | 
				
			||||||
    	std::vector<std::shared_ptr<backend::hidpp::Device>> devices; //tmp
 | 
					        std::map<std::string, std::shared_ptr<Device>> _devices;
 | 
				
			||||||
        //std::map<std::string, std::map<backend::hidpp::DeviceIndex, ConnectedDevice>> devices;
 | 
					        std::map<std::string, std::shared_ptr<Receiver>> _receivers;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extern DeviceMonitor* finder;
 | 
					    extern DeviceMonitor* finder;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/logid/Receiver.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/logid/Receiver.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#include "Receiver.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace logid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Receiver::Receiver(std::string path) : _path (path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    log_printf(DEBUG, "logid::Receiver created on %s", path.c_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/logid/Receiver.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/logid/Receiver.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					#ifndef LOGID_RECEIVER_H
 | 
				
			||||||
 | 
					#define LOGID_RECEIVER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace logid
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class Receiver
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					        Receiver(std::string path);
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					        std::string _path;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //LOGID_RECEIVER_H
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/logid/backend/dj/ReceiverMonitor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/logid/backend/dj/ReceiverMonitor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								src/logid/backend/dj/ReceiverMonitor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/logid/backend/dj/ReceiverMonitor.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					#ifndef LOGID_BACKEND_DJ_RECEIVERMONITOR_H
 | 
				
			||||||
 | 
					#define LOGID_BACKEND_DJ_RECEIVERMONITOR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //LOGID_BACKEND_DJ_RECEIVERMONITOR_H
 | 
				
			||||||
@@ -5,6 +5,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace logid::backend::hidpp20;
 | 
					using namespace logid::backend::hidpp20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Device::Device(std::string path, hidpp::DeviceIndex index)
 | 
				
			||||||
 | 
					    : hidpp::Device(path, index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(std::get<0>(version()) >= 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Device::Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index)
 | 
				
			||||||
 | 
					        : hidpp::Device(raw_device, index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    assert(std::get<0>(version()) >= 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<uint8_t> Device::callFunction(uint8_t feature_index,
 | 
					std::vector<uint8_t> Device::callFunction(uint8_t feature_index,
 | 
				
			||||||
        uint8_t function, std::vector<uint8_t>& params)
 | 
					        uint8_t function, std::vector<uint8_t>& params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,9 @@ namespace hidpp20 {
 | 
				
			|||||||
    class Device : public hidpp::Device
 | 
					    class Device : public hidpp::Device
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
 | 
					        Device(std::string path, hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					        Device(std::shared_ptr<raw::RawDevice> raw_device, hidpp::DeviceIndex index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<uint8_t> callFunction(uint8_t feature_index,
 | 
					        std::vector<uint8_t> callFunction(uint8_t feature_index,
 | 
				
			||||||
                uint8_t function,
 | 
					                uint8_t function,
 | 
				
			||||||
                std::vector<uint8_t>& params);
 | 
					                std::vector<uint8_t>& params);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
#ifndef LOGID_UTIL_H
 | 
					#ifndef LOGID_UTIL_H
 | 
				
			||||||
#define LOGID_UTIL_H
 | 
					#define LOGID_UTIL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#include "Actions.h"
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace logid
 | 
					namespace logid
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user