aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt9
-rw-r--r--Makefile30
-rw-r--r--compile_commands.json128
-rw-r--r--src/hid.c65
-rw-r--r--src/main.c69
-rw-r--r--src/matrix.c53
-rw-r--r--src/matrix.h17
-rw-r--r--src/split.c124
-rw-r--r--src/split.h4
-rw-r--r--src/usb_stdio.c40
-rw-r--r--src/usb_stdio.h3
-rw-r--r--src/util.c2
12 files changed, 284 insertions, 260 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be4a8c8..ac503fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,8 +14,11 @@ target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/split.c
${CMAKE_CURRENT_SOURCE_DIR}/src/neopix.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/matrix.c
${CMAKE_CURRENT_SOURCE_DIR}/src/keymap.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_stdio.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)
@@ -24,6 +27,7 @@ target_include_directories(${PROJECT} PUBLIC
${PICO_SDK_PATH}/src/rp2_common/hardware_gpio/include
${PICO_SDK_PATH}/src/rp2_common/hardware_pio/include
${PICO_SDK_PATH}/src/rp2_common/hardware_timer/include
+ ${PICO_SDK_PATH}/src/rp2_common/hardware_uart/include
)
target_link_libraries(${PROJECT} PRIVATE
@@ -40,6 +44,11 @@ target_compile_options(pico_stdio INTERFACE
-Wno-unused-parameter
)
+target_compile_options(${PROJECT} PRIVATE
+ "-DSPLIT_SIDE=${SPLIT_LEFT}"
+ "-DSPLIT_ROLE=${SPLIT_ROLE}"
+)
+
family_configure_target(${PROJECT})
family_add_default_example_warnings(${PROJECT})
suppress_tinyusb_warnings()
diff --git a/Makefile b/Makefile
index a47ee7d..70763b2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,34 @@
FAMILY ?= rp2040
PICO_SDK_PATH ?= lib/picosdk
-all: cmake
+all: left
clean:
rm -rf .build
-cmake: | $(PICO_SDK_PATH) .build
- cmake -B .build -DFAMILY=$(FAMILY) -DPICO_SDK_PATH=$(PICO_SDK_PATH)
- make -C .build
+left: | $(PICO_SDK_PATH) .build/left
+ cmake -B .build/left -DFAMILY=$(FAMILY) -DPICO_SDK_PATH=$(PICO_SDK_PATH) \
+ -DSPLIT_SIDE=LEFT -DSPLIT_ROLE=MASTER
+ make -C .build/left
+
+right: | $(PICO_SDK_PATH) .build/right
+ cmake -B .build/right -DFAMILY=$(FAMILY) -DPICO_SDK_PATH=$(PICO_SDK_PATH) \
+ -DSPLIT_SIDE=RIGHT -DSPLIT_ROLE=SLAVE
+ make -C .build/right
lib/picosdk:
git submodule update --init lib/picosdk
-.build:
- mkdir $@
+.build/left:
+ mkdir -p $@
+
+.build/right:
+ mkdir -p $@
+
+flash_left:
+ picotool load .build/left/sxkbd.uf2
-flash:
- picotool load .build/sxkbd.uf2
+flash_right:
+ picotool load .build/right/sxkbd.uf2
-.PHONY: all clean cmake upload
+.PHONY: all clean left right upload
diff --git a/compile_commands.json b/compile_commands.json
deleted file mode 100644
index 1cc75f0..0000000
--- a/compile_commands.json
+++ /dev/null
@@ -1,128 +0,0 @@
-[
- {
- "arguments": [
- "/usr/bin/arm-none-eabi-gcc",
- "-DCFG_TUSB_MCU=OPT_MCU_RP2040",
- "-DCFG_TUSB_OS=OPT_OS_PICO",
- "-DLIB_PICO_BIT_OPS=1",
- "-DLIB_PICO_BIT_OPS_PICO=1",
- "-DLIB_PICO_BOOTSEL_VIA_DOUBLE_RESET=1",
- "-DLIB_PICO_DIVIDER=1",
- "-DLIB_PICO_DIVIDER_HARDWARE=1",
- "-DLIB_PICO_DOUBLE=1",
- "-DLIB_PICO_DOUBLE_PICO=1",
- "-DLIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1",
- "-DLIB_PICO_FLOAT=1",
- "-DLIB_PICO_FLOAT_PICO=1",
- "-DLIB_PICO_INT64_OPS=1",
- "-DLIB_PICO_INT64_OPS_PICO=1",
- "-DLIB_PICO_MALLOC=1",
- "-DLIB_PICO_MEM_OPS=1",
- "-DLIB_PICO_MEM_OPS_PICO=1",
- "-DLIB_PICO_PLATFORM=1",
- "-DLIB_PICO_PRINTF=1",
- "-DLIB_PICO_PRINTF_PICO=1",
- "-DLIB_PICO_RUNTIME=1",
- "-DLIB_PICO_STANDARD_LINK=1",
- "-DLIB_PICO_STDIO=1",
- "-DLIB_PICO_STDIO_UART=1",
- "-DLIB_PICO_STDLIB=1",
- "-DLIB_PICO_SYNC=1",
- "-DLIB_PICO_SYNC_CORE=1",
- "-DLIB_PICO_SYNC_CRITICAL_SECTION=1",
- "-DLIB_PICO_SYNC_MUTEX=1",
- "-DLIB_PICO_SYNC_SEM=1",
- "-DLIB_PICO_TIME=1",
- "-DLIB_PICO_UTIL=1",
- "-DLIB_TINYUSB_BOARD=1",
- "-DLIB_TINYUSB_DEVICE=1",
- "-DPICO_BOARD=\"pico\"",
- "-DPICO_BUILD=1",
- "-DPICO_CMAKE_BUILD_TYPE=\"Release\"",
- "-DPICO_COPY_TO_RAM=0",
- "-DPICO_CXX_ENABLE_EXCEPTIONS=0",
- "-DPICO_NO_FLASH=0",
- "-DPICO_NO_HARDWARE=0",
- "-DPICO_ON_DEVICE=1",
- "-DPICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1",
- "-DPICO_TARGET_NAME=\"sxkbd\"",
- "-DPICO_USE_BLOCKED_RAM=0",
- "-I/snx/dev/sxkbd/src",
- "-I/usr/share/pico-sdk/src/common/pico_stdlib/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_gpio/include",
- "-I/usr/share/pico-sdk/src/common/pico_base/include",
- "-I/snx/dev/sxkbd/.build/generated/pico_base",
- "-I/usr/share/pico-sdk/src/boards/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_platform/include",
- "-I/usr/share/pico-sdk/src/rp2040/hardware_regs/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_base/include",
- "-I/usr/share/pico-sdk/src/rp2040/hardware_structs/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_claim/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_sync/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_irq/include",
- "-I/usr/share/pico-sdk/src/common/pico_sync/include",
- "-I/usr/share/pico-sdk/src/common/pico_time/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_timer/include",
- "-I/usr/share/pico-sdk/src/common/pico_util/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_uart/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_divider/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_runtime/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_clocks/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_resets/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_pll/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_vreg/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_watchdog/include",
- "-I/usr/share/pico-sdk/src/rp2_common/hardware_xosc/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_printf/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_bootrom/include",
- "-I/usr/share/pico-sdk/src/common/pico_bit_ops/include",
- "-I/usr/share/pico-sdk/src/common/pico_divider/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_double/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_int64_ops/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_float/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_malloc/include",
- "-I/usr/share/pico-sdk/src/rp2_common/boot_stage2/include",
- "-I/usr/share/pico-sdk/src/common/pico_binary_info/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_stdio/include",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_stdio_uart/include",
- "-I/snx/dev/sxkbd/lib/tinyusb/src",
- "-I/snx/dev/sxkbd/lib/tinyusb/src/common",
- "-I/snx/dev/sxkbd/lib/tinyusb/hw",
- "-I/usr/share/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include",
- "-mcpu=cortex-m0plus",
- "-mthumb",
- "-O3",
- "-DNDEBUG",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wfatal-errors",
- "-Wdouble-promotion",
- "-Wfloat-equal",
- "-Wshadow",
- "-Wwrite-strings",
- "-Wsign-compare",
- "-Wmissing-format-attribute",
- "-Wunreachable-code",
- "-Wcast-align",
- "-Wcast-qual",
- "-Wnull-dereference",
- "-Wuninitialized",
- "-Wunused",
- "-Wredundant-decls",
- "-Wconversion",
- "-Wcast-function-type",
- "-Wstrict-overflow",
- "-Wno-strict-aliasing",
- "-ffunction-sections",
- "-fdata-sections",
- "-c",
- "-o",
- "CMakeFiles/sxkbd.dir/src/main.c.obj",
- "/snx/dev/sxkbd/src/main.c"
- ],
- "directory": "/snx/dev/sxkbd/.build",
- "file": "/snx/dev/sxkbd/src/main.c",
- "output": "/snx/dev/sxkbd/.build/CMakeFiles/sxkbd.dir/src/main.c.obj"
- }
-]
diff --git a/src/hid.c b/src/hid.c
index 7ff1159..ed4eedd 100644
--- a/src/hid.c
+++ b/src/hid.c
@@ -1,75 +1,14 @@
-#include "board.h"
-#include "util.h"
-
-#include "hardware/timer.h"
-
-#define KEY_ROWS ARRLEN(matrix_row_pins)
-#define KEY_COLS ARRLEN(matrix_col_pins)
-#define KEY_COUNT (KEY_ROWS * KEY_COLS)
-
-static void handle_press(uint x, uint y);
-static void handle_release(uint x, uint y);
-
-static const uint matrix_col_pins[] = { 4, 5, 6, 7 };
-static const uint matrix_row_pins[] = { 29, 28, 27, 26, 22, 20 };
-
-//static uint press_index = 0;
-static bool press_map[KEY_COUNT] = { 0 };
-//static uint32_t press_syms[KEY_COUNT] = { 0 };
-//static uint8_t press_order[KEY_COUNT] = { 0 };
-
-void
-handle_press(uint x, uint y)
-{
-
-}
-
-void
-handle_release(uint x, uint y)
-{
-
-}
+#include "hid.h"
void
hid_init(void)
{
- uint x, y;
-
- for (y = 0; y < ARRLEN(matrix_row_pins); y++) {
- gpio_init(matrix_row_pins[y]);
- gpio_set_dir(matrix_row_pins[y], GPIO_IN);
- gpio_pull_up(matrix_row_pins[y]);
- }
-
- for (x = 0; x < ARRLEN(matrix_col_pins); x++) {
- gpio_init(matrix_col_pins[x]);
- gpio_set_dir(matrix_col_pins[x], GPIO_OUT);
- }
+
}
void
hid_task(void)
{
- bool pressed;
- uint x, y;
-
- /* scan matrix */
- for (y = 0; y < ARRLEN(matrix_row_pins); y++) {
- for (x = 0; x < ARRLEN(matrix_col_pins); x++) {
- gpio_put(matrix_col_pins[x], 0);
- busy_wait_us(5);
- pressed = !gpio_get(matrix_row_pins[y]);
- if (pressed && !press_map[y * KEY_COLS + x]) {
- handle_press(x, y);
- press_map[y * KEY_COLS + x] = true;
- } else if (!pressed && press_map[y * KEY_COLS + x]) {
- handle_release(x, y);
- press_map[y * KEY_COLS + x] = false;
- }
- gpio_put(matrix_col_pins[x], 1);
- busy_wait_us(5);
- }
- }
/* assemble hid report */
}
diff --git a/src/main.c b/src/main.c
index 0460e71..02dcc41 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,7 @@
#include "board.h"
+#include "usb_stdio.h"
+#include "matrix.h"
+#include "split.h"
#include "hid.h"
#include "keymap.h"
#include "neopix.h"
@@ -8,7 +11,6 @@
#include "class/cdc/cdc_device.h"
#include "class/hid/hid.h"
#include "device/usbd.h"
-#include "pico/stdio/driver.h"
#include "pico/stdlib.h"
#include "bsp/board.h"
#include "pico/time.h"
@@ -25,21 +27,10 @@ enum {
BLINK_SUSPENDED = 2500,
};
-void stub_stdio_write(const char *buf, int len);
-void stub_stdio_flush(void);
-int stub_stdio_read(char *buf, int len);
-
bool send_hid_report(int id, bool state);
void blink_task(void);
-static struct stdio_driver usb_stdio = {
- .out_chars = stub_stdio_write,
- .out_flush = stub_stdio_flush,
- .in_chars = stub_stdio_read,
- .next = NULL
-};
-
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
static bool hit_state = false;
@@ -52,44 +43,24 @@ int
main(void)
{
board_init();
-
- stdio_set_driver_enabled(&usb_stdio, true);
- stdio_init_all();
-
- neopix_init(&onboard_led, pio0, 0, 25);
tud_init(BOARD_TUD_RHPORT);
- hid_init();
-
- DEBUG("Init done.");
+ usb_stdio_init();
+ neopix_init(&onboard_led, pio0, 0, 25);
+ matrix_init();
+ split_init();
+ //hid_init();
while (true) {
tud_task();
blink_task();
- hid_task();
+ split_task();
+ //hid_task();
}
return 0;
}
void
-stub_stdio_write(const char *buf, int len)
-{
- tud_cdc_write(buf, (uint32_t) len);
-}
-
-void
-stub_stdio_flush(void)
-{
- tud_cdc_write_flush();
-}
-
-int
-stub_stdio_read(char *buf, int len)
-{
- return (int) tud_cdc_read(buf, (uint32_t) len);
-}
-
-void
tud_mount_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
@@ -104,7 +75,6 @@ tud_umount_cb(void)
void
tud_suspend_cb(bool remote_wakeup_en)
{
- (void) remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}
@@ -117,27 +87,17 @@ tud_resume_cb(void)
void
tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
- (void) itf;
- (void) rts;
- (void) dtr;
}
void
tud_cdc_rx_cb(uint8_t itf)
{
- (void) itf;
}
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;
}
@@ -145,11 +105,6 @@ 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_id;
- (void) report_type;
- (void) buffer;
- (void) bufsize;
}
void
@@ -158,10 +113,6 @@ tud_hid_report_complete_cb(uint8_t instance,
{
uint8_t id;
- (void) instance;
- (void) report;
- (void) len;
-
for (id = report[0] + 1; id < REPORT_ID_MAX; id++) {
if (send_hid_report(id, hit_state))
break;
diff --git a/src/matrix.c b/src/matrix.c
new file mode 100644
index 0000000..1da8289
--- /dev/null
+++ b/src/matrix.c
@@ -0,0 +1,53 @@
+#include "keymap.h"
+
+#include "matrix.h"
+#include "pico/types.h"
+#include "hardware/gpio.h"
+#include "hardware/timer.h"
+
+#include <string.h>
+
+static const uint matrix_row_pins[] = { 4, 5, 6, 7 };
+static const uint matrix_col_pins[] = { 29, 28, 27, 26, 22, 20 };
+static_assert(ARRLEN(matrix_row_pins) == KEY_ROWS);
+static_assert(ARRLEN(matrix_col_pins) == KEY_COLS);
+
+bool prev_state_matrix[KEY_COUNT];
+bool state_matrix[KEY_COUNT];
+
+void
+matrix_init(void)
+{
+ uint x, y;
+
+ for (y = 0; y < KEY_ROWS; y++) {
+ gpio_init(matrix_row_pins[y]);
+ gpio_set_dir(matrix_row_pins[y], GPIO_IN);
+ gpio_pull_up(matrix_row_pins[y]);
+ }
+
+ for (x = 0; x < KEY_COLS; x++) {
+ gpio_init(matrix_col_pins[x]);
+ gpio_set_dir(matrix_col_pins[x], GPIO_OUT);
+ }
+}
+
+void
+scan_matrix(void)
+{
+ bool pressed;
+ uint x, y;
+
+ memcpy(prev_state_matrix, state_matrix, sizeof(state_matrix));
+
+ for (y = 0; y < KEY_ROWS; y++) {
+ for (x = 0; x < KEY_COLS; x++) {
+ gpio_put(matrix_col_pins[x], 0);
+ busy_wait_us(5);
+ pressed = !gpio_get(matrix_row_pins[y]);
+ state_matrix[y * KEY_COLS + x] = pressed;
+ gpio_put(matrix_col_pins[x], 1);
+ busy_wait_us(5);
+ }
+ }
+}
diff --git a/src/matrix.h b/src/matrix.h
new file mode 100644
index 0000000..749d16f
--- /dev/null
+++ b/src/matrix.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "util.h"
+
+#include <stdint.h>
+
+#define KEY_ROWS 4
+#define KEY_COLS 6
+#define KEY_COUNT (KEY_ROWS * KEY_COLS)
+
+void matrix_init(void);
+void scan_matrix(void);
+
+extern bool prev_state_matrix[KEY_COUNT];
+extern bool state_matrix[KEY_COUNT];
+extern uint32_t sym_matrix[KEY_COUNT];
+
diff --git a/src/split.c b/src/split.c
new file mode 100644
index 0000000..ac07868
--- /dev/null
+++ b/src/split.c
@@ -0,0 +1,124 @@
+#include "split.h"
+#include "util.h"
+#include "matrix.h"
+
+#include "hardware/gpio.h"
+#include "hardware/regs/intctrl.h"
+#include "hardware/uart.h"
+#include "hardware/timer.h"
+#include "bsp/board.h"
+#include "tusb.h"
+
+#define UART_TX_PIN 0
+#define UART_RX_PIN 1
+
+enum {
+ CMD_SCAN_MATRIX_REQ = 0x80,
+ CMD_SCAN_MATRIX_RESP,
+ CMD_STDIO_PUTS
+};
+
+enum { SLAVE, MASTER };
+enum { LEFT, RIGHT };
+
+static void split_rx_cmd(uint8_t cmd);
+static void split_rx(void);
+
+static bool scan_pending = false;
+
+void
+split_rx_cmd(uint8_t cmd)
+{
+ char buf[64];
+ uint8_t c;
+ uint len;
+
+ switch (cmd) {
+ case CMD_SCAN_MATRIX_REQ:
+ if (SPLIT_ROLE != SLAVE);
+ break;
+ scan_pending = true;
+ return;
+ case CMD_SCAN_MATRIX_RESP:
+ if (SPLIT_ROLE != MASTER);
+ break;
+ scan_pending = false;
+ return;
+ case CMD_STDIO_PUTS:
+ if (SPLIT_ROLE != MASTER);
+ break;
+ len = 0;
+ while (uart_is_readable(uart0) && (c = uart_getc(uart0))) {
+ if (len == ARRLEN(buf)) {
+ tud_cdc_write(buf, len);
+ buf[0] = c;
+ len = 1;
+ } else {
+ buf[len++] = c;
+ }
+ }
+ if (len) {
+ tud_cdc_write(buf, len);
+ tud_cdc_write_flush();
+ }
+ return;
+ }
+
+ WARN("Unexpected uart cmd: %i", cmd);
+}
+
+void
+split_rx(void)
+{
+ while (uart_is_readable(uart0))
+ split_rx_cmd(uart_getc(uart0));
+}
+
+void
+split_init(void)
+{
+ uart_init(uart0, 2400);
+
+ gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
+ gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
+
+ uart_set_baudrate(uart0, 115200);
+
+ uart_set_hw_flow(uart0, false, false);
+
+ uart_set_format(uart0, 8, 1, UART_PARITY_NONE);
+
+ uart_set_fifo_enabled(uart0, true);
+
+ irq_set_exclusive_handler(UART0_IRQ, split_rx);
+ irq_set_enabled(UART0_IRQ, true);
+
+ uart_set_irq_enables(uart0, true, false);
+}
+
+void
+split_task(void)
+{
+ uint32_t start_ms;
+
+ if (SPLIT_ROLE == SLAVE) {
+ if (scan_pending) {
+ scan_matrix();
+ uart_putc_raw(uart0, CMD_SCAN_MATRIX_RESP);
+ scan_pending = false;
+ }
+ uart_putc_raw(uart0, CMD_STDIO_PUTS);
+ uart_putc_raw(uart0, '.');
+ uart_putc_raw(uart0, 0);
+ } else if (SPLIT_ROLE == MASTER) {
+ scan_pending = true;
+ uart_putc_raw(uart0, CMD_SCAN_MATRIX_REQ);
+ scan_matrix(); /* scan our side in parallel */
+ start_ms = board_millis();
+ while (scan_pending && board_millis() < start_ms + 50)
+ tud_task();
+ if (scan_pending) WARN("Slave matrix scan timeout");
+ else DEBUG("Slave matrix scan success");
+ scan_pending = false;
+ }
+}
diff --git a/src/split.h b/src/split.h
new file mode 100644
index 0000000..420b93d
--- /dev/null
+++ b/src/split.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void split_init(void);
+void split_task(void);
diff --git a/src/usb_stdio.c b/src/usb_stdio.c
new file mode 100644
index 0000000..90beefb
--- /dev/null
+++ b/src/usb_stdio.c
@@ -0,0 +1,40 @@
+#include "usb_stdio.h"
+
+#include "pico/stdio/driver.h"
+#include "tusb.h"
+
+static void usb_stdio_write(const char *buf, int len);
+static void usb_stdio_flush(void);
+static int usb_stdio_read(char *buf, int len);
+
+static struct stdio_driver usb_stdio = {
+ .out_chars = usb_stdio_write,
+ .out_flush = usb_stdio_flush,
+ .in_chars = usb_stdio_read,
+ .next = NULL
+};
+
+void
+usb_stdio_write(const char *buf, int len)
+{
+ tud_cdc_write(buf, (uint32_t) len);
+}
+
+void
+usb_stdio_flush(void)
+{
+ tud_cdc_write_flush();
+}
+
+int
+usb_stdio_read(char *buf, int len)
+{
+ return (int) tud_cdc_read(buf, (uint32_t) len);
+}
+
+void
+usb_stdio_init(void)
+{
+ stdio_set_driver_enabled(&usb_stdio, true);
+ stdio_init_all();
+}
diff --git a/src/usb_stdio.h b/src/usb_stdio.h
new file mode 100644
index 0000000..bbb4ea2
--- /dev/null
+++ b/src/usb_stdio.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void usb_stdio_init(void);
diff --git a/src/util.c b/src/util.c
index 797a259..b4a7fba 100644
--- a/src/util.c
+++ b/src/util.c
@@ -15,7 +15,7 @@ __attribute__((format(printf, 1, 0)))
panic_task(const char *fmtstr, va_list ap)
{
va_list cpy;
- char c;
+ char c;
if (!tud_cdc_available())
return;