2024-12-09 13:41:22 +00:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
|
|
|
#include "tinyusb.h"
|
|
|
|
#include "class/hid/hid_device.h"
|
|
|
|
|
2024-12-09 14:54:11 +00:00
|
|
|
#include "common.h"
|
|
|
|
#include "usb.h"
|
2024-12-13 02:29:01 +00:00
|
|
|
#include "lcd.h"
|
2024-12-13 17:46:59 +00:00
|
|
|
#include "ui.h"
|
2024-12-09 14:54:11 +00:00
|
|
|
|
2024-12-11 18:59:17 +00:00
|
|
|
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
|
2024-12-09 13:41:22 +00:00
|
|
|
|
|
|
|
static const char *TAG = "valconomy-usb";
|
|
|
|
|
|
|
|
// See https://github.com/hathach/tinyusb/blob/cb22301f91f0465a5578be35d9be284657ddd31d/src/common/tusb_types.h#L331
|
|
|
|
const tusb_desc_device_t val_usb_dev_descriptor = {
|
|
|
|
.bLength = sizeof(tusb_desc_device_t),
|
|
|
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
|
|
|
// BCD-coded USB version (?)
|
|
|
|
.bcdUSB = 0x0200,
|
|
|
|
|
|
|
|
.bDeviceClass = 0x00,
|
|
|
|
.bDeviceSubClass = 0x00,
|
|
|
|
.bDeviceProtocol = 0x00,
|
|
|
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
|
|
|
|
|
|
|
.idVendor = 0x6969,
|
|
|
|
.idProduct = 0x0004,
|
|
|
|
// BCD-coded device version (0.1)
|
|
|
|
.bcdDevice = 0x0010,
|
|
|
|
|
|
|
|
// Indices of strings
|
|
|
|
.iManufacturer = 0x01,
|
|
|
|
.iProduct = 0x02,
|
|
|
|
.iSerialNumber = 0x03,
|
|
|
|
|
|
|
|
.bNumConfigurations = 0x01,
|
|
|
|
};
|
|
|
|
|
2024-12-11 18:59:17 +00:00
|
|
|
const char* val_usb_string_descriptor[5] = {
|
|
|
|
// 0: supported language is English (0x0409)
|
2024-12-09 13:41:22 +00:00
|
|
|
(char[]){0x09, 0x04},
|
|
|
|
// 1: Manufacturer
|
|
|
|
"/dev/player0",
|
|
|
|
// 2: Product
|
|
|
|
"Valorant Economy Helper",
|
|
|
|
// 3: Serials, should use chip ID
|
|
|
|
val_dev_serial,
|
|
|
|
// 4: HID
|
|
|
|
"Valconomy HID interface",
|
|
|
|
};
|
|
|
|
|
2024-12-11 18:59:17 +00:00
|
|
|
const uint8_t val_hid_report_descriptor[] = {
|
|
|
|
TUD_HID_REPORT_DESC_GENERIC_INOUT(USB_EP_BUFSIZE),
|
|
|
|
};
|
|
|
|
|
|
|
|
const uint8_t val_hid_conf_descriptor[] = {
|
2024-12-09 13:41:22 +00:00
|
|
|
// Configuration number, interface count, string index, total length, attribute, power in mA
|
|
|
|
TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
|
|
|
|
2024-12-11 18:59:17 +00:00
|
|
|
// HID requires an IN endpoint even if we don't care about it
|
|
|
|
// Interface number, string index, protocol, report descriptor len, EP Out & In address, size & polling interval (ms)
|
|
|
|
// 0x80 in endpoint address indicates IN
|
|
|
|
TUD_HID_INOUT_DESCRIPTOR(0, 4, HID_ITF_PROTOCOL_NONE, sizeof(val_hid_report_descriptor), EPNUM_HID, 0x80 | EPNUM_HID, USB_EP_BUFSIZE, 100)
|
2024-12-09 13:41:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TinyUSB callbacks
|
|
|
|
|
|
|
|
// Invoked when received GET HID REPORT DESCRIPTOR request
|
|
|
|
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
|
|
|
uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) {
|
|
|
|
// We use only one interface and one HID report descriptor, so we can ignore parameter 'instance'
|
|
|
|
return val_hid_report_descriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoked when received GET_REPORT control request
|
|
|
|
// Application must fill buffer report's content and return its length.
|
|
|
|
// Return zero will cause the stack to STALL request
|
2024-12-13 17:46:59 +00:00
|
|
|
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buf, uint16_t reqlen) {
|
2024-12-09 13:41:22 +00:00
|
|
|
(void) instance;
|
2024-12-13 17:46:59 +00:00
|
|
|
if (report_id != 0 || reqlen < 1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ESP_LOGI(TAG, "Got %hu bytes report %hhu", reqlen, report_id);
|
|
|
|
// for (uint16_t i = 0; i < reqlen; i++) {
|
|
|
|
// ESP_LOGI(TAG, "b: %02hhx", buf[i]);
|
|
|
|
// }
|
|
|
|
buf[0] = val_ui_state_ready();
|
|
|
|
return 1;
|
2024-12-09 13:41:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Invoked when received SET_REPORT control request or
|
|
|
|
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
2024-12-13 17:46:59 +00:00
|
|
|
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buf, uint16_t bufsize) {
|
|
|
|
(void) instance;
|
|
|
|
assert(report_id == 0 && report_type == HID_REPORT_TYPE_OUTPUT && bufsize >= 1);
|
|
|
|
if (!val_lvgl_lock(-1)) {
|
|
|
|
ESP_LOGE(TAG, "Failed to grab LVGL lock");
|
|
|
|
return;
|
|
|
|
}
|
2024-12-15 15:36:52 +00:00
|
|
|
if (buf[0] > ST_GAME_OVER) {
|
2024-12-13 17:46:59 +00:00
|
|
|
ESP_LOGW(TAG, "Unknown state %hhu", buf[0]);
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
if (!val_ui_state_ready()) {
|
|
|
|
goto ret;
|
2024-12-11 18:59:17 +00:00
|
|
|
}
|
2024-12-13 17:46:59 +00:00
|
|
|
|
|
|
|
switch (buf[0]) {
|
|
|
|
case ST_NONE:
|
|
|
|
val_ui_none();
|
|
|
|
break;
|
|
|
|
case ST_MENU:
|
|
|
|
if (bufsize < 2) {
|
|
|
|
ESP_LOGE(TAG, "Invalid ST_MENU command");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
val_ui_menu((bool)buf[1]);
|
|
|
|
break;
|
|
|
|
case ST_IDLE:
|
|
|
|
val_ui_idle();
|
|
|
|
break;
|
2024-12-14 16:26:34 +00:00
|
|
|
case ST_QUEUE_START:
|
|
|
|
if (bufsize < 2) {
|
|
|
|
ESP_LOGE(TAG, "Invalid ST_QUEUE_START command");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
val_ui_queue_start((bool)buf[1]);
|
|
|
|
break;
|
2024-12-15 12:05:36 +00:00
|
|
|
case ST_MATCH_FOUND:
|
|
|
|
if (bufsize < 2) {
|
|
|
|
ESP_LOGE(TAG, "Invalid ST_MATCH_FOUND command");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
val_ui_match_found((bool)buf[1]);
|
|
|
|
break;
|
2024-12-15 13:57:31 +00:00
|
|
|
case ST_PREGAME:
|
|
|
|
if (bufsize < 2) {
|
|
|
|
ESP_LOGE(TAG, "Invalid ST_PREGAME command");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
val_ui_pregame((bool)buf[1]);
|
|
|
|
break;
|
2024-12-15 14:37:12 +00:00
|
|
|
case ST_GAME_GENERIC:
|
|
|
|
if (bufsize < 2 || buf[1] > VAL_EXT_GAMEMODES_SIZE) {
|
|
|
|
ESP_LOGE(TAG, "Invalid ST_PREGAME command");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
val_ui_game_generic(val_ext_gamemodes[buf[1]]);
|
|
|
|
break;
|
2024-12-15 15:36:52 +00:00
|
|
|
case ST_GAME_START:
|
|
|
|
val_ui_game_start();
|
|
|
|
break;
|
|
|
|
case ST_GAME_OVER:
|
|
|
|
if (bufsize < 2) {
|
|
|
|
ESP_LOGE(TAG, "Invalid ST_GAME_OVER command");
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
val_ui_game_over((bool)buf[1]);
|
|
|
|
break;
|
2024-12-13 17:46:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
|
|
|
val_lvgl_unlock();
|
2024-12-11 18:59:17 +00:00
|
|
|
}
|
2024-12-09 13:41:22 +00:00
|
|
|
|
|
|
|
void val_usb_init(void) {
|
|
|
|
ESP_LOGI(TAG, "Initializing USB");
|
|
|
|
|
|
|
|
const tinyusb_config_t cfg = {
|
|
|
|
.device_descriptor = &val_usb_dev_descriptor,
|
2024-12-11 18:59:17 +00:00
|
|
|
.string_descriptor = val_usb_string_descriptor,
|
|
|
|
.string_descriptor_count = sizeof(val_usb_string_descriptor) / sizeof(char *),
|
2024-12-09 13:41:22 +00:00
|
|
|
.external_phy = false,
|
|
|
|
|
|
|
|
#if (TUD_OPT_HIGH_SPEED)
|
|
|
|
// HID configuration descriptor for full-speed and high-speed are the same
|
|
|
|
.fs_configuration_descriptor = val_hid_conf_descriptor,
|
|
|
|
.hs_configuration_descriptor = val_hid_conf_descriptor,
|
|
|
|
.qualifier_descriptor = NULL,
|
|
|
|
#else
|
|
|
|
.configuration_descriptor = val_hid_conf_descriptor,
|
|
|
|
#endif // TUD_OPT_HIGH_SPEED
|
|
|
|
};
|
|
|
|
ESP_ERROR_CHECK(tinyusb_driver_install(&cfg));
|
|
|
|
}
|