Files
AudioMixer/hid_mixer.c
T
2026-09-07 14:40:16 +03:00

200 lines
4.7 KiB
C

#include "hid_mixer.h"
#include "tusb.h"
#include <string.h>
static mixer_state_t g_state;
static int16_t enc1_acc;
static int16_t enc2_acc;
static uint8_t flags_acc;
static uint8_t pot_val;
static bool pot_dirty;
static bool need_send;
void hid_mixer_init(void) {
memset(&g_state, 0, sizeof(g_state));
g_state.ui_dirty = true;
enc1_acc = 0;
enc2_acc = 0;
flags_acc = 0;
pot_val = 50;
pot_dirty = true;
need_send = true;
}
mixer_state_t *hid_mixer_state(void) {
return &g_state;
}
bool hid_mixer_mounted(void) {
return tud_mounted() && tud_hid_ready();
}
void hid_mixer_add_enc1(int8_t delta) {
enc1_acc += delta;
if (enc1_acc > 127) {
enc1_acc = 127;
}
if (enc1_acc < -127) {
enc1_acc = -127;
}
need_send = true;
}
void hid_mixer_add_enc2(int8_t delta) {
enc2_acc += delta;
if (enc2_acc > 127) {
enc2_acc = 127;
}
if (enc2_acc < -127) {
enc2_acc = -127;
}
need_send = true;
}
void hid_mixer_set_e1_sw(bool pressed) {
if (pressed) {
flags_acc |= AUSIO_FLAG_E1_SW;
need_send = true;
}
}
void hid_mixer_set_e2_sw(bool pressed) {
if (pressed) {
flags_acc |= AUSIO_FLAG_E2_SW;
need_send = true;
}
}
void hid_mixer_set_pot(uint8_t pot_0_100) {
if (pot_0_100 > 100) {
pot_0_100 = 100;
}
if (pot_val != pot_0_100) {
pot_val = pot_0_100;
pot_dirty = true;
need_send = true;
}
}
static void send_input_if_needed(void) {
if (!need_send && !pot_dirty) {
return;
}
if (!tud_hid_ready()) {
return;
}
uint8_t report[AUSIO_INPUT_SIZE];
memset(report, 0, sizeof(report));
report[0] = AUSIO_REPORT_ID_INPUT;
report[1] = (uint8_t)(int8_t)enc1_acc;
report[2] = (uint8_t)(int8_t)enc2_acc;
report[3] = flags_acc;
report[4] = pot_val;
if (tud_hid_report(AUSIO_REPORT_ID_INPUT, report + 1, AUSIO_INPUT_SIZE - 1)) {
enc1_acc = 0;
enc2_acc = 0;
flags_acc = 0;
pot_dirty = false;
need_send = false;
}
}
void hid_mixer_task(void) {
tud_task();
bool alive = tud_mounted();
if (alive != g_state.host_alive) {
g_state.host_alive = alive;
g_state.ui_dirty = true;
}
send_input_if_needed();
}
/* TinyUSB callbacks */
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type,
uint8_t const *buffer, uint16_t bufsize) {
(void)itf;
(void)report_type;
/* With report ID, TinyUSB may pass id separately and buffer without id,
or include id in buffer depending on path. Handle both. */
const uint8_t *p = buffer;
uint16_t len = bufsize;
if (report_id == 0 && len > 0) {
report_id = p[0];
p++;
len--;
}
if (report_id != AUSIO_REPORT_ID_OUTPUT) {
return;
}
if (len < (AUSIO_HDR_SIZE - 1)) {
return;
}
/* p[0]=count, p[1]=selected, p[2]=master, p[3]=page, p[4]=n_vis (no report id) */
mixer_state_t next = g_state;
next.session_count = p[0];
next.selected = p[1];
next.master_vol = p[2];
next.page_start = p[3];
next.n_visible = p[4];
if (next.n_visible > AUSIO_MAX_VISIBLE) {
next.n_visible = AUSIO_MAX_VISIBLE;
}
uint16_t off = 5;
for (uint8_t i = 0; i < next.n_visible; i++) {
if (off + AUSIO_SLOT_SIZE > len) {
next.n_visible = i;
break;
}
next.visible[i].vol = p[off];
memcpy(next.visible[i].name, &p[off + 1], AUSIO_NAME_CHARS);
next.visible[i].name[AUSIO_NAME_CHARS] = '\0';
off = (uint16_t)(off + AUSIO_SLOT_SIZE);
}
bool changed =
next.session_count != g_state.session_count ||
next.selected != g_state.selected ||
next.master_vol != g_state.master_vol ||
next.page_start != g_state.page_start ||
next.n_visible != g_state.n_visible;
if (!changed) {
for (uint8_t i = 0; i < next.n_visible; i++) {
if (next.visible[i].vol != g_state.visible[i].vol ||
memcmp(next.visible[i].name, g_state.visible[i].name, AUSIO_NAME_CHARS) != 0) {
changed = true;
break;
}
}
}
if (changed) {
next.ui_dirty = true;
next.host_alive = g_state.host_alive;
g_state = next;
}
}
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type,
uint8_t *buffer, uint16_t reqlen) {
(void)itf;
(void)report_id;
(void)report_type;
(void)buffer;
(void)reqlen;
return 0;
}
void tud_hid_report_complete_cb(uint8_t itf, uint8_t const *report, uint16_t len) {
(void)itf;
(void)report;
(void)len;
}