1
0
mirror of https://github.com/MatMoul/g810-led.git synced 2024-12-23 09:16:11 +00:00

Switch to hidapi

This commit is contained in:
MatMoul 2017-01-21 22:45:48 +01:00
parent cdaae30aa2
commit bcdcee88f1
6 changed files with 273 additions and 148 deletions

View File

@ -6,21 +6,29 @@
* make * make
## Dependencies :</br> ## Dependencies :</br>
* libusb * hidapi or libusb
* systemd
## hidapi vs libusb :</br>
hidapi is the new implementation but need to be tested.</br>
hidapi is very more speed than libusb (~20ms vs ~150ms).</br>
hidapi seem not work on CentOS, writing on hidraw is not allowed.</br>
hidapi is recommended but if you encounter problem on your system, switch to libusb.</br>
## Installation of dependencies :</br> ## Installation of dependencies :</br>
ArchLinux :</br> ArchLinux :</br>
`sudo pacman -S git gcc make libusb`</br> `sudo pacman -S git gcc make hidapi` (for hidapi)</br>
`sudo pacman -S git gcc make libusb` (for libusb)</br>
Debian :</br> Debian :</br>
`sudo apt-get install git g++ make libusb-1.0-0-dev`</br> `sudo apt-get install git g++ make libhidapi-dev` (for hidapi)</br>
`sudo apt-get install git g++ make libusb-1.0-0-dev` (for libusb)</br>
Fedora :</br> Fedora :</br>
`sudo dnf install git make gcc-c++ libusb-devel`</br> `sudo dnf install git make gcc-c++ hidapi-devel` (for hidapi)</br>
`sudo dnf install git make gcc-c++ libusbx-devel` (for libusb)</br>
## Installation :</br> ## Installation :</br>
`git clone https://github.com/MatMoul/g810-led.git`</br> `git clone https://github.com/MatMoul/g810-led.git`</br>
`cd g810-led`</br> `cd g810-led`</br>
`make`</br> `make` or `make LIB=libusb`</br>
`sudo make install`</br> `sudo make install`</br>
## Update :</br> ## Update :</br>
@ -30,8 +38,8 @@ Same as install, but your profile and reboot files are preserved.</br>
`sudo make uninstall`</br> `sudo make uninstall`</br>
## Boot profiles :</br> ## Boot profiles :</br>
g810-led has 2 systemd units (g810-led and g810-led-reboot).</br> If your system use systemd, g810-led has 2 systemd units (g810-led and g810-led-reboot).</br>
These 2 units set the keyboard profile on boot and reboot.</br> These 2 units set the keyboard profile on boot and reboot.</br>
Profiles are stored in /etc/g810 :</br> Profiles are stored in /etc/g810-led :</br>
* /etc/g810/profile * /etc/g810-led/profile
* /etc/g810/reboot * /etc/g810-led/reboot

View File

@ -1,16 +1,23 @@
CC=g++ CC=g++
CFLAGS=-Wall -O2 -std=gnu++11 CFLAGS=-Wall -O2 -std=gnu++11
LDFLAGS=-lusb-1.0 LIB?=hidapi
ifeq ($(LIB),libusb)
CPPFLAGS=-Dlibusb
LDFLAGS=-lusb-1.0
else
CPPFLAGS=-Dhidapi
LDFLAGS=-lhidapi-hidraw
endif
PROGN=g810-led PROGN=g810-led
SYSTEMDDIR?=/usr/lib/systemd SYSTEMDDIR?=/usr/lib/systemd
.PHONY: all debug clean .PHONY: all debug clean install uninstall
all: bin/$(PROGN) all: bin/$(PROGN)
bin/$(PROGN): src/main.cpp src/helpers/*.cpp src/helpers/*.h src/classes/*.cpp src/classes/*.h bin/$(PROGN): src/main.cpp src/helpers/*.cpp src/helpers/*.h src/classes/*.cpp src/classes/*.h
@mkdir -p bin @mkdir -p bin
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(CC) $(CPPFLAGS) $(CFLAGS) $^ -o $@ $(LDFLAGS)
debug: CFLAGS += -g -Wextra -pedantic debug: CFLAGS += -g -Wextra -pedantic
debug: bin/$(PROGN) debug: bin/$(PROGN)
@ -20,36 +27,43 @@ clean:
install: install:
@install -m 755 -d \ @install -m 755 -d \
$(DESTDIR)/etc/$(PROGN)/samples \
$(DESTDIR)/etc/udev/rules.d \ $(DESTDIR)/etc/udev/rules.d \
$(DESTDIR)$(SYSTEMDDIR)/system \
$(DESTDIR)/usr/bin $(DESTDIR)/usr/bin
@cp bin/$(PROGN) $(DESTDIR)/usr/bin @cp bin/$(PROGN) $(DESTDIR)/usr/bin
@test -s $(DESTDIR)/usr/bin/g410-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g410-led @test -s $(DESTDIR)/usr/bin/g410-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g410-led
@test -s $(DESTDIR)/usr/bin/g610-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g610-led @test -s $(DESTDIR)/usr/bin/g610-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g610-led
@test -s $(DESTDIR)/usr/bin/g910-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g910-led @test -s $(DESTDIR)/usr/bin/g910-led || ln -s /usr/bin/$(PROGN) $(DESTDIR)/usr/bin/g910-led
@cp udev/$(PROGN).rules $(DESTDIR)/etc/udev/rules.d @cp udev/$(PROGN).rules $(DESTDIR)/etc/udev/rules.d
@cp sample_profiles/* $(DESTDIR)/etc/$(PROGN)/samples
@test -s $(DESTDIR)/etc/$(PROGN)/profile || cp $(DESTDIR)/etc/$(PROGN)/samples/group_keys $(DESTDIR)/etc/$(PROGN)/profile
@test -s $(DESTDIR)/etc/$(PROGN)/reboot || cp $(DESTDIR)/etc/$(PROGN)/samples/all_off $(DESTDIR)/etc/$(PROGN)/reboot
@cp systemd/$(PROGN).service $(DESTDIR)$(SYSTEMDDIR)/system
@cp systemd/$(PROGN)-reboot.service $(DESTDIR)$(SYSTEMDDIR)/system
@udevadm control --reload-rules @udevadm control --reload-rules
@systemctl daemon-reload
@systemctl start $(PROGN) @test -s /usr/bin/systemd-run && \
@systemctl enable $(PROGN) install -m 755 -d \
@systemctl enable $(PROGN)-reboot $(DESTDIR)/etc/$(PROGN)/samples \
$(DESTDIR)$(SYSTEMDDIR)/system && \
cp sample_profiles/* $(DESTDIR)/etc/$(PROGN)/samples && \
test -s $(DESTDIR)/etc/$(PROGN)/profile || cp $(DESTDIR)/etc/$(PROGN)/samples/group_keys $(DESTDIR)/etc/$(PROGN)/profile && \
test -s $(DESTDIR)/etc/$(PROGN)/reboot || cp $(DESTDIR)/etc/$(PROGN)/samples/all_off $(DESTDIR)/etc/$(PROGN)/reboot && \
cp systemd/$(PROGN).service $(DESTDIR)$(SYSTEMDDIR)/system && \
cp systemd/$(PROGN)-reboot.service $(DESTDIR)$(SYSTEMDDIR)/system && \
systemctl daemon-reload && \
systemctl start $(PROGN) && \
systemctl enable $(PROGN) && \
systemctl enable $(PROGN)-reboot
uninstall: uninstall:
@systemctl disable $(PROGN) @test -s /usr/bin/systemd-run && \
@systemctl disable $(PROGN)-reboot systemctl disable $(PROGN) && \
@rm $(SYSTEMDDIR)/system/$(PROGN).service systemctl disable $(PROGN)-reboot && \
@rm $(SYSTEMDDIR)/system/$(PROGN)-reboot.service rm $(SYSTEMDDIR)/system/$(PROGN).service && \
@systemctl daemon-reload rm $(SYSTEMDDIR)/system/$(PROGN)-reboot.service && \
systemctl daemon-reload && \
rm -R /etc/$(PROGN)
@rm /usr/bin/g410-led @rm /usr/bin/g410-led
@rm /usr/bin/g610-led @rm /usr/bin/g610-led
@rm /usr/bin/g910-led @rm /usr/bin/g910-led
@rm /usr/bin/$(PROGN) @rm /usr/bin/$(PROGN)
@rm -R /etc/$(PROGN)
@rm /etc/udev/rules.d/$(PROGN).rules @rm /etc/udev/rules.d/$(PROGN).rules
@udevadm control --reload-rules @udevadm control --reload-rules

View File

@ -4,7 +4,11 @@
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
#include "libusb-1.0/libusb.h" #if defined(hidapi)
#include "hidapi/hidapi.h"
#elif defined(libusb)
#include "libusb-1.0/libusb.h"
#endif
using namespace std; using namespace std;
@ -17,61 +21,38 @@ LedKeyboard::~LedKeyboard() {
bool LedKeyboard::listKeyboards() { bool LedKeyboard::listKeyboards() {
libusb_context *ctx = NULL; #if defined(hidapi)
if(libusb_init(&m_ctx) < 0) return false; if (hid_init() < 0) return false;
libusb_device **devs; struct hid_device_info *devs, *dev;
ssize_t cnt = libusb_get_device_list(ctx, &devs); devs = hid_enumerate(0x0, 0x0);
if(cnt >= 0) { dev = devs;
for(ssize_t i = 0; i < cnt; i++) { while (dev) {
libusb_device *device = devs[i];
libusb_device_descriptor desc = {
0, // bLength
0, // bDescriptorType
0, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
0, // bMaxPacketSize0
0, // idVendor
0, // idProduct
0, // bcdDevice
0, // iManufacturer
0, // iProduct
0, // iSerialNumber
0 // bNumConfigurations
};
libusb_get_device_descriptor(device, &desc);
for (int i=0; i<(int)SuportedKeyboards.size(); i++) { for (int i=0; i<(int)SuportedKeyboards.size(); i++) {
if (desc.idVendor == SuportedKeyboards[i][0]) { if (dev->vendor_id == SuportedKeyboards[i][0]) {
if (desc.idProduct == SuportedKeyboards[i][1]) { if (dev->product_id == SuportedKeyboards[i][1]) {
cout<<"0x"<<std::hex<<desc.idVendor \ cout<<"0x"<<std::hex<<dev->vendor_id \
<<" 0x"<<std::hex<<desc.idProduct<<endl; <<" 0x"<<std::hex<<dev->product_id \
<<" "<<dev->serial_number \
<<" "<<dev->path<<" ";
dev = dev->next;
cout<<dev->serial_number<<" "<<dev->path<<endl;
i++;
break; break;
} }
} }
} }
dev = dev->next;
} }
libusb_free_device_list(devs, 1); hid_free_enumeration(devs);
libusb_exit(m_ctx);
} else return false;
return true; hid_exit();
} #elif defined(libusb)
libusb_context *ctx = NULL;
if(libusb_init(&m_ctx) < 0) return false;
bool LedKeyboard::isOpen() {
return m_isOpen;
}
bool LedKeyboard::open() {
if (m_isOpen) return true;
if(libusb_init(&m_ctx) < 0) return false;
if (m_keyboardModel == KeyboardModel::unknown) {
libusb_device **devs; libusb_device **devs;
ssize_t cnt = libusb_get_device_list(m_ctx, &devs); ssize_t cnt = libusb_get_device_list(ctx, &devs);
if(cnt >= 0) { if(cnt >= 0) {
for(ssize_t i = 0; i < cnt; i++) { for(ssize_t i = 0; i < cnt; i++) {
libusb_device *device = devs[i]; libusb_device *device = devs[i];
@ -95,72 +76,170 @@ bool LedKeyboard::open() {
for (int i=0; i<(int)SuportedKeyboards.size(); i++) { for (int i=0; i<(int)SuportedKeyboards.size(); i++) {
if (desc.idVendor == SuportedKeyboards[i][0]) { if (desc.idVendor == SuportedKeyboards[i][0]) {
if (desc.idProduct == SuportedKeyboards[i][1]) { if (desc.idProduct == SuportedKeyboards[i][1]) {
m_vendorID = desc.idVendor; cout<<"0x"<<std::hex<<desc.idVendor \
m_productID = desc.idProduct; <<" 0x"<<std::hex<<desc.idProduct<<endl;
break;
}
}
}
}
libusb_free_device_list(devs, 1);
libusb_exit(m_ctx);
} else return false;
#endif
return true;
}
bool LedKeyboard::isOpen() {
return m_isOpen;
}
bool LedKeyboard::open() {
if (m_isOpen) return true;
#if defined(hidapi)
if (hid_init() < 0) return false;
if (m_keyboardModel == KeyboardModel::unknown) {
struct hid_device_info *devs, *dev;
devs = hid_enumerate(0x0, 0x0);
dev = devs;
m_keyboardModel = KeyboardModel::unknown;
while (dev) {
for (int i=0; i<(int)SuportedKeyboards.size(); i++) {
if (dev->vendor_id == SuportedKeyboards[i][0]) {
if (dev->product_id == SuportedKeyboards[i][1]) {
m_vendorID = dev->vendor_id;
m_productID = dev->product_id;
m_keyboardModel = (KeyboardModel)SuportedKeyboards[i][2]; m_keyboardModel = (KeyboardModel)SuportedKeyboards[i][2];
break; break;
} }
} }
} }
if (m_keyboardModel != KeyboardModel::unknown) break; if (m_keyboardModel != KeyboardModel::unknown) break;
dev = dev->next;
}
hid_free_enumeration(devs);
if (! dev) {
cout<<"Keyboard not found"<<endl;
m_keyboardModel = KeyboardModel::unknown;
hid_exit();
return false;
} }
libusb_free_device_list(devs, 1);
} }
}
if (m_keyboardModel == KeyboardModel::unknown) { m_hidHandle = hid_open(m_vendorID, m_productID, NULL);
cout<<"Keyboard not found"<<endl;
libusb_exit(m_ctx);
m_ctx = NULL;
return false;
}
m_hidHandle = libusb_open_device_with_vid_pid(m_ctx, m_vendorID, m_productID); if(m_hidHandle == 0) {
hid_exit();
return false;
}
#elif defined(libusb)
if(libusb_init(&m_ctx) < 0) return false;
if(m_hidHandle == 0) { if (m_keyboardModel == KeyboardModel::unknown) {
libusb_exit(m_ctx); libusb_device **devs;
m_ctx = NULL; ssize_t cnt = libusb_get_device_list(m_ctx, &devs);
return false; if(cnt >= 0) {
} for(ssize_t i = 0; i < cnt; i++) {
libusb_device *device = devs[i];
libusb_device_descriptor desc = {
0, // bLength
0, // bDescriptorType
0, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
0, // bMaxPacketSize0
0, // idVendor
0, // idProduct
0, // bcdDevice
0, // iManufacturer
0, // iProduct
0, // iSerialNumber
0 // bNumConfigurations
};
libusb_get_device_descriptor(device, &desc);
for (int i=0; i<(int)SuportedKeyboards.size(); i++) {
if (desc.idVendor == SuportedKeyboards[i][0]) {
if (desc.idProduct == SuportedKeyboards[i][1]) {
m_vendorID = desc.idVendor;
m_productID = desc.idProduct;
m_keyboardModel = (KeyboardModel)SuportedKeyboards[i][2];
break;
}
}
}
if (m_keyboardModel != KeyboardModel::unknown) break;
if(libusb_kernel_driver_active(m_hidHandle, 1) == 1) { }
if(libusb_detach_kernel_driver(m_hidHandle, 1) != 0) { libusb_free_device_list(devs, 1);
}
}
if (m_keyboardModel == KeyboardModel::unknown) {
cout<<"Keyboard not found"<<endl;
libusb_exit(m_ctx); libusb_exit(m_ctx);
m_ctx = NULL; m_ctx = NULL;
return false; return false;
} }
m_isKernellDetached = true;
}
if(libusb_claim_interface(m_hidHandle, 1) < 0) {
if(m_isKernellDetached==true) {
libusb_attach_kernel_driver(m_hidHandle, 1);
m_isKernellDetached = false;
}
libusb_exit(m_ctx);
m_ctx = NULL;
return false;
}
m_hidHandle = libusb_open_device_with_vid_pid(m_ctx, m_vendorID, m_productID);
if(m_hidHandle == 0) {
libusb_exit(m_ctx);
m_ctx = NULL;
return false;
}
if(libusb_kernel_driver_active(m_hidHandle, 1) == 1) {
if(libusb_detach_kernel_driver(m_hidHandle, 1) != 0) {
libusb_exit(m_ctx);
m_ctx = NULL;
return false;
}
m_isKernellDetached = true;
}
if(libusb_claim_interface(m_hidHandle, 1) < 0) {
if(m_isKernellDetached==true) {
libusb_attach_kernel_driver(m_hidHandle, 1);
m_isKernellDetached = false;
}
libusb_exit(m_ctx);
m_ctx = NULL;
return false;
}
#endif
m_isOpen = true; m_isOpen = true;
return true; return true;
} }
bool LedKeyboard::close() { bool LedKeyboard::close() {
if (! m_isOpen) return false; if (! m_isOpen) return true;
m_isOpen = false; m_isOpen = false;
if(libusb_release_interface(m_hidHandle, 1) != 0) return false;
if(m_isKernellDetached==true) { #if defined(hidapi)
libusb_attach_kernel_driver(m_hidHandle, 1); hid_close(m_hidHandle);
m_isKernellDetached = false; m_hidHandle = 0;
} hid_exit();
libusb_close(m_hidHandle); #elif defined(libusb)
m_hidHandle = NULL; if(libusb_release_interface(m_hidHandle, 1) != 0) return false;
libusb_exit(m_ctx); if(m_isKernellDetached==true) {
m_ctx = NULL; libusb_attach_kernel_driver(m_hidHandle, 1);
m_isKernellDetached = false;
}
libusb_close(m_hidHandle);
m_hidHandle = NULL;
libusb_exit(m_ctx);
m_ctx = NULL;
#endif
return true; return true;
} }
@ -438,16 +517,32 @@ bool LedKeyboard::setNativeEffect(NativeEffect effect, NativeEffectPart part, ui
bool LedKeyboard::sendDataInternal(const byte_buffer_t &data) { bool LedKeyboard::sendDataInternal(byte_buffer_t &data) {
if (! m_isOpen) return false; if (! m_isOpen) return false;
int r;
if (data.size() > 20) r = libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0212, 1, const_cast<unsigned char*>(data.data()), data.size(), 2000); if (data.size() > 0) {
else r = libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0211, 1, const_cast<unsigned char*>(data.data()), data.size(), 2000); #if defined(hidapi)
usleep(1000); data.insert(data.begin(), 0x00);
if (r < 0) return false; if (hid_write(m_hidHandle, const_cast<unsigned char*>(data.data()), data.size()) < 0) {
unsigned char buffer[64]; std::cout<<"Error: Can not write to hidraw, try with the libusb version"<<std::endl;
int len = 0; return false;
r = libusb_interrupt_transfer(m_hidHandle, 0x82, buffer, sizeof(buffer), &len, 1); }
usleep(500);
byte_buffer_t data2;
data2.resize(21, 0x00);
hid_read_timeout(m_hidHandle, const_cast<unsigned char*>(data2.data()), data2.size(), 0);
#elif defined(libusb)
int r;
if (data.size() > 20) r = libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0212, 1, const_cast<unsigned char*>(data.data()), data.size(), 2000);
else r = libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0211, 1, const_cast<unsigned char*>(data.data()), data.size(), 2000);
usleep(1000);
if (r < 0) return false;
unsigned char buffer[64];
int len = 0;
r = libusb_interrupt_transfer(m_hidHandle, 0x82, buffer, sizeof(buffer), &len, 1);
#endif
}
return true; return true;
} }

View File

@ -4,7 +4,11 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include "libusb-1.0/libusb.h" #if defined(hidapi)
#include "hidapi/hidapi.h"
#elif defined(libusb)
#include "libusb-1.0/libusb.h"
#endif
class LedKeyboard { class LedKeyboard {
@ -180,15 +184,20 @@ class LedKeyboard {
}; };
bool m_isOpen = false; bool m_isOpen = false;
bool m_isKernellDetached = false;
uint16_t m_vendorID = 0; uint16_t m_vendorID = 0;
uint16_t m_productID = 0; uint16_t m_productID = 0;
KeyboardModel m_keyboardModel = KeyboardModel::unknown; KeyboardModel m_keyboardModel = KeyboardModel::unknown;
libusb_device_handle *m_hidHandle;
libusb_context *m_ctx = NULL; #if defined(hidapi)
hid_device *m_hidHandle;
#elif defined(libusb)
bool m_isKernellDetached = false;
libusb_device_handle *m_hidHandle;
libusb_context *m_ctx = NULL;
#endif
bool sendDataInternal(const byte_buffer_t &data); bool sendDataInternal(byte_buffer_t &data);
byte_buffer_t getKeyGroupAddress(KeyAddressGroup keyAddressGroup); byte_buffer_t getKeyGroupAddress(KeyAddressGroup keyAddressGroup);
}; };

View File

@ -186,7 +186,6 @@ int pipeProfile(LedKeyboard &kbd) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc > 1) { if (argc > 1) {
std::string arg = argv[1]; std::string arg = argv[1];

View File

@ -1,7 +1,7 @@
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c331", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c331", MODE="666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c337", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c337", MODE="666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c330", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c330", MODE="666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c333", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c333", MODE="666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c338", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c338", MODE="666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c32b", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c32b", MODE="666"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c335", MODE="660", GROUP="users" ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c335", MODE="666"