#include "hid_mixer.h" #include "tusb.h" #include 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; }