firmware+controller: Initial working HID state control
This commit is contained in:
parent
6d0db71305
commit
277eb4ee3b
@ -1,17 +1,22 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import hid
|
import logging
|
||||||
|
|
||||||
USB_VID = 0x6969
|
import valconomy
|
||||||
USB_PID = 0x0004
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
hid_handle = hid.device()
|
logging.basicConfig(
|
||||||
hid_handle.open(vendor_id=USB_VID, product_id=USB_PID)
|
format='%(asctime)s %(name)s %(levelname)s %(message)s', level=logging.INFO)
|
||||||
|
|
||||||
|
h = valconomy.HIDValconomyHandler()
|
||||||
try:
|
try:
|
||||||
hid_handle.write(b'\x00test')
|
h.menu(None, False)
|
||||||
|
h.none()
|
||||||
|
h.menu(None, True)
|
||||||
|
h.idle(None)
|
||||||
|
|
||||||
|
h.service()
|
||||||
finally:
|
finally:
|
||||||
hid_handle.close()
|
h.close()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import base64
|
import base64
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
import errno
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import os
|
import os
|
||||||
|
import queue
|
||||||
|
import struct
|
||||||
import time
|
import time
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
@ -49,12 +52,12 @@ class RiotPlayerInfo:
|
|||||||
return f'{self.name}#{self.tag}'
|
return f'{self.name}#{self.tag}'
|
||||||
|
|
||||||
class ValorantLocalClient:
|
class ValorantLocalClient:
|
||||||
lockfile_path = os.path.join(os.environ['LOCALAPPDATA'], r'Riot Games\Riot Client\Config\lockfile')
|
|
||||||
poll_interval = 0.5
|
poll_interval = 0.5
|
||||||
|
|
||||||
def __init__(self, callback: Callable[[RiotPlayerInfo, bool], None]):
|
def __init__(self, callback: Callable[[RiotPlayerInfo, bool], None]):
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
|
||||||
|
self.lockfile_path = os.path.join(os.environ['LOCALAPPDATA'], r'Riot Games\Riot Client\Config\lockfile')
|
||||||
self.port, self.password = None, None
|
self.port, self.password = None, None
|
||||||
self.running = True
|
self.running = True
|
||||||
self.players = {}
|
self.players = {}
|
||||||
@ -228,7 +231,78 @@ class ValconomyHandler:
|
|||||||
log.info('Hard luck...')
|
log.info('Hard luck...')
|
||||||
|
|
||||||
class HIDValconomyHandler(ValconomyHandler):
|
class HIDValconomyHandler(ValconomyHandler):
|
||||||
pass
|
vid = 0x6969
|
||||||
|
pid = 0x0004
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.dev = None
|
||||||
|
self.running = True
|
||||||
|
self.queue = queue.Queue(128)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.dev is not None:
|
||||||
|
self.dev.close()
|
||||||
|
|
||||||
|
def _dev_ready(self):
|
||||||
|
try:
|
||||||
|
if self.dev is None:
|
||||||
|
dev = hid.device()
|
||||||
|
dev.open(vendor_id=self.vid, product_id=self.pid)
|
||||||
|
self.dev = dev
|
||||||
|
log.info(f'USB device opened')
|
||||||
|
|
||||||
|
# 2 bytes: report ID and returned value
|
||||||
|
# We get back the same report ID and value
|
||||||
|
data = self.dev.get_input_report(0, 2)
|
||||||
|
assert len(data) == 2
|
||||||
|
return data[1] == 1
|
||||||
|
except OSError:
|
||||||
|
if self.dev is not None:
|
||||||
|
log.warn(f'USB device lost')
|
||||||
|
self.dev = None
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _do(self, cmd, *vals, fmt=None):
|
||||||
|
if fmt is None:
|
||||||
|
fmt = ''
|
||||||
|
|
||||||
|
fmt = '<BB' + fmt
|
||||||
|
# Prepend report ID 0
|
||||||
|
data = struct.pack(fmt, *(0, cmd) + vals)
|
||||||
|
self.dev.write(data)
|
||||||
|
|
||||||
|
def _enq(self, cmd, *vals, fmt=None):
|
||||||
|
self.queue.put((cmd, vals, fmt))
|
||||||
|
|
||||||
|
def service(self):
|
||||||
|
while not self.queue.empty():
|
||||||
|
cmd, vals, fmt = self.queue.get()
|
||||||
|
|
||||||
|
while not self._dev_ready():
|
||||||
|
if not self.running:
|
||||||
|
break
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._do(cmd, *vals, fmt=fmt)
|
||||||
|
except OSError as ex:
|
||||||
|
log.warn(f'USB device lost, state dequeuing stalled')
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.running:
|
||||||
|
while self.queue.empty():
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
self.service()
|
||||||
|
|
||||||
|
def none(self):
|
||||||
|
self._enq(0)
|
||||||
|
|
||||||
|
def menu(self, info: RiotPlayerInfo, was_idle: bool=False):
|
||||||
|
self._enq(1, 1 if was_idle else 0, fmt='B')
|
||||||
|
|
||||||
|
def idle(self, info: RiotPlayerInfo):
|
||||||
|
self._enq(2)
|
||||||
|
|
||||||
class GameState(Enum):
|
class GameState(Enum):
|
||||||
NONE = 0
|
NONE = 0
|
||||||
|
@ -280,7 +280,5 @@ void val_lvgl_ui(lv_display_t *disp) {
|
|||||||
lv_label_set_text(l_cfg, LV_SYMBOL_SETTINGS);
|
lv_label_set_text(l_cfg, LV_SYMBOL_SETTINGS);
|
||||||
lv_obj_center(l_cfg);
|
lv_obj_center(l_cfg);
|
||||||
|
|
||||||
// val_ui_none();
|
val_ui_none();
|
||||||
// val_ui_menu(true);
|
|
||||||
val_ui_idle();
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
|
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
|
||||||
|
|
||||||
@ -77,24 +78,55 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) {
|
|||||||
// Invoked when received GET_REPORT control request
|
// Invoked when received GET_REPORT control request
|
||||||
// Application must fill buffer report's content and return its length.
|
// Application must fill buffer report's content and return its length.
|
||||||
// Return zero will cause the stack to STALL request
|
// Return zero will cause the stack to STALL request
|
||||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
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) {
|
||||||
(void) instance;
|
(void) instance;
|
||||||
(void) report_id;
|
if (report_id != 0 || reqlen < 1) {
|
||||||
(void) report_type;
|
|
||||||
(void) buffer;
|
|
||||||
(void) reqlen;
|
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// Invoked when received SET_REPORT control request or
|
// Invoked when received SET_REPORT control request or
|
||||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
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) {
|
||||||
assert(report_id == 0 && report_type == HID_REPORT_TYPE_OUTPUT);
|
(void) instance;
|
||||||
ESP_LOGI(TAG, "Got %hu bytes report %hhu", bufsize, report_id);
|
assert(report_id == 0 && report_type == HID_REPORT_TYPE_OUTPUT && bufsize >= 1);
|
||||||
for (uint16_t i = 0; i < bufsize; i++) {
|
if (!val_lvgl_lock(-1)) {
|
||||||
ESP_LOGI(TAG, "b: %02hhx", buffer[i]);
|
ESP_LOGE(TAG, "Failed to grab LVGL lock");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (buf[0] > ST_IDLE) {
|
||||||
|
ESP_LOGW(TAG, "Unknown state %hhu", buf[0]);
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
if (!val_ui_state_ready()) {
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret:
|
||||||
|
val_lvgl_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void val_usb_init(void) {
|
void val_usb_init(void) {
|
||||||
|
@ -5,4 +5,10 @@
|
|||||||
#define EPNUM_HID 0x01
|
#define EPNUM_HID 0x01
|
||||||
#define USB_EP_BUFSIZE 64
|
#define USB_EP_BUFSIZE 64
|
||||||
|
|
||||||
|
typedef enum val_state {
|
||||||
|
ST_NONE = 0,
|
||||||
|
ST_MENU,
|
||||||
|
ST_IDLE
|
||||||
|
} val_state_t;
|
||||||
|
|
||||||
void val_usb_init(void);
|
void val_usb_init(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user