/*-----------------------------------------*\ | SteelSeriesApexBaseController.h | | | | Base controller for SteelSeries Apex | | Keyboard lighting controllers | | | | Florian Heilmann (FHeilmann) 19/10/2020 | \*-----------------------------------------*/ #include "RGBController.h" #include "SteelSeriesGeneric.h" #include #include #pragma once #define STEELSERIES_PACKET_IN_SIZE 64 #define STEELSERIES_PACKET_OUT_SIZE STEELSERIES_PACKET_IN_SIZE + 1 class SteelSeriesApexBaseController { public: virtual ~SteelSeriesApexBaseController() { } std::string GetDeviceLocation() { return("HID: " + location); }; steelseries_type proto_type; /*----------------------------------------*\ | The serial number of the keyboard is | | acquired by sending an output report | | to address 0xFF and reading the result. | | The HID capability table is not used. | | The serial number also contains the model| | number which can be used to determine | | the physical layout of different region | | keyboards throughout the product stack. | \*----------------------------------------*/ std::string GetSerialString() { std::string return_string = ""; if(proto_type == APEX) { unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE]; unsigned char ibuf[STEELSERIES_PACKET_IN_SIZE]; int result; memset(obuf, 0x00, sizeof(obuf)); obuf[0x00] = 0; obuf[0x01] = 0xFF; hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE); result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2); /*---------------------------------------*\ | Only the first 19 bytes are of value | \*---------------------------------------*/ if( result > 0) { std::string serialnum(ibuf, ibuf+19); return_string = serialnum; } } return(return_string); } std::string GetVersionString() { std::string return_string = "Unsupported protocol"; if(proto_type == APEX) { /*--------------------------------------------*\ | For the Apex Pro there are two firmware | | versions which can be acquired, KBD and LED. | | We know where both are located, we do not | | know which is what. For now we'll make an | | assumption and fix if proven wrong. | \*--------------------------------------------*/ unsigned char obuf[STEELSERIES_PACKET_OUT_SIZE]; unsigned char ibuf[STEELSERIES_PACKET_IN_SIZE]; int result; memset(obuf, 0x00, sizeof(obuf)); obuf[0x00] = 0; obuf[0x01] = 0x90; hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE); result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 2); if(result > 0) { std::string fwver(ibuf, ibuf+STEELSERIES_PACKET_IN_SIZE); fwver = fwver.c_str(); /*---------------------------------------*\ | Find 2 periods in string, if found we | | can form a X.Y.Z revision. | \*---------------------------------------*/ std::size_t majorp = fwver.find('.'); if(majorp != std::string::npos) { std::size_t minorp = fwver.find('.', majorp+1); if(minorp != std::string::npos) { std::string major = fwver.substr(0, majorp); std::string minor = fwver.substr(majorp+1, (minorp-majorp-1)); std::string build = fwver.substr(minorp+1); return_string = "KBD: " + major + "." + minor + "." + build; } } } /*---------------------------------------*\ | Clear and reuse buffer | \*---------------------------------------*/ memset(ibuf, 0x00, sizeof(ibuf)); obuf[0x02] = 0x01; hid_write(dev, obuf, STEELSERIES_PACKET_OUT_SIZE); result = hid_read_timeout(dev, ibuf, STEELSERIES_PACKET_IN_SIZE, 10); if(result > 0) { std::string fwver(ibuf, ibuf+STEELSERIES_PACKET_IN_SIZE); fwver = fwver.c_str(); std::size_t majorp = fwver.find('.'); if(majorp != std::string::npos) { std::size_t minorp = fwver.find('.', majorp+1); if(minorp != std::string::npos) { std::string major = fwver.substr(0, majorp); std::string minor = fwver.substr(majorp+1, (minorp-majorp-1)); std::string build = fwver.substr(minorp+1); return_string = return_string + " / LED: " + major + "." + minor + "." + build; } } } } return(return_string); } virtual void SetMode ( unsigned char mode, std::vector colors ) = 0; virtual void SetLEDsDirect(std::vector colors) = 0; protected: std::string location; hid_device* dev; unsigned char active_mode; };