diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8af2d15
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+logiconf.pro.user*
diff --git a/99-hidraw-logitech-g402.rules b/99-hidraw-logitech-g402.rules
new file mode 100644
index 0000000..79f0818
--- /dev/null
+++ b/99-hidraw-logitech-g402.rules
@@ -0,0 +1 @@
+KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c07e", MODE="0666"
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9b2697d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+Linux alternative for the Logitech Gaming Software.
+
+Currently, it works only for the G402 Gaming Mouse.
+
+INSTRUCTIONS:
+move 99-hidraw-logitech-g402.rules to /lib/udev/rules.d/99-hidraw-permissions.rules, unplug and plug the mouse
diff --git a/hidpp/hidpp.pro b/hidpp/hidpp.pro
new file mode 100755
index 0000000..a5c060a
--- /dev/null
+++ b/hidpp/hidpp.pro
@@ -0,0 +1,68 @@
+TARGET = hidpp
+TEMPLATE = lib
+CONFIG += c++11 staticlib object_parallel_to_source
+
+SOURCES += misc/HIDRaw.cpp \
+ misc/Log.cpp \
+ misc/CRC.cpp \
+ misc/UsageStrings.cpp \
+ hidpp/Device.cpp \
+ hidpp/Report.cpp \
+ hidpp/DeviceInfo.cpp \
+ hidpp10/Device.cpp \
+ hidpp10/Address.cpp \
+ hidpp10/Error.cpp \
+ hidpp10/WriteError.cpp \
+ hidpp10/IMemory.cpp \
+ hidpp10/IReceiver.cpp \
+ hidpp10/IIndividualFeatures.cpp \
+ hidpp10/Sensor.cpp \
+ hidpp10/IResolution.cpp \
+ hidpp10/IProfile.cpp \
+ hidpp10/MemoryMapping.cpp \
+ hidpp10/ProfileDirectory.cpp \
+ hidpp10/Profile.cpp \
+ hidpp10/Macro.cpp \
+ hidpp20/Device.cpp \
+ hidpp20/Error.cpp \
+ hidpp20/IRoot.cpp \
+ hidpp20/IFeatureSet.cpp \
+ hidpp20/IOnboardProfiles.cpp
+
+HEADERS += hidpp/defs.h \
+ hidpp/Device.h \
+ hidpp/DeviceInfo.h \
+ hidpp/ids.h \
+ hidpp/Report.h \
+ hidpp10/Address.h \
+ hidpp10/defs.h \
+ hidpp10/Device.h \
+ hidpp10/DeviceInfo.h \
+ hidpp10/Error.h \
+ hidpp10/IIndividualFeatures.h \
+ hidpp10/IMemory.h \
+ hidpp10/IProfile.h \
+ hidpp10/IReceiver.h \
+ hidpp10/IResolution.h \
+ hidpp10/Macro.h \
+ hidpp10/MemoryMapping.h \
+ hidpp10/ProfileDirectory.h \
+ hidpp10/Profile.h \
+ hidpp10/Sensor.h \
+ hidpp10/WriteError.h \
+ hidpp20/defs.h \
+ hidpp20/Device.h \
+ hidpp20/Error.h \
+ hidpp20/IFeatureSet.h \
+ hidpp20/IOnboardProfiles.h \
+ hidpp20/IRoot.h \
+ misc/CRC.h \
+ misc/Endian.h \
+ misc/HIDRaw.h \
+ misc/Log.h \
+ misc/UsageStrings.h
+
+unix {
+ target.path = /usr/lib
+ INSTALLS += target
+}
diff --git a/hidpp/hidpp/Device.cpp b/hidpp/hidpp/Device.cpp
new file mode 100755
index 0000000..b4349fc
--- /dev/null
+++ b/hidpp/hidpp/Device.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+using namespace HIDPP;
+
+Device::NoHIDPPReportException::NoHIDPPReportException ()
+{
+}
+
+const char *Device::NoHIDPPReportException::what () const noexcept
+{
+ return "No HID++ report";
+}
+
+static const std::array ShortReportDesc = {
+ 0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
+ 0x09, 0x01, // Usage (0001 - Vendor)
+ 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 LongReportDesc = {
+ 0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
+ 0x09, 0x02, // Usage (0002 - Vendor)
+ 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 ShortReportDesc2 = {
+ 0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
+ 0x09, 0x01, // Usage (0001 - Vendor)
+ 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 LongReportDesc2 = {
+ 0x06, 0x00, 0xFF, // Usage Page (FF00 - Vendor)
+ 0x09, 0x02, // Usage (0002 - Vendor)
+ 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
+};
+
+Device::Device (const std::string &path, DeviceIndex device_index):
+ HIDRaw (path), _device_index (device_index)
+{
+ const HIDRaw::ReportDescriptor &rdesc = getReportDescriptor ();
+ if (rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
+ ShortReportDesc.begin (),
+ ShortReportDesc.end ()) &&
+ rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
+ ShortReportDesc2.begin (),
+ ShortReportDesc2.end ()))
+ throw NoHIDPPReportException ();
+ if (rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
+ LongReportDesc.begin (),
+ LongReportDesc.end ()) &&
+ rdesc.end () == std::search (rdesc.begin (), rdesc.end (),
+ LongReportDesc2.begin (),
+ LongReportDesc2.end ()))
+ throw NoHIDPPReportException ();
+
+ if (device_index >= WirelessDevice1 && device_index <= WirelessDevice6) {
+ HIDPP10::Device ur (path, DefaultDevice);
+ HIDPP10::IReceiver ireceiver (&ur);
+ ireceiver.getDeviceInformation (device_index - 1,
+ nullptr,
+ nullptr,
+ &_product_id,
+ nullptr);
+ _name = ireceiver.getDeviceName (device_index - 1);
+ }
+ else {
+ _product_id = HIDRaw::productID ();
+ _name = HIDRaw::name ();
+ }
+}
+
+DeviceIndex Device::deviceIndex () const
+{
+ return _device_index;
+}
+
+void Device::getProtocolVersion (unsigned int &major, unsigned int &minor)
+{
+ constexpr int software_id = 1; // Must be a 4 bit unsigned value
+ Report request (Report::Short,
+ _device_index,
+ HIDPP20::IRoot::index,
+ HIDPP20::IRoot::Ping,
+ software_id);
+ sendReport (request);
+ while (true) {
+ Report response = getReport (true); // Time out if there is no valid response received fast enough
+
+ if (response.deviceIndex () != _device_index) {
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored report with wrong device index"
+ << std::endl;
+ continue;
+ }
+
+ uint8_t sub_id, address, error_code;
+ if (response.checkErrorMessage10 (&sub_id, &address, &error_code)) {
+ if (sub_id != HIDPP20::IRoot::index ||
+ address != (HIDPP20::IRoot::Ping << 4 | software_id)) {
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored error message with wrong subID or address"
+ << std::endl;
+ continue;
+ }
+ if (error_code != HIDPP10::Error::InvalidSubID)
+ throw HIDPP10::Error (static_cast (error_code));
+ major = 1;
+ minor = 0;
+ return;
+ }
+ uint8_t feature_index;
+ unsigned int function, sw_id;
+ if (response.checkErrorMessage20 (&feature_index, &function, &sw_id, &error_code)) {
+ if (feature_index != HIDPP20::IRoot::index || function != HIDPP20::IRoot::Ping || sw_id != software_id) {
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored error message with wrong feature/function/softwareID"
+ << std::endl;
+ continue;
+ }
+ throw HIDPP20::Error (static_cast (error_code));
+ }
+ if (response.featureIndex () == HIDPP20::IRoot::index &&
+ response.function () == HIDPP20::IRoot::Ping &&
+ response.softwareID () == software_id) {
+ major = response.params ()[0];
+ minor = response.params ()[1];
+ return;
+ }
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored report with wrong feature/function/softwareID"
+ << std::endl;
+ }
+}
+
+uint16_t Device::productID () const
+{
+ return _product_id;
+}
+
+std::string Device::name () const
+{
+ return _name;
+}
+
+int Device::sendReport (const Report &report)
+{
+ return writeReport (report.rawReport ());
+}
+
+Report Device::getReport (bool timeout)
+{
+ std::vector raw_report;
+ while (true) {
+ try {
+ raw_report.resize (Report::MaxDataLength+1);
+ if (timeout)
+ readReport (raw_report, 1);
+ else
+ readReport (raw_report);
+ return Report (raw_report[0], &raw_report[1], raw_report.size () - 1);
+ }
+ catch (Report::InvalidReportID e) {
+ // Ignore non-HID++ reports
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored non HID++ report" << std::endl;
+ Log::printBytes (Log::Debug, "Ignored report:",
+ raw_report.begin (), raw_report.end ());
+ continue;
+ }
+ catch (Report::InvalidReportLength e) {
+ // Ignore non-HID++ reports
+ Log::warning () << __FUNCTION__ << ": "
+ << "Invalid HID++ report length" << std::endl;
+ Log::printBytes (Log::Warning, "Ignored report:",
+ raw_report.begin (), raw_report.end ());
+ continue;
+ }
+ }
+}
diff --git a/hidpp/hidpp/Device.h b/hidpp/hidpp/Device.h
new file mode 100755
index 0000000..01e27c8
--- /dev/null
+++ b/hidpp/hidpp/Device.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP_DEVICE_H
+#define HIDPP_DEVICE_H
+
+#include
+#include
+#include
+
+namespace HIDPP
+{
+
+/**
+ * A generic HID++ Device
+ *
+ * \ingroup hidpp
+ */
+class Device: public HIDRaw
+{
+public:
+ /**
+ * Exception when no HID++ report is found in the report descriptor.
+ */
+ class NoHIDPPReportException: public std::exception
+ {
+ public:
+ NoHIDPPReportException ();
+ virtual const char *what () const noexcept;
+ };
+
+ /**
+ * HID++ device constructor.
+ *
+ * Open the hidraw device node at \p path.
+ *
+ * For receivers and wireless devices, multiple devices use the same hidraw
+ * node, \p device_index is needed to select a particular device.
+ *
+ * \throws SysCallError
+ * \throws NoHIDPPReportException
+ * \throws HIDPP10::Error Only for wireless devices, if there is an error
+ * while reading device information.
+ */
+ Device (const std::string &path, DeviceIndex device_index = DefaultDevice);
+
+ /**
+ * Access the device index.
+ */
+ DeviceIndex deviceIndex () const;
+
+ /**
+ * Check the HID++ protocol version.
+ *
+ * \param major Major number of the protocol version.
+ * \param minor Minor number of the protocol version.
+ */
+ void getProtocolVersion (unsigned int &major, unsigned int &minor);
+
+ /**
+ * Get the product ID of the device.
+ *
+ * - Use HID product ID for wired device or receivers.
+ * - Use wireless PID given by the receiver for wireless devices.
+ */
+ uint16_t productID () const;
+ /**
+ * Get the product name of the device.
+ *
+ * - Use HID product name for wired device or receivers.
+ * - Use the name given by the receiver for wireless devices.
+ */
+ std::string name () const;
+
+ /**
+ * Send a HID++ report to this device.
+ */
+ int sendReport (const Report &report);
+ /**
+ * Read a HID++ report from this device.
+ *
+ * It discards any non-HID++ report.
+ *
+ * \param timeout If true, try to read a report with a time out, throw HIDRaw::TimeoutError if no valid report is read fast enough.
+ */
+ Report getReport (bool timeout = false);
+
+private:
+ DeviceIndex _device_index;
+ uint16_t _product_id;
+ std::string _name;
+};
+
+}
+
+#endif
diff --git a/hidpp/hidpp/DeviceInfo.cpp b/hidpp/hidpp/DeviceInfo.cpp
new file mode 100755
index 0000000..f27d91a
--- /dev/null
+++ b/hidpp/hidpp/DeviceInfo.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+
+using namespace HIDPP;
+
+DeviceInfo ReceiverInfo (
+ DeviceInfo::Receiver
+);
+
+HIDPP10::MouseInfo G5Info (
+ &HIDPP10::ListSensor::S6006,
+ HIDPP10::IResolutionType0,
+ HIDPP10::NoProfile
+);
+
+HIDPP10::MouseInfo G9Info = {
+ &HIDPP10::ListSensor::S6090,
+ HIDPP10::IResolutionType0,
+ HIDPP10::G9ProfileType
+};
+
+HIDPP10::MouseInfo G9xInfo = {
+ &HIDPP10::RangeSensor::S9500,
+ HIDPP10::IResolutionType3,
+ HIDPP10::G500ProfileType
+};
+
+HIDPP10::MouseInfo G500Info = {
+ &HIDPP10::RangeSensor::S9500,
+ HIDPP10::IResolutionType3,
+ HIDPP10::G500ProfileType
+};
+
+HIDPP10::MouseInfo G500sInfo = {
+ &HIDPP10::RangeSensor::S9808,
+ HIDPP10::IResolutionType3,
+ HIDPP10::G500ProfileType
+};
+
+HIDPP10::MouseInfo G700Info = {
+ &HIDPP10::RangeSensor::S9500,
+ HIDPP10::IResolutionType3,
+ HIDPP10::G700ProfileType
+};
+
+HIDPP10::MouseInfo G700sInfo = {
+ &HIDPP10::RangeSensor::S9808,
+ HIDPP10::IResolutionType3,
+ HIDPP10::G700ProfileType
+};
+
+const DeviceInfo *HIDPP::getDeviceInfo (uint16_t product_id)
+{
+ switch (product_id) {
+ case 0xc52b: // Unifying receiver
+ case 0xc52f: // Nano receiver advanced
+ case 0xc531: // G700 receiver
+ case 0xc532: // Unifying receiver
+ case 0xc537: // G602 receiver
+ return &ReceiverInfo;
+
+ case ID::G5:
+ case ID::G5_2007:
+ case ID::G7:
+ return &G5Info;
+
+ case ID::G9:
+ return &G9Info;
+
+ case ID::G9x:
+ case ID::G9x_MW3:
+ return &G9xInfo;
+
+ case ID::G500:
+ return &G500Info;
+
+ case ID::G500s:
+ return &G500sInfo;
+
+ case ID::G700:
+ return &G700Info;
+
+ case ID::G700s:
+ return &G700sInfo;
+
+ default:
+ return nullptr;
+ }
+}
diff --git a/hidpp/hidpp/DeviceInfo.h b/hidpp/hidpp/DeviceInfo.h
new file mode 100755
index 0000000..7b78bdf
--- /dev/null
+++ b/hidpp/hidpp/DeviceInfo.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef DEVICE_INFO_H
+#define DEVICE_INFO_H
+
+#include
+
+namespace HIDPP
+{
+ struct DeviceInfo
+ {
+ enum Type {
+ Receiver,
+ Device,
+ } type;
+
+ DeviceInfo (Type type): type (type) {}
+ virtual ~DeviceInfo () {} // Make the structure polymorphic
+ };
+
+ const DeviceInfo *getDeviceInfo (uint16_t product_id);
+}
+
+#endif
+
diff --git a/hidpp/hidpp/Report.cpp b/hidpp/hidpp/Report.cpp
new file mode 100755
index 0000000..3f60f62
--- /dev/null
+++ b/hidpp/hidpp/Report.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+
+using namespace HIDPP;
+
+Report::InvalidReportID::InvalidReportID ()
+{
+}
+
+const char *Report::InvalidReportID::what () const noexcept
+{
+ return "Invalid Report ID for a HID++ report";
+}
+
+Report::InvalidReportLength::InvalidReportLength ()
+{
+}
+
+const char *Report::InvalidReportLength::what () const noexcept
+{
+ return "Invalid Report Length for a HID++ report";
+}
+
+// Offsets
+#define TYPE 0
+#define DEVICE_INDEX 1
+#define SUB_ID 2
+#define ADDRESS 3
+
+Report::Report (uint8_t type, const uint8_t *data, std::size_t length):
+ _header ({ type })
+{
+ switch (static_cast (type)) {
+ case Short:
+ _params.resize (ShortParamLength);
+ break;
+ case Long:
+ _params.resize (LongParamLength);
+ break;
+ default:
+ throw InvalidReportID ();
+ }
+ if (length != Report::HeaderLength-1+_params.size ())
+ throw InvalidReportLength ();
+
+ std::copy (data, data+HeaderLength-1, &_header[1]);
+ std::copy (data+HeaderLength-1, data+length, _params.begin ());
+}
+
+Report::Report (Type type,
+ HIDPP::DeviceIndex device_index,
+ uint8_t sub_id,
+ uint8_t address):
+ _header({ type, device_index, sub_id, address })
+{
+ switch (type) {
+ case Short:
+ _params.resize (ShortParamLength, 0);
+ break;
+ case Long:
+ _params.resize (LongParamLength, 0);
+ break;
+ }
+}
+
+Report::Report (HIDPP::DeviceIndex device_index,
+ uint8_t sub_id,
+ uint8_t address,
+ const std::vector ¶ms):
+ _header({ 0, device_index, sub_id, address }),
+ _params (params)
+{
+ switch (params.size ()) {
+ case ShortParamLength:
+ _header[TYPE] = Short;
+ break;
+ case LongParamLength:
+ _header[TYPE] = Long;
+ break;
+ default:
+ throw InvalidReportLength ();
+ }
+}
+
+Report::Report (Type type,
+ DeviceIndex device_index,
+ uint8_t feature_index,
+ unsigned int function,
+ unsigned int sw_id):
+ _header({ type, device_index, feature_index,
+ static_cast ((function & 0x0F) << 4 | (sw_id & 0x0F)) })
+{
+ switch (type) {
+ case Short:
+ _params.resize (ShortParamLength, 0);
+ break;
+ case Long:
+ _params.resize (LongParamLength, 0);
+ break;
+ }
+}
+
+Report::Report (DeviceIndex device_index,
+ uint8_t feature_index,
+ unsigned int function,
+ unsigned int sw_id,
+ const std::vector ¶ms):
+ _header({ 0, device_index, feature_index,
+ static_cast ((function & 0x0F) << 4 | (sw_id & 0x0F)) }),
+ _params (params)
+{
+ switch (params.size ()) {
+ case ShortParamLength:
+ _header[TYPE] = Short;
+ break;
+ case LongParamLength:
+ _header[TYPE] = Long;
+ break;
+ default:
+ throw InvalidReportLength ();
+ }
+}
+
+Report::Type Report::type () const
+{
+ return static_cast (_header[TYPE]);
+}
+
+DeviceIndex Report::deviceIndex () const
+{
+ return static_cast (_header[DEVICE_INDEX]);
+}
+
+uint8_t Report::subID () const
+{
+ return _header[SUB_ID];
+}
+
+void Report::setSubID (uint8_t sub_id)
+{
+ _header[SUB_ID] = sub_id;
+}
+
+uint8_t Report::address () const
+{
+ return _header[ADDRESS];
+}
+
+void Report::setAddress (uint8_t address)
+{
+ _header[ADDRESS] = address;
+}
+
+uint8_t Report::featureIndex () const
+{
+ return _header[SUB_ID];
+}
+
+void Report::setfeatureIndex (uint8_t feature_index)
+{
+ _header[SUB_ID] = feature_index;
+}
+
+unsigned int Report::function () const
+{
+ return (_header[ADDRESS] & 0xF0) >> 4;
+}
+
+void Report::setFunction (unsigned int function)
+{
+ _header[ADDRESS] = (function & 0x0F) << 4 | (_header[ADDRESS] & 0x0F);
+}
+
+unsigned int Report::softwareID () const
+{
+ return _header[ADDRESS] & 0x0F;
+}
+
+void Report::setSoftwareID (unsigned int sw_id)
+{
+ _header[ADDRESS] = (_header[ADDRESS] & 0xF0) | (sw_id & 0x0F);
+}
+
+std::size_t Report::paramLength () const
+{
+ return paramLength (static_cast (_header[TYPE]));
+}
+
+std::size_t Report::paramLength (Type type)
+{
+ switch (type) {
+ case Short:
+ return ShortParamLength;
+ case Long:
+ return LongParamLength;
+ default:
+ throw std::logic_error ("Invalid type");
+ }
+}
+
+std::vector &Report::params ()
+{
+ return _params;
+}
+
+const std::vector &Report::params () const
+{
+ return _params;
+}
+
+const std::vector Report::rawReport () const
+{
+ std::vector report (HeaderLength + _params.size ());
+ std::copy (_header.begin (), _header.end (), report.begin ());
+ std::copy (_params.begin (), _params.end (), report.begin () + HeaderLength);
+ return report;
+}
+
+bool Report::checkErrorMessage10 (uint8_t *sub_id,
+ uint8_t *address,
+ uint8_t *error_code) const
+{
+ if (static_cast (_header[TYPE]) != Short ||
+ _header[SUB_ID] != HIDPP10::ErrorMessage)
+ return false;
+
+ if (sub_id)
+ *sub_id = _header[3];
+ if (address)
+ *address = _params[0];
+ if (error_code)
+ *error_code = _params[1];
+ return true;
+}
+
+bool Report::checkErrorMessage20 (uint8_t *feature_index,
+ unsigned int *function,
+ unsigned int *sw_id,
+ uint8_t *error_code) const
+{
+ if (static_cast (_header[TYPE]) != Long ||
+ _header[SUB_ID] != HIDPP20::ErrorMessage)
+ return false;
+
+ if (feature_index)
+ *feature_index = _header[3];
+ if (function)
+ *function = (_params[0] & 0xF0) >> 4;
+ if (sw_id)
+ *sw_id = _params[0] & 0x0F;
+ if (error_code)
+ *error_code = _params[1];
+ return true;
+}
+
diff --git a/hidpp/hidpp/Report.h b/hidpp/hidpp/Report.h
new file mode 100755
index 0000000..1180625
--- /dev/null
+++ b/hidpp/hidpp/Report.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP_REPORT_H
+#define HIDPP_REPORT_H
+
+#include
+
+#include
+#include
+
+namespace HIDPP
+{
+
+/**
+ * Contains a HID++ report.
+ *
+ * \ingroup hidpp
+ *
+ * It can be used for both HID++ 1.0 or 2.0 reports.
+ *
+ * Common fields are:
+ * - Report type (see \ref Type)
+ * - Device index (see \ref DeviceIndex)
+ * - Parameters
+ *
+ * HID++ 1.0 fields are:
+ * - SubID
+ * - Address
+ *
+ * HID++ 2.0 fields are:
+ * - Feature index
+ * - Function index
+ * - Software ID
+ */
+class Report
+{
+public:
+ /**
+ * The type of the report (or report ID).
+ *
+ * The only difference between report types is the length of its
+ * parameters.
+ *
+ * \sa ShortParamLength LongParamLength
+ */
+ enum Type: uint8_t {
+ Short = 0x10, ///< Short reports use 3 byte parameters.
+ Long = 0x11, ///< Long report use 16 byte parameters.
+ };
+
+ /**
+ * Exception for reports with invalid report ID.
+ */
+ class InvalidReportID: std::exception
+ {
+ public:
+ InvalidReportID ();
+ virtual const char *what () const noexcept;
+ };
+ /**
+ * Exception for reports where the length is not the expected one
+ * from the report type.
+ */
+ class InvalidReportLength: std::exception
+ {
+ public:
+ InvalidReportLength ();
+ virtual const char *what () const noexcept;
+ };
+
+ /**
+ * Maximum length of a HID++ report.
+ */
+ static constexpr std::size_t MaxDataLength = 19;
+
+ /**
+ * Raw data constructor
+ *
+ * \param report_id Report ID
+ * \param data Raw report data
+ * \param length Length of the \p data array.
+ *
+ * \throws InvalidReportID
+ * \throws InvalidReportLength
+ */
+ Report (uint8_t report_id, const uint8_t *data, std::size_t length);
+
+ /**
+ * Access report type.
+ */
+ Type type () const;
+ /**
+ * Access report device index.
+ */
+ DeviceIndex deviceIndex () const;
+
+ /**
+ * \name HID++ 1.0
+ *
+ * @{
+ */
+
+ /**
+ * HID++ 1.0 constructor from type.
+ *
+ * Parameters size is set from \p type and is filled with zeroes.
+ */
+ Report (Type type,
+ DeviceIndex device_index,
+ uint8_t sub_id,
+ uint8_t address);
+ /**
+ * HID++ 1.0 constructor from parameters.
+ *
+ * The type of the report is guessed from \p params size.
+ *
+ * \throws InvalidReportLength
+ */
+ Report (DeviceIndex device_index,
+ uint8_t sub_id,
+ uint8_t address,
+ const std::vector ¶ms);
+
+ /**
+ * Access HID++ 1.0 report subID.
+ */
+ uint8_t subID () const;
+ /**
+ * Set HID++ 1.0 report subID.
+ */
+ void setSubID (uint8_t sub_id);
+
+ /**
+ * Access HID++ 1.0 report address.
+ */
+ uint8_t address () const;
+ /**
+ * Set HID++ 1.0 report address.
+ */
+ void setAddress (uint8_t address);
+
+ /**
+ * Check if the report is a HID++ 1.0 error report.
+ *
+ * Each pointer can be null and is then ignored.
+ *
+ * \param sub_id The subID of the report responsible for the error.
+ * \param address The address of the report responsible for the error.
+ * \param error_code The error code of the error.
+ *
+ * \return \c true if the report is a HID++ 1.0 error, \c false otherwise.
+ *
+ * \sa HIDPP10::Error
+ */
+ bool checkErrorMessage10 (uint8_t *sub_id, uint8_t *address, uint8_t *error_code) const;
+
+ /**@}*/
+
+ /**
+ * \name HID++ 2.0
+ *
+ * @{
+ */
+
+ /**
+ * HID++ 2.0 constructor from type.
+ *
+ * Parameters size is set from \p type and is filled with zeroes.
+ */
+ Report (Type type,
+ DeviceIndex device_index,
+ uint8_t feature_index,
+ unsigned int function,
+ unsigned int sw_id);
+ /**
+ * HID++ 2.0 constructor from parameters.
+ *
+ * The type of the report is guessed from \p params size.
+ *
+ * \throws InvalidReportLength
+ */
+ Report (DeviceIndex device_index,
+ uint8_t feature_index,
+ unsigned int function,
+ unsigned int sw_id,
+ const std::vector ¶ms);
+
+ /**
+ * Access HID++ 2.0 report feature index.
+ */
+ uint8_t featureIndex () const;
+ /**
+ * Set HID++ 2.0 report feature index.
+ */
+ void setfeatureIndex (uint8_t feature_index);
+
+ /**
+ * Access HID++ 2.0 report function.
+ */
+ unsigned int function () const;
+ /**
+ * Set HID++ 2.0 report function.
+ */
+ void setFunction (unsigned int function);
+
+ /**
+ * Access HID++ 2.0 software ID.
+ */
+ unsigned int softwareID () const;
+ /**
+ * Set HID++ 2.0 software ID.
+ */
+ void setSoftwareID (unsigned int sw_id);
+
+ /**
+ * Check if the report is a HID++ 2.0 error report.
+ *
+ * Each pointer can be null and is then ignored.
+ *
+ * \param feature_index The feature index of the report responsible for the error.
+ * \param function The function of the report responsible for the error.
+ * \param sw_id The software ID of the report responsible for the error.
+ * \param error_code The error code of the error.
+ *
+ * \return \c true if the report is a HID++ 2.0 error, \c false otherwise.
+ *
+ * \sa HIDPP20::Error
+ */
+ bool checkErrorMessage20 (uint8_t *feature_index, unsigned int *function, unsigned int *sw_id, uint8_t *error_code) const;
+
+ /**@}*/
+
+ /**
+ * Get the parameter length of the report.
+ */
+ std::size_t paramLength () const;
+ /**
+ * Get the parameter length for \p type.
+ */
+ static std::size_t paramLength (Type type);
+
+ /**
+ * Access the report parameters.
+ */
+ std::vector ¶ms ();
+ /**
+ * Read-only access to the report parameters.
+ */
+ const std::vector ¶ms () const;
+
+ /**
+ * Get the raw HID report (without the ID).
+ */
+ const std::vector rawReport () const;
+
+private:
+ static constexpr std::size_t HeaderLength = 4;
+ std::array _header;
+ std::vector _params;
+};
+
+}
+
+#endif
+
diff --git a/hidpp/hidpp/defs.h b/hidpp/hidpp/defs.h
new file mode 100755
index 0000000..122eeda
--- /dev/null
+++ b/hidpp/hidpp/defs.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP_DEFS_H
+#define HIDPP_DEFS_H
+
+#include
+#include
+
+namespace HIDPP
+{
+ /**
+ * \defgroup hidpp HID++
+ * @{
+ */
+
+ /**
+ * Short HID++ report parameter length.
+ */
+ constexpr std::size_t ShortParamLength = 3;
+ /**
+ * Long HID++ report parameter length.
+ */
+ constexpr std::size_t LongParamLength = 16;
+
+ /**
+ * HID++ device index.
+ *
+ * Receiver and wireless devices share the same
+ * hidraw device. The device index is used to direct
+ * the HID++ report to a particular device.
+ */
+ enum DeviceIndex: uint8_t {
+ DefaultDevice = 0xff, // used by receiver or corded or bluetooth devices
+ CordedDevice = 0, // used by older corded devices
+ WirelessDevice1 = 1,
+ WirelessDevice2 = 2,
+ WirelessDevice3 = 3,
+ WirelessDevice4 = 4,
+ WirelessDevice5 = 5,
+ WirelessDevice6 = 6,
+ };
+
+ /**@}*/
+}
+
+#endif
diff --git a/hidpp/hidpp/ids.h b/hidpp/hidpp/ids.h
new file mode 100755
index 0000000..91141a0
--- /dev/null
+++ b/hidpp/hidpp/ids.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP_IDS_H
+#define HIDPP_IDS_H
+
+#include
+
+namespace HIDPP
+{
+ namespace ID {
+ constexpr uint16_t G5 = 0xc041;
+ constexpr uint16_t G5_2007 = 0xc049;
+ constexpr uint16_t G7 = 0xc51a; // or is it the receiver ID?
+ constexpr uint16_t G9 = 0xc048;
+ constexpr uint16_t G9x = 0xc066;
+ constexpr uint16_t G9x_MW3 = 0xc249;
+ constexpr uint16_t G500 = 0xc068;
+ constexpr uint16_t G700 = 0xc06b;
+ constexpr uint16_t G500s = 0xc24e;
+ constexpr uint16_t G700s = 0xc07c;
+ }
+}
+
+#endif
diff --git a/hidpp/hidpp10/Address.cpp b/hidpp/hidpp10/Address.cpp
new file mode 100755
index 0000000..66655a9
--- /dev/null
+++ b/hidpp/hidpp10/Address.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+using namespace HIDPP10;
+
+bool Address::operator< (const Address &other) const
+{
+ return page < other.page ||
+ (page == other.page && offset < other.offset);
+}
+
diff --git a/hidpp/hidpp10/Address.h b/hidpp/hidpp10/Address.h
new file mode 100755
index 0000000..9e755ba
--- /dev/null
+++ b/hidpp/hidpp10/Address.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_ADDRESS_H
+#define HIDPP10_ADDRESS_H
+
+#include
+
+namespace HIDPP10
+{
+
+struct Address {
+ uint8_t page;
+ uint8_t offset;
+
+ bool operator< (const Address &other) const;
+};
+
+}
+
+#endif
+
diff --git a/hidpp/hidpp10/Device.cpp b/hidpp/hidpp10/Device.cpp
new file mode 100755
index 0000000..809789d
--- /dev/null
+++ b/hidpp/hidpp10/Device.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+using namespace HIDPP10;
+
+Device::Device (const std::string &path, HIDPP::DeviceIndex device_index):
+ HIDPP::Device (path, device_index)
+{
+ // TODO: check version
+}
+
+template
+void Device::accessRegister (uint8_t address,
+ const std::vector *params,
+ std::vector *results)
+{
+ std::vector in;
+ if (params) {
+ in = *params;
+ in.resize (params_length, 0);
+ }
+ else {
+ in.resize (params_length, 0);
+ }
+ HIDPP::Report request (deviceIndex (),
+ sub_id, address, in);
+ sendReport (request);
+
+ while (true) {
+ HIDPP::Report response = getReport ();
+
+ uint8_t r_sub_id, r_address, error_code;
+ if (response.checkErrorMessage10 (&r_sub_id, &r_address, &error_code)) {
+ if (r_sub_id != sub_id || r_address != address) {
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored error message with wrong subID or address"
+ << std::endl;
+ continue;
+ }
+
+ Log::printf (Log::Debug, "Received error message with code 0x%02hhx\n", error_code);
+ throw Error (static_cast (error_code));
+ }
+
+ if (response.subID () != sub_id ||
+ response.address () != address) {
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored report with wrong subID or address"
+ << std::endl;
+ continue;
+ }
+
+ if (response.paramLength () != results_length)
+ throw std::runtime_error ("Invalid result length");
+
+ if (results)
+ *results = response.params ();
+ return;
+ }
+}
+
+void Device::setRegister (uint8_t address,
+ const std::vector ¶ms,
+ std::vector *results)
+{
+ if (params.size () <= HIDPP::ShortParamLength) {
+ Log::printf (Log::Debug, "Setting short register 0x%02hhx\n", address);
+ Log::printBytes (Log::Debug, "Parameters:",
+ params.begin (), params.end ());
+
+ accessRegister
+ (address, ¶ms, results);
+
+ if (results)
+ Log::printBytes (Log::Debug, "Results:",
+ results->begin (), results->end ());
+ }
+ else if (params.size () <= HIDPP::LongParamLength) {
+ Log::printf (Log::Debug, "Setting long register 0x%02hhx\n", address);
+ Log::printBytes (Log::Debug, "Parameters:",
+ params.begin (), params.end ());
+
+ accessRegister
+ (address, ¶ms, results);
+
+ if (results)
+ Log::printBytes (Log::Debug, "Results:",
+ results->begin (), results->end ());
+ }
+ else
+ throw std::logic_error ("Register too long");
+
+}
+
+void Device::getRegister (uint8_t address,
+ const std::vector *params,
+ std::vector &results)
+{
+ if (results.size () <= HIDPP::ShortParamLength) {
+ Log::printf (Log::Debug, "Getting short register 0x%02hhx\n", address);
+ if (params)
+ Log::printBytes (Log::Debug, "Parameters:",
+ params->begin (), params->end ());
+
+ accessRegister
+ (address, params, &results);
+
+ Log::printBytes (Log::Debug, "Results:",
+ results.begin (), results.end ());
+ }
+ else if (results.size () <= HIDPP::LongParamLength) {
+ Log::printf (Log::Debug, "Getting long register 0x%02hhx\n", address);
+ if (params)
+ Log::printBytes (Log::Debug, "Parameters:",
+ params->begin (), params->end ());
+
+ accessRegister
+ (address, params, &results);
+
+ Log::printBytes (Log::Debug, "Results:",
+ results.begin (), results.end ());
+ }
+ else
+ throw std::logic_error ("Register too long");
+}
+
+void Device::sendDataPacket (uint8_t sub_id, uint8_t seq_num,
+ const std::vector ¶ms,
+ bool wait_for_ack)
+{
+ Log::printf (Log::Debug, "Sending data packet %hhu\n", seq_num);
+ Log::printBytes (Log::Debug, "Data packet", params.begin (), params.end ());
+
+ HIDPP::Report packet (deviceIndex (),
+ sub_id,
+ seq_num,
+ params);
+ sendReport (packet);
+
+ if (!wait_for_ack)
+ return;
+
+ while (true) {
+ HIDPP::Report response = getReport ();
+
+ if (response.deviceIndex () != deviceIndex () ||
+ response.subID () != SendDataAcknowledgement) {
+ Log::debug () << __FUNCTION__ << ": "
+ << "Ignored notification with wrong deviceIndex or subID"
+ << std::endl;
+ continue;
+ }
+
+ if (response.address () == 1 && response.params ()[0] == seq_num) {
+ /* Expected notification */
+ Log::printf (Log::Debug, "Data packet %hhu acknowledged\n", seq_num);
+ return;
+ }
+ else {
+ /* The notification is an error message */
+ Log::printf (Log::Debug, "Data packet %hhu: error 0x%02hhx\n",
+ seq_num, response.address ());
+ throw WriteError (response.address ());
+ }
+ }
+}
+
diff --git a/hidpp/hidpp10/Device.h b/hidpp/hidpp10/Device.h
new file mode 100755
index 0000000..bf78a94
--- /dev/null
+++ b/hidpp/hidpp10/Device.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_DEVICE_H
+#define HIDPP10_DEVICE_H
+
+#include
+#include
+
+namespace HIDPP10
+{
+
+class Device: public HIDPP::Device
+{
+public:
+ Device (const std::string &path, HIDPP::DeviceIndex device_index = HIDPP::DefaultDevice);
+
+ void setRegister (uint8_t address,
+ const std::vector ¶ms,
+ std::vector *results);
+ void getRegister (uint8_t address,
+ const std::vector *params,
+ std::vector &results);
+
+ void sendDataPacket (uint8_t sub_id, uint8_t seq_num,
+ const std::vector ¶ms,
+ bool wait_for_ack = false);
+private:
+ template
+ void accessRegister (uint8_t address,
+ const std::vector *params,
+ std::vector *results);
+};
+
+}
+
+#endif
diff --git a/hidpp/hidpp10/DeviceInfo.h b/hidpp/hidpp10/DeviceInfo.h
new file mode 100755
index 0000000..ce3859f
--- /dev/null
+++ b/hidpp/hidpp10/DeviceInfo.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_DEVICE_INFO_H
+#define HIDPP10_DEVICE_INFO_H
+
+#include
+
+#include
+#include
+#include
+
+namespace HIDPP10
+{
+ struct MouseInfo: HIDPP::DeviceInfo
+ {
+ const Sensor *sensor;
+ IResolutionType iresolution_type;
+ ProfileType profile_type;
+
+ MouseInfo (const Sensor *sensor,
+ IResolutionType iresolution_type,
+ ProfileType profile_type):
+ HIDPP::DeviceInfo (HIDPP::DeviceInfo::Device),
+ sensor (sensor),
+ iresolution_type (iresolution_type),
+ profile_type (profile_type)
+ {
+ }
+ };
+
+ inline const MouseInfo *getMouseInfo (uint16_t product_id)
+ {
+ return dynamic_cast (HIDPP::getDeviceInfo (product_id));
+ }
+}
+
+#endif
diff --git a/hidpp/hidpp10/Error.cpp b/hidpp/hidpp10/Error.cpp
new file mode 100755
index 0000000..2662243
--- /dev/null
+++ b/hidpp/hidpp10/Error.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+using namespace HIDPP10;
+
+Error::Error (ErrorCode error_code):
+ _error_code (error_code)
+{
+}
+
+const char *Error::what () const noexcept
+{
+ switch (_error_code) {
+ case Success:
+ return "Success";
+ case InvalidSubID:
+ return "Invalid sub ID";
+ case InvalidAddress:
+ return "Invalid address";
+ case InvalidValue:
+ return "Invalid value";
+ case ConnectFail:
+ return "Connect fail";
+ case TooManyDevices:
+ return "Too many devices";
+ case AlreadyExists:
+ return "Already exists";
+ case Busy:
+ return "Busy";
+ case UnknownDevice:
+ return "Unknown device";
+ case ResourceError:
+ return "Resource error";
+ case RequestUnavailable:
+ return "Request unavailable";
+ case InvalidParamValue:
+ return "Invalid param value";
+ case WrongPINCode:
+ return "Wrong PIN code";
+ default:
+ return "Unknown error code";
+ }
+}
+
+Error::ErrorCode Error::errorCode () const
+{
+ return _error_code;
+}
+
diff --git a/hidpp/hidpp10/Error.h b/hidpp/hidpp10/Error.h
new file mode 100755
index 0000000..e7af32a
--- /dev/null
+++ b/hidpp/hidpp10/Error.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_ERROR_H
+#define HIDPP10_ERROR_H
+
+#include
+
+#include
+
+namespace HIDPP10
+{
+
+class Error: public std::exception
+{
+public:
+ enum ErrorCode: uint8_t {
+ Success = 0x00,
+ InvalidSubID = 0x01,
+ InvalidAddress = 0x02,
+ InvalidValue = 0x03,
+ ConnectFail = 0x04,
+ TooManyDevices = 0x05,
+ AlreadyExists = 0x06,
+ Busy = 0x07,
+ UnknownDevice = 0x08,
+ ResourceError = 0x09,
+ RequestUnavailable = 0x0A,
+ InvalidParamValue = 0x0B,
+ WrongPINCode = 0x0C,
+ };
+
+ Error (ErrorCode error_code);
+
+ virtual const char *what () const noexcept;
+ ErrorCode errorCode () const;
+
+private:
+ ErrorCode _error_code;
+};
+
+}
+
+#endif
diff --git a/hidpp/hidpp10/IIndividualFeatures.cpp b/hidpp/hidpp10/IIndividualFeatures.cpp
new file mode 100755
index 0000000..2ff583e
--- /dev/null
+++ b/hidpp/hidpp10/IIndividualFeatures.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+
+using namespace HIDPP10;
+
+IIndividualFeatures::IIndividualFeatures (Device *dev):
+ _dev (dev)
+{
+}
+
+unsigned int IIndividualFeatures::flags ()
+{
+ std::vector results (HIDPP::ShortParamLength);
+ _dev->getRegister (EnableIndividualFeatures, nullptr, results);
+ unsigned int flags = 0;
+ for (unsigned int i = 0; i < 3; ++i)
+ flags |= results[i] << (i*8);
+ return flags;
+}
+
+void IIndividualFeatures::setFlags (unsigned int f)
+{
+ std::vector params (HIDPP::ShortParamLength);
+ for (unsigned int i = 0; i < 3; ++i)
+ params[i] = (f >> (i*8)) & 0xFF;
+ _dev->setRegister (EnableIndividualFeatures, params, nullptr);
+}
+
+bool IIndividualFeatures::hasFlag (IndividualFeature feature)
+{
+ return flags () & feature;
+}
+
+void IIndividualFeatures::setFlag (IndividualFeature feature)
+{
+ unsigned int f = flags ();
+ f |= feature;
+ setFlags (f);
+}
+
+void IIndividualFeatures::unsetFlag (IndividualFeature feature)
+{
+ unsigned int f = flags ();
+ f &= ~feature;
+ setFlags (f);
+}
+
diff --git a/hidpp/hidpp10/IIndividualFeatures.h b/hidpp/hidpp10/IIndividualFeatures.h
new file mode 100755
index 0000000..147f1af
--- /dev/null
+++ b/hidpp/hidpp10/IIndividualFeatures.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_IINDIVIDUALFEATURES_H
+#define HIDPP10_IINDIVIDUALFEATURES_H
+
+namespace HIDPP10
+{
+
+class Device;
+
+class IIndividualFeatures
+{
+public:
+ enum IndividualFeature: unsigned int {
+ SpecialButtonFunction = 1<<1,
+ EnhancedKeyUsage = 1<<2,
+ FastForwardRewind = 1<<3,
+ ScrollingAcceleration = 1<<6,
+ ButtonsControlResolution = 1<<7,
+ InhibitLockKeySound = 1<<16,
+ MXAir3DEngine = 1<<18,
+ LEDControl = 1<<19,
+ };
+
+ IIndividualFeatures (Device *dev);
+
+ unsigned int flags ();
+ void setFlags (unsigned int flags);
+
+ bool hasFlag (IndividualFeature feature);
+ void setFlag (IndividualFeature feature);
+ void unsetFlag (IndividualFeature feature);
+
+private:
+ Device *_dev;
+};
+
+}
+
+#endif
+
+
diff --git a/hidpp/hidpp10/IMemory.cpp b/hidpp/hidpp10/IMemory.cpp
new file mode 100755
index 0000000..a8f4f14
--- /dev/null
+++ b/hidpp/hidpp10/IMemory.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+
+#include
+
+using namespace HIDPP10;
+
+IMemory::IMemory (Device *dev):
+ _dev (dev)
+{
+}
+
+int IMemory::readSome (Address address, uint8_t *buffer, std::size_t maxlen)
+{
+ std::vector params (HIDPP::ShortParamLength);
+ params[0] = address.page;
+ params[1] = address.offset;
+ std::vector results (HIDPP::LongParamLength);
+ _dev->getRegister (MemoryRead, ¶ms, results);
+ std::size_t len = std::min (HIDPP::LongParamLength, maxlen);
+ std::copy (results.begin (), results.begin () + len, buffer);
+ return len;
+}
+
+void IMemory::readMem (Address address, std::vector &data)
+{
+ std::size_t read = 0;
+ while (read < data.size ()) {
+ std::size_t len = readSome (address, &data[read], data.size () - read);
+ address.offset += len/2;
+ read += len;
+ }
+}
+
+void IMemory::writeMem (Address address, const std::vector &data)
+{
+ static constexpr std::size_t HeaderLength = 9;
+ static constexpr std::size_t FirstPacketDataLength =
+ HIDPP::LongParamLength - HeaderLength;
+
+ /*
+ * Init sequence number
+ */
+ resetSequenceNumber ();
+
+ /*
+ * Start sending packets
+ */
+ bool first = true;
+ std::size_t sent = 0;
+ uint8_t seq_num = 0;
+ while (sent < data.size ()) {
+ uint8_t sub_id;
+ std::vector params (HIDPP::LongParamLength);
+ if (first) {
+ sub_id = SendDataBeginAck;
+ /* First packet header */
+ params[0] = 0x01; // Unknown meaning
+ params[1] = address.page;
+ params[2] = address.offset;
+ writeBE (params, 5, data.size ());
+ /* Start of data */
+ if (data.size () < FirstPacketDataLength) {
+ std::copy (data.begin (), data.end (),
+ params.begin () + HeaderLength);
+ sent = data.size ();
+ }
+ else {
+ std::copy (data.begin (),
+ data.begin () + FirstPacketDataLength,
+ params.begin () + HeaderLength);
+ sent += FirstPacketDataLength;
+ }
+ first = false;
+ }
+ else {
+ sub_id = SendDataContinueAck;
+ if (data.size () < HIDPP::LongParamLength) {
+ std::copy (data.begin () + sent,
+ data.end (),
+ params.begin ());
+ sent = data.size ();
+ }
+ else {
+ std::copy (data.begin () + sent,
+ data.begin () + sent + HIDPP::LongParamLength,
+ params.begin ());
+ sent += HIDPP::LongParamLength;
+ }
+ }
+ _dev->sendDataPacket (sub_id, seq_num, params, true);
+ seq_num++;
+ }
+}
+
+void IMemory::writePage (uint8_t page, const std::vector &data)
+{
+ if (data.size () > 512)
+ throw std::logic_error ("page too big");
+
+ fillPage (page);
+ writeMem ({page, 0}, data);
+}
+
+void IMemory::resetSequenceNumber ()
+{
+ std::vector params (HIDPP::ShortParamLength);
+ params[0] = 1;
+ _dev->setRegister (ResetSeqNum, params, nullptr);
+}
+
+void IMemory::fillPage (uint8_t page)
+{
+ std::vector params (HIDPP::LongParamLength);
+ params[0] = Fill;
+ params[6] = page;
+ _dev->setRegister (MemoryOperation, params, nullptr);
+}
+
diff --git a/hidpp/hidpp10/IMemory.h b/hidpp/hidpp10/IMemory.h
new file mode 100755
index 0000000..0566bbc
--- /dev/null
+++ b/hidpp/hidpp10/IMemory.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_IMEMORY_H
+#define HIDPP10_IMEMORY_H
+
+#include
+#include
+
+#include
+
+namespace HIDPP10
+{
+
+class Device;
+
+class IMemory
+{
+public:
+ enum MemoryOp: uint8_t {
+ Fill = 2,
+ Copy = 3,
+ };
+
+ IMemory (Device *dev);
+
+ int readSome (Address address, uint8_t *buffer, std::size_t maxlen);
+ void readMem (Address address, std::vector &data);
+
+
+ void writeMem (Address address, const std::vector &data);
+ void writePage (uint8_t page, const std::vector &data);
+
+ void resetSequenceNumber ();
+ void fillPage (uint8_t page);
+
+private:
+ Device *_dev;
+};
+
+}
+
+#endif
diff --git a/hidpp/hidpp10/IProfile.cpp b/hidpp/hidpp10/IProfile.cpp
new file mode 100755
index 0000000..122c7ac
--- /dev/null
+++ b/hidpp/hidpp10/IProfile.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+
+using namespace HIDPP10;
+
+IProfile::IProfile (Device *dev):
+ _dev (dev)
+{
+}
+
+int IProfile::activeProfile ()
+{
+ std::vector results (HIDPP::ShortParamLength);
+ _dev->getRegister (CurrentProfile, nullptr, results);
+ if (results[0] == FactoryDefault)
+ return -1;
+ if (results[0] == ProfileIndex)
+ return results[1];
+ throw std::runtime_error ("Invalid active profile type.");
+}
+
+void IProfile::loadFactoryDefault ()
+{
+ std::vector params (HIDPP::ShortParamLength);
+ params[0] = FactoryDefault;
+ _dev->setRegister (CurrentProfile, params, nullptr);
+}
+
+void IProfile::loadProfileFromIndex (unsigned int index)
+{
+ std::vector params (HIDPP::ShortParamLength);
+ params[0] = ProfileIndex;
+ params[1] = index;
+ _dev->setRegister (CurrentProfile, params, nullptr);
+}
+
+void IProfile::loadProfileFromAddress (Address address)
+{
+ std::vector params (HIDPP::ShortParamLength);
+ params[0] = ProfileAddress;
+ params[1] = address.page;
+ params[2] = address.offset;
+ _dev->setRegister (CurrentProfile, params, nullptr);
+}
+
+void IProfile::reloadActiveProfile ()
+{
+ std::vector current_value (HIDPP::ShortParamLength);
+ _dev->getRegister (CurrentProfile, nullptr, current_value);
+ _dev->setRegister (CurrentProfile, current_value, nullptr);
+}
+
diff --git a/hidpp/hidpp10/IProfile.h b/hidpp/hidpp10/IProfile.h
new file mode 100755
index 0000000..04847b8
--- /dev/null
+++ b/hidpp/hidpp10/IProfile.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_IPROFILE_H
+#define HIDPP10_IPROFILE_H
+
+#include
+
+namespace HIDPP10
+{
+
+class Device;
+
+class IProfile
+{
+public:
+ IProfile (Device *dev);
+
+ enum ProfileType: uint8_t {
+ ProfileIndex = 0x00,
+ ProfileAddress = 0x01,
+ FactoryDefault = 0xFF,
+ };
+
+ /**
+ * Get active profile.
+ *
+ * Returns -1 for factory default, or a positive
+ * integer for current profile index.
+ */
+ int activeProfile ();
+
+ void loadFactoryDefault ();
+ void loadProfileFromIndex (unsigned int index);
+ void loadProfileFromAddress (Address address);
+
+ void reloadActiveProfile ();
+
+private:
+ Device *_dev;
+};
+
+}
+
+#endif
+
+
diff --git a/hidpp/hidpp10/IReceiver.cpp b/hidpp/hidpp10/IReceiver.cpp
new file mode 100755
index 0000000..be8869c
--- /dev/null
+++ b/hidpp/hidpp10/IReceiver.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+using namespace HIDPP10;
+
+IReceiver::IReceiver (Device *dev):
+ _dev (dev)
+{
+}
+
+void IReceiver::getDeviceInformation (unsigned int device,
+ uint8_t *destination_id,
+ uint8_t *report_interval,
+ uint16_t *wpid,
+ DeviceType *type)
+{
+ if (device >= 16)
+ throw std::out_of_range ("Device index too big");
+
+ std::vector params (HIDPP::ShortParamLength),
+ results (HIDPP::LongParamLength);
+
+ params[0] = DeviceInformation | (device & 0x0F);
+
+ _dev->getRegister (DevicePairingInfo, ¶ms, results);
+
+ if (params[0] != results[0])
+ throw std::runtime_error ("Invalid DevicePairingInfo type");
+
+ if (destination_id)
+ *destination_id = results[1];
+ if (report_interval)
+ *report_interval = results[2];
+ if (wpid)
+ *wpid = readBE (results, 3);
+ if (type)
+ *type = static_cast (results[7]);
+}
+
+void IReceiver::getDeviceExtendedInformation (unsigned int device,
+ uint32_t *serial,
+ uint32_t *report_types,
+ PowerSwitchLocation *ps_loc)
+{
+ if (device >= 16)
+ throw std::out_of_range ("Device index too big");
+
+ std::vector params (HIDPP::ShortParamLength),
+ results (HIDPP::LongParamLength);
+
+ params[0] = ExtendedDeviceInformation | (device & 0x0F);
+
+ _dev->getRegister (DevicePairingInfo, ¶ms, results);
+
+ if (params[0] != results[0])
+ throw std::runtime_error ("Invalid DevicePairingInfo type");
+
+ if (serial)
+ *serial = readBE (results, 1);
+ if (report_types)
+ *report_types = readBE (results, 5);
+ if (ps_loc)
+ *ps_loc = static_cast (results[9] & 0x0F);
+}
+
+std::string IReceiver::getDeviceName (unsigned int device)
+{
+ if (device >= 16)
+ throw std::out_of_range ("Device index too big");
+
+ std::vector params (HIDPP::ShortParamLength),
+ results (HIDPP::LongParamLength);
+
+ params[0] = DeviceName | (device & 0x0F);
+
+ _dev->getRegister (DevicePairingInfo, ¶ms, results);
+
+ if (params[0] != results[0])
+ throw std::runtime_error ("Invalid DevicePairingInfo type");
+
+ std::size_t length = results[1];
+ return std::string (reinterpret_cast (&results[2]), std::min (length, 14ul));
+}
diff --git a/hidpp/hidpp10/IReceiver.h b/hidpp/hidpp10/IReceiver.h
new file mode 100755
index 0000000..e8ce18e
--- /dev/null
+++ b/hidpp/hidpp10/IReceiver.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_IRECEIVER_H
+#define HIDPP10_IRECEIVER_H
+
+#include
+#include
+
+namespace HIDPP10
+{
+
+class Device;
+
+class IReceiver
+{
+public:
+ enum InformationType: uint8_t {
+ DeviceInformation = 0x20,
+ ExtendedDeviceInformation = 0x30,
+ DeviceName = 0x40,
+ };
+
+ enum DeviceType: uint8_t {
+ Unknown = 0x00,
+ Keyboard = 0x01,
+ Mouse = 0x02,
+ Numpad = 0x03,
+ Presenter = 0x04,
+ Trackball = 0x08,
+ Touchpad = 0x09,
+ };
+
+ enum PowerSwitchLocation {
+ Base = 0x1,
+ TopCase = 0x2,
+ TopRightCornerEdge = 0x3,
+ Other = 0x4,
+ TopLeftCorner = 0x5,
+ BottomLeftCorner = 0x6,
+ TopRightCorner = 0x7,
+ BottomRightCorner = 0x8,
+ TopEdge = 0x9,
+ RightEdge = 0xA,
+ LeftEdge = 0xB,
+ BottomEdge = 0xC,
+ };
+
+ IReceiver (Device *dev);
+
+ void getDeviceInformation (unsigned int device,
+ uint8_t *destination_id,
+ uint8_t *report_interval,
+ uint16_t *wpid,
+ DeviceType *type);
+ void getDeviceExtendedInformation (unsigned int device,
+ uint32_t *serial,
+ uint32_t *report_types,
+ PowerSwitchLocation *ps_loc);
+ std::string getDeviceName (unsigned int device);
+
+private:
+ Device *_dev;
+};
+
+}
+
+#endif
+
diff --git a/hidpp/hidpp10/IResolution.cpp b/hidpp/hidpp10/IResolution.cpp
new file mode 100755
index 0000000..0c4411b
--- /dev/null
+++ b/hidpp/hidpp10/IResolution.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+using namespace HIDPP10;
+
+IResolution0::IResolution0 (Device *dev, const Sensor *sensor):
+ _dev (dev), _sensor (sensor)
+{
+}
+
+unsigned int IResolution0::getCurrentResolution ()
+{
+ std::vector results (HIDPP::ShortParamLength);
+ _dev->getRegister (SensorResolution, nullptr, results);
+ return _sensor->toDPI (results[0]);
+}
+
+void IResolution0::setCurrentResolution (unsigned int dpi)
+{
+ std::vector params (HIDPP::ShortParamLength);
+ params[0] = _sensor->fromDPI (dpi);
+ _dev->setRegister (SensorResolution, params, nullptr);
+}
+
+IResolution3::IResolution3 (Device *dev, const Sensor *sensor):
+ _dev (dev), _sensor (sensor)
+{
+}
+
+void IResolution3::getCurrentResolution (unsigned int &x_dpi, unsigned int &y_dpi)
+{
+ std::vector results (HIDPP::LongParamLength);
+ _dev->getRegister (SensorResolution, nullptr, results);
+ x_dpi = _sensor->toDPI (readLE (results, 0));
+ y_dpi = _sensor->toDPI (readLE (results, 2));
+}
+
+void IResolution3::setCurrentResolution (unsigned int x_dpi, unsigned int y_dpi)
+{
+ std::vector params (HIDPP::LongParamLength);
+ writeLE (params, 0, _sensor->fromDPI (x_dpi));
+ writeLE (params, 2, _sensor->fromDPI (y_dpi));
+ _dev->setRegister (SensorResolution, params, nullptr);
+}
+
+bool IResolution3::getAngleSnap ()
+{
+ std::vector results (HIDPP::LongParamLength);
+ _dev->getRegister (SensorResolution, nullptr, results);
+ switch (results[5]) {
+ case 0x01:
+ return false;
+ case 0x02:
+ return true;
+ default:
+ throw std::runtime_error ("Invalid angle snap value");
+ }
+}
+
+void IResolution3::setAngleSnap (bool angle_snap)
+{
+ std::vector params (HIDPP::LongParamLength);
+ params[5] = angle_snap ? 0x02 : 0x01;
+ _dev->setRegister (SensorResolution, params, nullptr);
+}
+
diff --git a/hidpp/hidpp10/IResolution.h b/hidpp/hidpp10/IResolution.h
new file mode 100755
index 0000000..e845e93
--- /dev/null
+++ b/hidpp/hidpp10/IResolution.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef HIDPP10_IRESOLUTION_H
+#define HIDPP10_IRESOLUTION_H
+
+namespace HIDPP10
+{
+
+enum IResolutionType {
+ IResolutionType0,
+ IResolutionType3,
+};
+
+class Device;
+class Sensor;
+
+class IResolution0
+{
+public:
+ IResolution0 (Device *dev, const Sensor *sensor);
+
+ unsigned int getCurrentResolution ();
+ void setCurrentResolution (unsigned int dpi);
+
+private:
+ Device *_dev;
+ const Sensor *_sensor;
+};
+
+class IResolution3
+{
+public:
+ IResolution3 (Device *dev, const Sensor *sensor);
+
+ void getCurrentResolution (unsigned int &x_dpi, unsigned int &y_dpi);
+ void setCurrentResolution (unsigned int x_dpi, unsigned int y_dpi);
+
+ bool getAngleSnap ();
+ void setAngleSnap (bool angle_snap);
+
+private:
+ Device *_dev;
+ const Sensor *_sensor;
+};
+
+}
+
+#endif
diff --git a/hidpp/hidpp10/Macro.cpp b/hidpp/hidpp10/Macro.cpp
new file mode 100755
index 0000000..6b4450d
--- /dev/null
+++ b/hidpp/hidpp10/Macro.cpp
@@ -0,0 +1,969 @@
+/*
+ * Copyright 2015 Clément Vuchener
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include
+
+#include
+#include
+#include
+
+#include