Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ add_subdirectory(lib/Pico-PIO-USB)
add_subdirectory(lib/kmbox-commands)

# Shared libraries
add_subdirectory(lib/hid-defs)
add_subdirectory(lib/fast-protocol)
add_subdirectory(lib/wire-protocol)
add_subdirectory(lib/peri-clock)
add_subdirectory(lib/dma-uart)
Expand Down Expand Up @@ -161,7 +163,7 @@ target_link_libraries(PIOKMbox pico_pio_usb)
target_link_libraries(PIOKMbox kmbox_commands)

# Link shared libraries
target_link_libraries(PIOKMbox wire_protocol peri_clock dma_uart led_utils)
target_link_libraries(PIOKMbox hid_defs fast_protocol wire_protocol peri_clock dma_uart led_utils)

# Add PIO USB HCD implementation directly
target_sources(PIOKMbox PRIVATE
Expand Down
3 changes: 3 additions & 0 deletions PIOKMbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ static void core1_task_loop(void) {

tuh_task();

// Drain SET_REPORT passthrough queue (device→host vendor reports)
hid_host_task();

// Xbox host task: forward console commands to controller, keepalive
if (g_xbox_mode) {
xbox_host_task();
Expand Down
4 changes: 4 additions & 0 deletions bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/lut.pio)
endif()

# Add shared libraries
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../lib/hid-defs hid-defs)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../lib/fast-protocol fast-protocol)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../lib/kmbox-commands kmbox-commands)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../lib/wire-protocol wire-protocol)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../lib/peri-clock peri-clock)
Expand All @@ -149,6 +151,8 @@ set(BRIDGE_LIBS
hardware_uart
hardware_adc
kmbox_commands
hid_defs
fast_protocol
wire_protocol
dma_uart
led_utils
Expand Down
102 changes: 11 additions & 91 deletions bridge/fast_commands.h
Original file line number Diff line number Diff line change
@@ -1,101 +1,21 @@
/**
* Fast Binary Command Definitions for Bridge KMBox UART
* Fast Binary Command Definitions for Bridge -> KMBox UART
*
* All bridge translators (Ferrum, Makcu, tracker) should produce these
* 8-byte packets instead of text strings. The KMBox already has an
* optimized binary parser that handles them with zero string parsing.
*
* Key command IDs:
* 0x01 FAST_CMD_MOUSE_MOVE — direct accumulator (buttons + wheel + move)
* 0x02 FAST_CMD_MOUSE_CLICK — button click with repeat count
* 0x07 FAST_CMD_SMOOTH_MOVE — smooth injection queue (humanized)
* Thin wrapper — all definitions now live in the shared library
* lib/fast-protocol/include/fast_protocol.h. This file exists so
* existing bridge #include "fast_commands.h" directives continue to work.
*/

#ifndef BRIDGE_FAST_COMMANDS_H
#define BRIDGE_FAST_COMMANDS_H

#include <stdint.h>
#include <string.h>

// Command IDs (must match defines.h on KMBox side)
#define FAST_CMD_MOUSE_MOVE 0x01
#define FAST_CMD_MOUSE_CLICK 0x02
#define FAST_CMD_SMOOTH_MOVE 0x07
#define FAST_CMD_SMOOTH_CONFIG 0x08
#define FAST_CMD_SMOOTH_CLEAR 0x09
#define FAST_CMD_CYCLE_HUMAN 0x0F
#define FAST_CMD_PING 0xFE

// Smooth injection modes (must match inject_mode_t on KMBox side)
#define INJECT_MODE_IMMEDIATE 0
#define INJECT_MODE_SMOOTH 1
#define INJECT_MODE_VELOCITY_MATCHED 2
#define INJECT_MODE_MICRO 3

#define FAST_CMD_PACKET_SIZE 8

// ============================================================================
// Inline packet builders — produce 8-byte packets, return 8 always
// ============================================================================

/**
* Build FAST_CMD_SMOOTH_MOVE (0x07) packet.
* KMBox routes this through smooth_inject_movement() which applies
* humanization (easing, subdivision, tremor, overshoot) automatically.
* Use for: km.move(), tracker aim commands, makcu MOVE.
*/
static inline size_t fast_build_smooth_move(uint8_t *buf, int16_t x, int16_t y, uint8_t mode) {
buf[0] = FAST_CMD_SMOOTH_MOVE;
buf[1] = (uint8_t)(x & 0xFF);
buf[2] = (uint8_t)((x >> 8) & 0xFF);
buf[3] = (uint8_t)(y & 0xFF);
buf[4] = (uint8_t)((y >> 8) & 0xFF);
buf[5] = mode;
buf[6] = 0;
buf[7] = 0;
return FAST_CMD_PACKET_SIZE;
}

/**
* Build FAST_CMD_MOUSE_MOVE (0x01) packet.
* KMBox routes this through kmbox_add_mouse_movement() (direct accumulator)
* plus optional buttons + wheel. No smooth queue / humanization subdivision.
* Use for: button state changes, wheel, raw passthrough moves.
*/
static inline size_t fast_build_mouse_move(uint8_t *buf, int16_t x, int16_t y,
uint8_t buttons, int8_t wheel) {
buf[0] = FAST_CMD_MOUSE_MOVE;
buf[1] = (uint8_t)(x & 0xFF);
buf[2] = (uint8_t)((x >> 8) & 0xFF);
buf[3] = (uint8_t)(y & 0xFF);
buf[4] = (uint8_t)((y >> 8) & 0xFF);
buf[5] = buttons;
buf[6] = (uint8_t)wheel;
buf[7] = 0;
return FAST_CMD_PACKET_SIZE;
}

/**
* Build FAST_CMD_MOUSE_CLICK (0x02) packet.
* KMBox generates press + release pairs internally.
*/
static inline size_t fast_build_mouse_click(uint8_t *buf, uint8_t button, uint8_t count) {
buf[0] = FAST_CMD_MOUSE_CLICK;
buf[1] = button;
buf[2] = count;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
return FAST_CMD_PACKET_SIZE;
}
#include "fast_protocol.h"

// Button masks (match HID standard)
#define FAST_BTN_LEFT 0x01
#define FAST_BTN_RIGHT 0x02
#define FAST_BTN_MIDDLE 0x04
#define FAST_BTN_BACK 0x08
#define FAST_BTN_FORWARD 0x10
// Legacy button mask aliases — prefer HID_BTN_* from hid_defs.h in new code
#define FAST_BTN_LEFT HID_BTN_LEFT
#define FAST_BTN_RIGHT HID_BTN_RIGHT
#define FAST_BTN_MIDDLE HID_BTN_MIDDLE
#define FAST_BTN_BACK HID_BTN_BACK
#define FAST_BTN_FORWARD HID_BTN_FORWARD

#endif // BRIDGE_FAST_COMMANDS_H
26 changes: 13 additions & 13 deletions bridge/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ static uint32_t uart_rx_bytes_total = 0;
static uint32_t uart_tx_bytes_total = 0;
static uint32_t uart_rx_overflows = 0;

// KMBox temperature (from 0x0C info packet)
// KMBox temperature (from 0x0D info packet)
static float kmbox_temperature_c = -999.0f;

// Sync stats from hw_uart module (called periodically)
Expand Down Expand Up @@ -496,8 +496,8 @@ static void uart_rx_task(void) {
binary_idx = 0;
}

// Check for start of binary response packet (0xFF, 0xFE, 0x0C, or 0x0E from KMBox)
if (!in_binary_packet && (c == 0xFF || c == 0xFE || c == 0x0C || c == 0x0E)) {
// Check for start of binary response packet (0xFF, 0xFE, 0x0D, or 0x0E from KMBox)
if (!in_binary_packet && (c == 0xFF || c == 0xFE || c == 0x0D || c == 0x0E)) {
in_binary_packet = true;
binary_idx = 0;
binary_packet[binary_idx++] = c;
Expand Down Expand Up @@ -530,8 +530,8 @@ static void uart_rx_task(void) {
if (kmbox_state != KMBOX_CONNECTED) {
kmbox_state = KMBOX_CONNECTED;
}
} else if (binary_packet[0] == 0x0C) {
// Info response: [0x0C][hmode][imode][max_per_frame][queue_count][temp_lo][temp_hi][flags]
} else if (binary_packet[0] == 0x0D) {
// Info response: [0x0D][hmode][imode][max_per_frame][queue_count][temp_lo][temp_hi][flags]
// flags: [0]=jitter_en [1]=vel_match [2:4]=queue_depth_3bit
kmbox_humanization_mode = binary_packet[1];
kmbox_inject_mode = binary_packet[2];
Expand All @@ -555,7 +555,7 @@ static void uart_rx_task(void) {
// Extended stats: [0x0E][queue_count][queue_cap][hmode][total_lo][total_hi][ovf_lo][ovf_hi]
kmbox_queue_depth = binary_packet[1];
kmbox_queue_capacity = binary_packet[2];
// binary_packet[3] = hmode (redundant, but useful if 0x0C wasn't received)
// binary_packet[3] = hmode (redundant, but useful if 0x0D wasn't received)
if (!kmbox_humanization_valid) {
kmbox_humanization_mode = binary_packet[3];
}
Expand Down Expand Up @@ -672,7 +672,7 @@ static void kmbox_connection_task(void) {
last_humanization_request_ms = now - HUMANIZATION_REQUEST_INTERVAL_MS + HUMANIZATION_INITIAL_DELAY_MS;

// Send initial info request right away (binary)
uint8_t info_req[8] = {0x0C, 0, 0, 0, 0, 0, 0, 0};
uint8_t info_req[8] = {0x0D, 0, 0, 0, 0, 0, 0, 0};
send_uart_packet(info_req, 8);
}
}
Expand All @@ -696,11 +696,11 @@ static void kmbox_connection_task(void) {
if (now - last_humanization_request_ms >= HUMANIZATION_REQUEST_INTERVAL_MS) {
last_humanization_request_ms = now;

// Alternate between 0x0C (basic info + temp) and 0x0E (extended stats)
// Alternate between 0x0D (basic info + temp) and 0x0E (extended stats)
static uint8_t info_cycle = 0;
if (info_cycle % 2 == 0) {
// Primary: humanization mode, inject mode, queue depth, temperature, flags
uint8_t info_req[8] = {0x0C, 0, 0, 0, 0, 0, 0, 0};
uint8_t info_req[8] = {0x0D, 0, 0, 0, 0, 0, 0, 0};
send_uart_packet(info_req, 8);
} else {
// Extended: total injected, queue overflows, queue capacity
Expand Down Expand Up @@ -736,16 +736,16 @@ static void kmbox_connection_task(void) {
}
}

// TEMP: Send 0x0C request even when disconnected to test UART RX
// Send 0x0D info request even when disconnected to test UART RX
if (now - last_humanization_request_ms >= HUMANIZATION_REQUEST_INTERVAL_MS) {
last_humanization_request_ms = now;
uint8_t info_req[8] = {0x0C, 0, 0, 0, 0, 0, 0, 0};
uint8_t info_req[8] = {0x0D, 0, 0, 0, 0, 0, 0, 0};
bool sent = send_uart_packet(info_req, 8);

// Debug: confirm we're sending the request
static uint32_t last_info_debug_disc = 0;
if (now - last_info_debug_disc > 5000) {
printf("[Bridge TX DISC] 0x0C: %02X %02X %02X %02X %02X %02X %02X %02X (sent=%d)\n",
printf("[Bridge TX DISC] 0x0D: %02X %02X %02X %02X %02X %02X %02X %02X (sent=%d)\n",
info_req[0], info_req[1], info_req[2], info_req[3],
info_req[4], info_req[5], info_req[6], info_req[7], sent);
last_info_debug_disc = now;
Expand Down
10 changes: 5 additions & 5 deletions bridge/makcu_translator.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ uint16_t makcu_build_response(
// Helper: Convert Makcu button number to HID button mask
static uint8_t makcu_button_to_mask(uint8_t button) {
switch (button) {
case 1: return 0x01; // Left
case 2: return 0x02; // Right
case 3: return 0x04; // Middle
case 4: return 0x08; // Side1
case 5: return 0x10; // Side2
case 1: return HID_BTN_LEFT;
case 2: return HID_BTN_RIGHT;
case 3: return HID_BTN_MIDDLE;
case 4: return HID_BTN_BACK;
case 5: return HID_BTN_FORWARD;
default: return 0x00;
}
}
Expand Down
Loading
Loading