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
18 changes: 14 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@ permissions:

jobs:
build-teensy-firmware:
name: Build Teensy 4.1 Firmware
name: Build Teensy 4.1 Firmware (${{ matrix.config.name }})
runs-on: ubuntu-latest

strategy:
matrix:
config:
- name: with-tft
make_args: TFT=1
- name: without-tft
make_args: TFT=0
- name: with-net
make_args: NET=1

steps:
- uses: actions/checkout@v4

Expand All @@ -22,13 +32,13 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-arm-none-eabi binutils-arm-none-eabi libnewlib-arm-none-eabi

- name: Build firmware
run: make firmware.hex TOOLCHAIN=/usr/bin
- name: Build firmware (${{ matrix.config.name }})
run: make firmware.hex TOOLCHAIN=/usr/bin ${{ matrix.config.make_args }}

- name: Upload firmware artifact
uses: actions/upload-artifact@v4
with:
name: firmware-hex
name: firmware-hex-${{ matrix.config.name }}
path: firmware.hex

build-bridge-firmware:
Expand Down
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ TFT_DRIVER ?= 1
TOUCH ?= 0
# Pass UART_AUTOBAUD=1 to detect baud from incoming RX data at boot
UART_AUTOBAUD ?= 0
# Pass NET=1 to enable Ethernet (KMBox Net UDP protocol, replaces UART commands)
NET ?= 0

DEFINES = -DARDUINO_TEENSY41 -D__IMXRT1062__ -DF_CPU=816000000 -DUART_ENABLED=$(UART) \
-DUART_BAUD=$(UART_BAUD) -DTFT_ENABLED=$(TFT) -DTFT_DRIVER=$(TFT_DRIVER) \
-DTOUCH_ENABLED=$(TOUCH) -DUART_AUTOBAUD=$(UART_AUTOBAUD)
-DTOUCH_ENABLED=$(TOUCH) -DUART_AUTOBAUD=$(UART_AUTOBAUD) \
-DNET_ENABLED=$(NET)
Comment on lines +22 to +28
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabling NET compiles and exposes the KMBox Net UDP protocol (src/enet.c, src/udp.c, src/kmnet.c), but that implementation currently has effectively no strong authentication: any host that knows the 32‑bit device_uuid can send KMBox Net commands. Because this UUID is derived from the MAC, displayed on the TFT, and reused as a static token, a network attacker who learns or guesses it can connect and then inject arbitrary keyboard/mouse events or trigger device reboots over UDP. Before enabling this mode by default, you should harden the KMBox Net protocol with real per-device or per-session secrets, bind commands to the original client IP/port, and add message authentication so only an authorized peer can control the device.

Copilot uses AI. Check for mistakes.

CFLAGS = $(MCU_FLAGS) $(DEFINES) \
-Os -Wall -Wno-unused-variable \
Expand All @@ -38,7 +41,8 @@ CORE_SRC = core/startup.c core/bootdata.c
SRC = src/main.c src/uart.c src/usb_host.c src/usb_device.c src/desc_capture.c \
src/kmbox.c src/humanize.c src/smooth.c src/ferrum.c src/makcu.c \
src/tft.c src/tft_display.c src/st7735.c src/ili9341.c src/ft6206.c \
src/font6x8.c
src/font6x8.c \
src/enet.c src/udp.c src/kmnet.c

OBJ = $(CORE_SRC:.c=.o) $(SRC:.c=.o)

Expand All @@ -54,7 +58,8 @@ $(TARGET).hex: $(TARGET).elf
$(OBJCOPY) -O ihex -R .eeprom $< $@

# Hot-path sources get -O2 instead of -Os for better inlining/unrolling
HOT_SRC = src/usb_host.o src/usb_device.o src/kmbox.o src/smooth.o src/humanize.o
HOT_SRC = src/usb_host.o src/usb_device.o src/kmbox.o src/smooth.o src/humanize.o \
src/enet.o src/kmnet.o
$(HOT_SRC): CFLAGS := $(subst -Os,-O2,$(CFLAGS))

%.o: %.c
Expand Down
24 changes: 24 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,23 @@ if [[ "$uart_choice" -eq 2 ]]; then
[[ "$autobaud_choice" -eq 2 ]] && UART_AUTOBAUD=1
fi

# ── Network ──────────────────────────────────────────────────────────────
NET=0

net_choice=$(prompt_choice "Command input:" \
"UART (KMBox/Makcu/Ferrum)" \
"Ethernet (KMBox Net UDP)")

if [[ "$net_choice" -eq 2 ]]; then
NET=1
# NET mode requires TFT for IP/port/UUID display
if [[ "$TFT" -eq 0 ]]; then
printf "\n${YELLOW} Note: Ethernet mode requires TFT — enabling ST7735${RESET}\n"
TFT=1
TFT_DRIVER=1
fi
fi

# ── Build Options ───────────────────────────────────────────────────────────
CLEAN=false
if prompt_yn "Clean before build?" "n"; then
Expand Down Expand Up @@ -158,6 +175,12 @@ else
printf " │ UART: ${DIM}%-25s${RESET} │\n" "Disabled"
fi

if [[ "$NET" -eq 1 ]]; then
printf " │ Network: ${GREEN}%-25s${RESET} │\n" "KMBox Net (Ethernet)"
else
printf " │ Network: ${DIM}%-25s${RESET} │\n" "Disabled"
fi

$CLEAN && cl="Yes" || cl="No"
$FLASH && fl="Yes" || fl="No"
$BUILD_BRIDGE && br="Yes" || br="No"
Expand All @@ -182,6 +205,7 @@ MAKE_ARGS=(
"UART=${UART}"
"UART_BAUD=${UART_BAUD}"
"UART_AUTOBAUD=${UART_AUTOBAUD}"
"NET=${NET}"
"-j${PARALLEL}"
)

Expand Down
7 changes: 6 additions & 1 deletion core/startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,14 @@ FLASHMEM static void configure_cache(void)

// DMA buffer overlay: non-cacheable (higher region # wins over region 5)
// Eliminates all manual cache maintenance for USB + TFT DMA structures
// 64K covers USB buffers (~4KB) + ST7735 TFT framebuffers (~41KB)
SCB_MPU_RBAR = 0x20200000 | REGION(10);
#if NET_ENABLED
// 128K for USB (~4KB) + TFT (~41KB) + ENET (~15KB) buffers
SCB_MPU_RASR = MEM_NOCACHE | READWRITE | NOEXEC | SIZE_128K;
#else
// 64K covers USB buffers (~4KB) + ST7735 TFT framebuffers (~41KB)
SCB_MPU_RASR = MEM_NOCACHE | READWRITE | NOEXEC | SIZE_64K;
#endif

asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
SCB_MPU_CTRL = SCB_MPU_CTRL_ENABLE;
Expand Down
16 changes: 8 additions & 8 deletions src/desc_capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ bool capture_descriptors(captured_descriptors_t *desc)
int ret;
usb_setup_t setup;
setup = make_get_descriptor(USB_DESC_DEVICE, 0, 0, 8);
ret = usb_host_control_transfer(0, 8, &setup, desc->device_desc);
ret = usb_host_control_transfer(0, 8, &setup, desc->device_desc, 2000);
if (ret < 0 || ret < 8 || desc->device_desc[0] != 18 ||
desc->device_desc[1] != USB_DESC_DEVICE) {
uart_puts("FAIL: could not read device descriptor (8 bytes)\r\n");
Expand All @@ -113,15 +113,15 @@ bool capture_descriptors(captured_descriptors_t *desc)
setup.wValue = desc->dev_addr;
setup.wIndex = 0;
setup.wLength = 0;
ret = usb_host_control_transfer(0, desc->ep0_maxpkt, &setup, NULL);
ret = usb_host_control_transfer(0, desc->ep0_maxpkt, &setup, NULL, 2000);
if (ret < 0) {
uart_puts("FAIL: SET_ADDRESS\r\n");
return false;
}
delay(10); // Device needs time to process new address
setup = make_get_descriptor(USB_DESC_DEVICE, 0, 0, 18);
ret = usb_host_control_transfer(desc->dev_addr, desc->ep0_maxpkt,
&setup, desc->device_desc);
&setup, desc->device_desc, 2000);
if (ret < 0 || ret < 18 || desc->device_desc[0] != 18 ||
desc->device_desc[1] != USB_DESC_DEVICE) {
uart_puts("FAIL: full device descriptor\r\n");
Expand All @@ -130,7 +130,7 @@ bool capture_descriptors(captured_descriptors_t *desc)
desc->device_desc_len = 18;
setup = make_get_descriptor(USB_DESC_CONFIGURATION, 0, 0, 9);
ret = usb_host_control_transfer(desc->dev_addr, desc->ep0_maxpkt,
&setup, desc->config_desc);
&setup, desc->config_desc, 2000);
if (ret < 0 || ret < 9 || desc->config_desc[1] != USB_DESC_CONFIGURATION) {
uart_puts("FAIL: config descriptor header\r\n");
return false;
Expand All @@ -145,7 +145,7 @@ bool capture_descriptors(captured_descriptors_t *desc)
}
setup = make_get_descriptor(USB_DESC_CONFIGURATION, 0, 0, total_len);
ret = usb_host_control_transfer(desc->dev_addr, desc->ep0_maxpkt,
&setup, desc->config_desc);
&setup, desc->config_desc, 2000);
if (ret < 0 || ret < 9 || desc->config_desc[1] != USB_DESC_CONFIGURATION) {
uart_puts("FAIL: full config descriptor\r\n");
return false;
Expand All @@ -164,7 +164,7 @@ bool capture_descriptors(captured_descriptors_t *desc)
setup = make_get_iface_descriptor(USB_DESC_HID_REPORT, 0,
iface->iface_num, rdlen);
ret = usb_host_control_transfer(desc->dev_addr, desc->ep0_maxpkt,
&setup, iface->hid_report_desc);
&setup, iface->hid_report_desc, 2000);
if (ret < 0) {
uart_puts(" FAIL\r\n");
iface->hid_report_desc_len = 0;
Expand All @@ -176,7 +176,7 @@ bool capture_descriptors(captured_descriptors_t *desc)
uint8_t str_buf[MAX_STRING_DESC_SIZE];
setup = make_get_descriptor(USB_DESC_STRING, 0, 0, 4);
ret = usb_host_control_transfer(desc->dev_addr, desc->ep0_maxpkt,
&setup, str_buf);
&setup, str_buf, 2000);
uint16_t langid = 0x0409; // Default to English
if (ret >= 4 && str_buf[1] == USB_DESC_STRING) {
langid = str_buf[2] | (str_buf[3] << 8);
Expand All @@ -195,7 +195,7 @@ bool capture_descriptors(captured_descriptors_t *desc)
setup = make_get_descriptor(USB_DESC_STRING, string_indices[i],
langid, MAX_STRING_DESC_SIZE);
ret = usb_host_control_transfer(desc->dev_addr, desc->ep0_maxpkt,
&setup, desc->string_desc[desc->num_strings]);
&setup, desc->string_desc[desc->num_strings], 2000);
if (ret > 0) {
desc->string_desc_len[desc->num_strings] = ret;
desc->string_index[desc->num_strings] = string_indices[i];
Expand Down
Loading