#include #include #include "a811.h" #include "usb_thingy.h" #define CHK(X) \ if ((r = (X)) != 0) \ return r; ssize_t logError(const std::string &errorMessage, const char *file, int line, const char *function) { std::cerr << "ERROR: " << file << ":" << line << " - " << function << ": " << errorMessage << std::endl; return 1; } A811::A811() { // Init usb lib _connection = &(Connection::getInstance()); // init other vars _conf12 = (conf_12 *)malloc(sizeof(conf_12)); memset(_conf12, 0, sizeof(conf_12)); readConfigFromDevice(CONF_TYPE::LIGHT); _macros = nullptr; } ssize_t A811::setLightMode(LIGHT_MODE mode, int p1, int p2) { switch (mode) { case LIGHT_MODE::COLORFUL_STREAMING: if (p1 <= 0 || p1 > 4 || p2 <= 0 || p2 > 4) logError("ERROR: Invalid brightness or speed.", __FILE__, __LINE__, __func__); _conf12->c1.light_mode = (uint8_t)mode; _conf12->c1.col_brightness_speed = (uint8_t)((p1 & 0x0F) | ((p2 & 0x0F) << 4)); std::cout << std::hex << (int)_conf12->c1.light_mode << "-2\n"; break; case LIGHT_MODE::STEADY: if (p1 <= 0 || p1 > 4 || p2 <= 0 || p2 > 4) logError("ERROR: Invalid brightness or speed.", __FILE__, __LINE__, __func__); _conf12->c1.col_brightness_speed = (uint8_t)((p1 & 0x0F) | ((p2 & 0x0F) << 4)); _conf12->c1.light_mode = (uint8_t)mode; break; case LIGHT_MODE::BREATHING: if (p1 <= 0 || p1 > 4 || p2 <= 0 || p2 > 6) logError("ERROR: Invalid brightness or color number.", __FILE__, __LINE__, __func__); _conf12->c1.light_mode = (uint8_t)mode; _conf12->c1.br_brightness_speed = (uint8_t)((p1 & 0x0F) | ((p2 & 0x0F) << 4)); break; default: logError("ERROR: Invalid LIGHT_MODE.", __FILE__, __LINE__, __func__); return ssize_t(1); } return ssize_t(0); } LIGHT_MODE A811::getLightMode() { return LIGHT_MODE(_conf12->c1.light_mode); } ssize_t A811::setLightModeColors(LIGHT_MODE mode, unsigned char colors[21]) { switch (mode) { case LIGHT_MODE::STEADY: std::memcpy(&_conf12->c1.col_steady, colors, sizeof(_conf12->c1.col_steady)); break; case LIGHT_MODE::BREATHING: std::memcpy(&_conf12->c1.col_breathing, colors, sizeof(_conf12->c1.col_breathing)); break; default: logError("ERROR: Invalid LIGHT_MODE.", __FILE__, __LINE__, __func__); return ssize_t(1); } return ssize_t(0); } unsigned char *A811::getLightModeColors(LIGHT_MODE mode) { switch (mode) { case LIGHT_MODE::STEADY: return _conf12->c1.col_steady; case LIGHT_MODE::BREATHING: return _conf12->c1.col_breathing; default: logError("ERROR: Invalid LIGHT_MODE.", __FILE__, __LINE__, __func__); return nullptr; } } ssize_t A811::setUSBPollingRate(POLLING_RATE pr) { if ((uint8_t)pr <= 0 || (uint8_t)pr > 4) logError("ERROR: Invalid POLLING_RATE.", __FILE__, __LINE__, __func__); _conf12->c1.polling_rate = (uint8_t)pr; return ssize_t(); } POLLING_RATE A811::getUSBPollingRate() { return POLLING_RATE(_conf12->c1.polling_rate); } ssize_t A811::setDPI(DPI_MODE mode, unsigned char color[3], int dpi, int active) { if ((uint8_t)mode < (uint8_t)DPI_MODE::DPI_1 || (uint8_t)mode > (uint8_t)DPI_MODE::DPI_5) { logError("ERROR: Invalid DPI_MODE.", __FILE__, __LINE__, __func__); return ssize_t(1); } if (dpi > 26000 || dpi < 50) { logError("ERROR: Invalid dpi.", __FILE__, __LINE__, __func__); return ssize_t(2); } if (active > 5 || active < 1) { logError("ERROR: Invalid active dpi modes.", __FILE__, __LINE__, __func__); return ssize_t(2); } // Calculate the DPI value according to the formula uint16_t dpi_value = (dpi - 50) / 50; // Split the value into two bytes (least significant byte first) uint8_t lsb = dpi_value & 0xFF; // Extract the least significant byte uint8_t msb = (dpi_value >> 8) & 0xFF; // Extract the most significant byte _conf12->c1.dpi_modes = // number of active modes (1 & 0x0f) << 4 | ((active & 0x0F)); _conf12->c1.hdpi[((uint8_t)mode - 1) * 2] = lsb; _conf12->c1.hdpi[((uint8_t)mode - 1) * 2 + 1] = msb; _conf12->c1.col_dpi[((uint8_t)mode - 1) * 3] = color[0]; _conf12->c1.col_dpi[((uint8_t)mode - 1) * 3 + 1] = color[1]; _conf12->c1.col_dpi[((uint8_t)mode - 1) * 3 + 2] = color[2]; return ssize_t(0); } int A811::getDPI(DPI_MODE mode) { if ((uint8_t)mode < (uint8_t)DPI_MODE::DPI_1 || (uint8_t)mode > (uint8_t)DPI_MODE::DPI_5) { logError("ERROR: Invalid DPI_MODE.", __FILE__, __LINE__, __func__); return ssize_t(1); } // Assume lsb and msb are given or extracted from your configuration structure uint8_t lsb = _conf12->c1.hdpi[((uint8_t)mode - 1) * 2]; uint8_t msb = _conf12->c1.hdpi[((uint8_t)mode - 1) * 2 + 1]; // Reconstruct the dpi_value uint16_t dpi_value = msb << 8 | lsb & 0xFF; std::cout << std::hex << dpi_value << " : " << (int)lsb << " : " << (int)msb << std::endl; // Reverse the formula to get the original dpi uint16_t dpi = (dpi_value * 50) + 50; return dpi; } BATTERY_STAT A811::getBatteryStatus() { if (_batStat.wired == 0x10) { if (_batStat.capacity == 0x01) return BATTERY_STAT::CHARGING; else if (_batStat.capacity == 0x02) return BATTERY_STAT::NOT_CHARGING; } return BATTERY_STAT::DISCHARGING; } int A811::getBatteryCapacity() { if (_batStat.wired == 0x11) return (int)_batStat.capacity; //@comment thats weird what to do i cant read the battery level if it is // plugged??? else return 0; } ssize_t A811::setMultimediaButton(int id, std::string keyname) { if (id >= 0 && id < 7) { // Assuming keyname is a valid key in the _keycodes map if (_keycodes.find(keyname) == _keycodes.end()) { logError("ERROR: Keyname not found in keycodes.", __FILE__, __LINE__, __func__); return ssize_t(1); // or handle the error appropriately } auto arr = _keycodes[keyname]; unsigned char *mahbytes = (unsigned char *)&_conf12->c2.mouse_buttons[id]; for (int i = 0; i < (int)sizeof(_conf12->c2.mouse_buttons[id]); ++i) { std::cout << std::hex << (int)mahbytes[i] << "|"; mahbytes[i] = ((unsigned char *)&arr)[i]; std::cout << std::hex << (int)mahbytes[i] << std::endl; } } else if (id >= 7 && id < 15) { // Assuming keyname is a valid key in the _keycodes map auto it = _keycodes.find(keyname); if (it != _keycodes.end()) { const std::array &keycode_array = it->second; // Get the array from the map // std::copy(keycode_array.begin(), keycode_array.end(), _conf12->c2.side[id - 7].keycode); } else { logError("ERROR: Keyname not found in keycodes.", __FILE__, __LINE__, __func__); return ssize_t(1); // or handle the error appropriately } } else { logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__); return ssize_t(1); } return ssize_t(0); } ssize_t A811::setMacroButton(int id, int macro_id, int cycle_type, int cycle_cnt) { unsigned char keyConf[4] = {0x70, macro_id, cycle_type, cycle_cnt}; // maybe check if macro is on mouse // check validity of data // also i am not sure at all how the macro ids work like why is the 1st key alway macro nr 1 and so on if (id >= 0 && id < 7) { memcpy(&_conf12->c2.mouse_buttons[id], keyConf, sizeof(_conf12->c2.mouse_buttons[id])); } else if (id >= 7 && id < 15) { memcpy(&_conf12->c2.side[id - 7], keyConf, sizeof(_conf12->c2.side[id])); } else { logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__); return ssize_t(1); } return ssize_t(0); } ssize_t A811::setButton(int id, std::string keyboardKey, int mod) { unsigned char key[4]; key[0] = 0x21; key[1] = mod; if (id >= 0 && id < 7) { // Assuming keyname is a valid key in the _keycodes map auto it = _keyboardKeys.find(keyboardKey); if (it != _keyboardKeys.end()) { key[2] = it->second; key[3] = 0x00; // optional button memcpy(&_conf12->c2.mouse_buttons[id], key, sizeof(_conf12->c2.mouse_buttons[id])); } else { logError("ERROR: Keyname not found in _keyboardKeys.", __FILE__, __LINE__, __func__); return ssize_t(1); // or handle the error appropriately } } else if (id >= 7 && id < 15) { // Assuming keyname is a valid key in the _keycodes map auto it = _keyboardKeys.find(keyboardKey); if (it != _keyboardKeys.end()) { key[2] = it->second; key[3] = 0x00; // optional button memcpy(&_conf12->c2.side[id], key, sizeof(_conf12->c2.side[id])); } else { logError("ERROR: Keyname not found in _keyboardKeys.", __FILE__, __LINE__, __func__); return ssize_t(1); // or handle the error appropriately } } else { logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__); return ssize_t(1); } return ssize_t(0); } _r_button A811::getButton(int id) { _r_button b; /* if (id >= 0 && id < 7){ // Assuming keyname is a valid key in the _keycodes map auto it = _buttonNames.find(id); if (it != _buttonNames.end()) { b.name = it->second; } else { logError("ERROR: Button name not found in _buttonNames.", __FILE__, __LINE__, __func__); // Handle the error appropriately, e.g., returning an empty _r_button return _r_button(); // Return empty or error _r_button } } else if (id >= 7 && id < 15) { // Assuming keyname is a valid key in the _keycodes map auto it = _buttonNames.find(id-7); if (it != _buttonNames.end()) { b.name = it->second; } else { logError("ERROR: Button name not found in _buttonNames.", __FILE__, __LINE__, __func__); // Handle the error appropriately, e.g., returning an empty _r_button return _r_button(); // Return empty or error _r_button } } else { logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__); } */ return _r_button(); } ssize_t A811::readConfigFromDevice(CONF_TYPE t_conf) { unsigned char _data[8] = {0x05, 0x21, 0, 0, 0, 0, 0, 0}; unsigned char _datas[520]; memset(_datas, 0, 520); /*if(!connection->isWireless()) _data[1] = 0x11;*/ // not sure if this means anything ssize_t r; CHK(_connection->open()); switch (t_conf) { case CONF_TYPE::LIGHT: _data[1] = 0x21; CHK(_connection->setReport(0x0305, _data, 8)); CHK(_connection->getReport(0x0308, (unsigned char *)&_conf12->c1, 520)); break; case CONF_TYPE::KEY: _data[1] = 0x22; CHK(_connection->setReport(0x0305, (unsigned char *)_data, 8)); CHK(_connection->getReport(0x0308, (unsigned char *)&_conf12->c2, 520)); break; case CONF_TYPE::MACRO: logError("ERROR: Macros not implemented.", __FILE__, __LINE__, __func__); break; case CONF_TYPE::BATTERY: _data[1] = 0x90; CHK(_connection->setReport(0x0305, (unsigned char *)_data, 8)); CHK(_connection->getReport(0x0305, (unsigned char *)&_batStat, 8)); break; default: logError("ERROR: Invalid CONF_TYPE.", __FILE__, __LINE__, __func__); CHK(_connection->close()); return ssize_t(1); } CHK(_connection->close()); return ssize_t(0); } ssize_t A811::writeConfigToDevice(CONF_TYPE t_conf) { ssize_t r; CHK(_connection->open()); switch (t_conf) { case CONF_TYPE::LIGHT: _conf12->c1.req_type = 0x92; std::cout << std::hex << (int)_conf12->c1.light_mode << "-3\n"; CHK(_connection->setReport(0x0308, (unsigned char *)&_conf12->c1, 520)); break; case CONF_TYPE::KEY: _conf12->c2.req_type = 0x50; CHK(_connection->setReport(0x0308, (unsigned char *)&_conf12->c2, 520)); break; case CONF_TYPE::MACRO: logError("ERROR: Macros not implemented.", __FILE__, __LINE__, __func__); break; case CONF_TYPE::BATTERY: logError("ERROR: Invalid write to CONF_TYPE::BATTERY.", __FILE__, __LINE__, __func__); break; default: logError("ERROR: Invalid CONF_TYPE.", __FILE__, __LINE__, __func__); CHK(_connection->close()); return ssize_t(1); } CHK(_connection->close()); return ssize_t(0); }