sxkbd

Firmware for RP2040-based corne split keyboard
git clone https://git.sinitax.com/sinitax/sxkbd
Log | Files | Refs | Submodules | README | LICENSE | sfeed.txt

commit 4c462d0af136c244e2c2edf6f464c5f495f5b870
parent 8e0fad10878f0e81b8ed4d00187309c5ba96287d
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 10 Aug 2024 02:32:33 +0200

Switch to event-triggered messaging

Diffstat:
MMakefile | 2+-
Msrc/keymat.c | 42+++++++++++++++++++++++++++++-------------
Msrc/keymat.h | 7+++----
Msrc/main.c | 1+
Msrc/split.c | 253+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/util.c | 2+-
Msrc/util.h | 8++++++++
7 files changed, 162 insertions(+), 153 deletions(-)

diff --git a/Makefile b/Makefile @@ -13,7 +13,7 @@ CMAKE_C_FLAGS = -DSPLIT_SIDE=$(shell echo "$(SIDE)" | tr a-z A-Z) ifdef ROLE CMAKE_C_FLAGS += -DSPLIT_ROLE=$(shell echo "$(ROLE)" | tr a-z A-Z) endif -ifdef GPIO_MOD +ifneq ($(GPIO_MOD),0) CMAKE_C_FLAGS += -DBAD_GPIO_MITIGATION=1 endif diff --git a/src/keymat.c b/src/keymat.c @@ -2,13 +2,17 @@ #include "keymap.h" #include "split.h" +#include "util.h" + +#include "bsp/board.h" #include "pico/types.h" #include "hardware/gpio.h" #include "hardware/timer.h" -#include "util.h" #include <string.h> +#define DEBOUNCE_MS 5 + #ifdef BAD_GPIO_MITIGATION static const uint keymat_row_pins[] = { 4, 9, 6, 7 }; #else @@ -22,6 +26,8 @@ static_assert(ARRLEN(keymat_col_pins) == KEY_COLS); bool keymat_prev[KEY_ROWS][KEY_COLS]; bool keymat[KEY_ROWS][KEY_COLS]; +static uint32_t keymat_modt[KEY_ROWS_HALF][KEY_COLS]; + void keymat_init(void) { @@ -44,27 +50,37 @@ keymat_init(void) } } -void -keymat_next(void) -{ - memcpy(keymat_prev, keymat, sizeof(keymat)); -} - -void +bool keymat_scan(void) { bool (*keymat_half)[KEY_COLS]; + bool state, modified; + uint32_t now_ms; uint x, y; - keymat_half = KEYMAT_HALF(SPLIT_SIDE); + now_ms = board_millis(); + modified = false; + + memcpy(keymat_prev, keymat, sizeof(keymat)); + keymat_half = KEYMAT_HALF(keymat, SPLIT_SIDE); for (y = 0; y < KEY_ROWS_HALF; y++) { gpio_put(keymat_row_pins[y], 0); busy_wait_us(5); - for (x = 0; x < KEY_COLS; x++) - keymat_half[y][x] = !gpio_get(keymat_col_pins[x]); + for (x = 0; x < KEY_COLS; x++) { + if (keymat_modt[y][x] > now_ms - DEBOUNCE_MS) + continue; + state = !gpio_get(keymat_col_pins[x]); + if (state != keymat_half[y][x]) { + modified = true; + keymat_half[y][x] = state; + keymat_modt[y][x] = now_ms; + } + } gpio_put(keymat_row_pins[y], 1); busy_wait_us(5); } + + return modified; } uint32_t @@ -75,7 +91,7 @@ keymat_encode_half(int side) uint x, y; mask = 0; - keymat_half = KEYMAT_HALF(side); + keymat_half = KEYMAT_HALF(keymat, side); for (y = 0; y < KEY_ROWS_HALF; y++) { for (x = 0; x < KEY_COLS; x++) { if (keymat_half[y][x]) @@ -92,7 +108,7 @@ keymat_decode_half(int side, uint32_t mask) bool (*keymat_half)[KEY_COLS]; uint x, y; - keymat_half = KEYMAT_HALF(side); + keymat_half = KEYMAT_HALF(keymat, side); for (y = 0; y < KEY_ROWS_HALF; y++) { for (x = 0; x < KEY_COLS; x++) { keymat_half[y][x] = (mask >> (y * KEY_COLS + x)) & 1; diff --git a/src/keymat.h b/src/keymat.h @@ -9,13 +9,12 @@ #define KEY_COLS 6 #define KEY_COUNT (KEY_ROWS * KEY_COLS) -#define KEYMAT_HALF(side) ((side) == LEFT ? &keymat[0] : &keymat[KEY_ROWS_HALF]) +#define KEYMAT_HALF(keymat, side) ((side) == LEFT ? &(keymat)[0] : &(keymat)[KEY_ROWS_HALF]) void keymat_init(void); -void keymat_next(void); -void keymat_scan(void); +bool keymat_scan(void); uint32_t keymat_encode_half(int side); -void keymat_decode_half(int side, uint32_t); +void keymat_decode_half(int side, uint32_t mask); void keymat_debug(void); diff --git a/src/main.c b/src/main.c @@ -186,6 +186,7 @@ process_cmd(char *cmd) } else if (!strcmp(cmd, "warn")) { if (*warnlog) { printf("Warning: %s\n", warnlog); + *warnlog = '\0'; } else { printf("No warnings logged\n"); } diff --git a/src/split.c b/src/split.c @@ -4,26 +4,22 @@ #include "uart_rx.pio.h" #include "uart_tx.pio.h" -#include "hardware/regs/io_bank0.h" -#include "hardware/structs/padsbank0.h" +#include "device/usbd.h" #include "hardware/pio.h" #include "hardware/irq.h" #include "hardware/gpio.h" -#include "hardware/address_mapped.h" #include "hardware/regs/intctrl.h" -#include "hardware/regs/pads_bank0.h" -#include "hardware/uart.h" -#include "hardware/timer.h" #include "hardware/clocks.h" -#include "pico/time.h" -#include "bsp/board.h" -#include "class/cdc/cdc_device.h" -#include "tusb.h" #include <stdint.h> -#define UART_TIMEOUT 5 -#define UART_BAUD 9600 +#define UART_AWAIT_TIMEOUT_US 1000 +#define UART_RECV_TIMEOUT_US 200 +#define UART_SEND_TIMEOUT_US 200 + +#define UART_BAUD 115200 + +#define CMD_START 0x8a #if SPLIT_SIDE == LEFT #define UART_TX_PIN 0 @@ -41,23 +37,6 @@ enum { CMD_SLAVE_WARN }; -static void uart_tx_sm_init(void); -static void uart_rx_sm_init(void); -static void uart_full_init(void); - -static bool uart_await_rx(uint32_t timeout_ms); -static bool uart_await_tx(uint32_t timeout_ms); - -static uint8_t uart_rx_byte(void); -static void uart_tx_byte(uint8_t c); - -static uint uart_recv(uint8_t *data, uint len, bool nullterm); -static uint uart_send(const uint8_t *data, uint len); - -static void handle_cmd(uint8_t cmd); -static bool send_cmd(uint8_t cmd); -static void irq_rx(void); - static uint uart_tx_sm; static uint uart_tx_sm_offset; @@ -65,11 +44,19 @@ static uint uart_rx_sm; static uint uart_rx_sm_offset; static uint32_t halfmat; -static bool scan_pending = false; int split_role; -void +static void +irq_rx(void) +{ + if (pio_interrupt_get(pio0, 0)) { + DEBUG(LOG_SPLIT, "UART RX ERR"); + pio_interrupt_clear(pio0, 0); + } +} + +static void uart_tx_sm_init(void) { pio_sm_config config; @@ -89,7 +76,7 @@ uart_tx_sm_init(void) pio_sm_set_enabled(pio0, uart_tx_sm, false); } -void +static void uart_rx_sm_init(void) { pio_sm_config config; @@ -109,7 +96,7 @@ uart_rx_sm_init(void) pio_sm_set_enabled(pio0, uart_rx_sm, false); } -void +static void uart_full_init(void) { pio_gpio_init(pio0, UART_RX_PIN); @@ -139,152 +126,161 @@ uart_full_init(void) pio_sm_set_enabled(pio0, uart_tx_sm, true); } -bool -uart_await_rx(uint32_t timeout_ms) +static bool +uart_await_rx(uint64_t timeout_us) { - uint32_t start_ms; + uint64_t start_us; bool empty; - start_ms = board_millis(); + if (!pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) + return true; + + start_us = board_micros(); do { - empty = pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm); - if (!empty) break; tud_task(); - } while (board_millis() < start_ms + timeout_ms); + empty = pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm); + } while (empty && board_micros() < start_us + timeout_us); return !empty; } -bool -uart_await_tx(uint32_t timeout_ms) +static bool +uart_await_tx(uint64_t timeout_us) { - uint32_t start_ms; + uint64_t start_us; bool full; - start_ms = board_millis(); + if (!pio_sm_is_tx_fifo_full(pio0, uart_tx_sm)) + return true; + + start_us = board_micros(); do { - full = pio_sm_is_tx_fifo_full(pio0, uart_tx_sm); - if (!full) break; tud_task(); - } while (board_millis() < start_ms + timeout_ms); + full = pio_sm_is_tx_fifo_full(pio0, uart_tx_sm); + } while (full && board_micros() < start_us + timeout_us); return !full; - pio_sm_set_enabled(pio0, uart_tx_sm, true); } -uint8_t +static uint8_t uart_rx_byte(void) { return *(uint8_t*)((uintptr_t)&pio0->rxf[uart_rx_sm] + 3); } -void +static void uart_tx_byte(uint8_t c) { pio_sm_put(pio0, uart_tx_sm, c); } -uint -uart_recv(uint8_t *data, uint len, bool nullterm) +static uint +uart_recv(uint8_t *data, uint len) { uint recv; for (recv = 0; recv < len; recv++) { - if (pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) { - if (!uart_await_rx(UART_TIMEOUT)) - break; - } + if (!uart_await_rx(UART_RECV_TIMEOUT_US)) + break; *data++ = uart_rx_byte(); - if (nullterm && !*data) + } + + return recv; +} + +static uint +uart_recv_str(uint8_t *data, uint max) +{ + uint recv; + + for (recv = 0; recv < max; recv++) { + if (!uart_await_rx(UART_RECV_TIMEOUT_US)) break; + *data++ = uart_rx_byte(); + if (!*data) break; } return recv; } -uint +static uint uart_send(const uint8_t *data, uint len) { uint sent; for (sent = 0; sent < len; sent++) { - if (pio_sm_is_tx_fifo_full(pio0, uart_tx_sm)) { - if (!uart_await_tx(UART_TIMEOUT)) - break; - } + if (!uart_await_tx(UART_SEND_TIMEOUT_US)) + break; uart_tx_byte(*data++); } return sent; } -void -handle_cmd(uint8_t start) +static int +handle_cmd(void) { static uint8_t msgbuf[128]; - uint8_t cmd; + uint8_t cmd, start; + uint len; - if (start != 0xaa) - return; + start = uart_rx_byte(); + if (start != CMD_START) { + WARN(LOG_SPLIT, "Got bad start byte: %02u", start); + return -1; + } - if (!uart_recv(&cmd, 1, false)) { + if (!uart_recv(&cmd, 1)) { WARN(LOG_SPLIT, "Got start byte without command"); - return; + return -1; } switch (cmd) { case CMD_SCAN_KEYMAT_REQ: if (split_role != SLAVE) { WARN(LOG_SPLIT, "Got SCAN_KEYMAT_REQ as master"); - break; + return -1; } - scan_pending = true; break; case CMD_SCAN_KEYMAT_RESP: if (split_role != MASTER) { WARN(LOG_SPLIT, "Got SCAN_KEYMAT_RESP as slave"); - break; + return -1; } - if (uart_recv((uint8_t *) &halfmat, 4, false) != 4) + if (uart_recv((uint8_t *) &halfmat, 4) != 4) { WARN(LOG_SPLIT, "Incomplete matrix received"); - scan_pending = false; + return -1; + } break; case CMD_SLAVE_WARN: if (split_role != MASTER) { WARN(LOG_SPLIT, "Got SLAVE_WARN as slave"); - break; + return -1; } - memset(msgbuf, 0, sizeof(msgbuf)); - uart_recv(msgbuf, sizeof(msgbuf)-1, true); + len = uart_recv_str(msgbuf, sizeof(msgbuf)-1); + msgbuf[len] = '\0'; WARN(LOG_SPLIT, "SLAVE: %s\n", msgbuf); break; default: WARN(LOG_SPLIT, "Unknown uart cmd: %i", cmd); - break; + return -1; } + + return cmd; } -bool +static bool send_cmd(uint8_t cmd) { uint8_t buf[2]; - buf[0] = 0xaa; + buf[0] = CMD_START; buf[1] = cmd; return uart_send(buf, 2) == 2; } void -irq_rx(void) -{ - if (pio_interrupt_get(pio0, 0)) { - DEBUG(LOG_SPLIT, "UART RX ERR"); - pio_interrupt_clear(pio0, 0); - } -} - -void split_init(void) { uart_full_init(); @@ -295,60 +291,49 @@ split_init(void) #endif } -void -split_task(void) +static void +split_task_master(void) { - uint32_t start_ms; + int cmd; - if (split_role == MASTER) { - scan_pending = true; - if (!send_cmd(CMD_SCAN_KEYMAT_REQ)) { - WARN(LOG_SPLIT, "UART send SCAN_KEYMAT_REQ failed"); - return; - } - keymat_next(); - keymat_scan(); /* scan our side in parallel */ - start_ms = board_millis(); - while (scan_pending && board_millis() < start_ms + UART_TIMEOUT) { - if (!pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) - handle_cmd(uart_rx_byte()); - tud_task(); - } - if (scan_pending) { - WARN(LOG_SPLIT | LOG_TIMING, - "Slave matrix scan timeout (%u)", - board_millis() - start_ms); - } else { - DEBUG(LOG_SPLIT | LOG_TIMING, - "Slave matrix scan success (%u)", - board_millis() - start_ms); + keymat_scan(); + + if (uart_await_rx(UART_AWAIT_TIMEOUT_US)) { + if ((cmd = handle_cmd()) == CMD_SCAN_KEYMAT_RESP) { keymat_decode_half(SPLIT_OPP(SPLIT_SIDE), halfmat); + } else { + WARN(LOG_SPLIT, "Got unexpected command %02x", cmd); } - keymat_debug(); - scan_pending = false; - } else { - start_ms = board_millis(); - while (!scan_pending && board_millis() < start_ms + 3) { - if (!pio_sm_is_rx_fifo_empty(pio0, uart_rx_sm)) - handle_cmd(uart_rx_byte()); - tud_task(); - } - if (scan_pending) { - keymat_scan(); - DEBUG(LOG_SPLIT, "Sending SCAN_KEYMAT_RESP"); - if (!send_cmd(CMD_SCAN_KEYMAT_RESP)) { - WARN(LOG_SPLIT, - "UART send SCAN_KEYMAT_RESP failed"); - return; - } - halfmat = keymat_encode_half(SPLIT_SIDE); - uart_send((uint8_t *) &halfmat, 4); - scan_pending = false; + } + + keymat_debug(); +} + +static void +split_task_slave(void) +{ + if (keymat_scan()) { + DEBUG(LOG_SPLIT, "Sending SCAN_KEYMAT_RESP"); + halfmat = keymat_encode_half(SPLIT_SIDE); + if (!send_cmd(CMD_SCAN_KEYMAT_RESP) + || !uart_send((uint8_t *) &halfmat, 4)) { + WARN(LOG_SPLIT, + "UART send SCAN_KEYMAT_RESP failed"); } } } void +split_task(void) +{ + if (split_role == MASTER) { + split_task_master(); + } else { + split_task_slave(); + } +} + +void split_warn_master(const char *msg) { uint32_t len; diff --git a/src/util.c b/src/util.c @@ -52,7 +52,7 @@ stdio_log(int facility, int level, const char *fmtstr, ...) if (level < log_level_min) return; - if (level == LOG_WARN) { + if (level == LOG_WARN && !*warnlog) { led_start_blip(HARD_RED, 100); va_copy(cpy, ap); va_start(cpy, fmtstr); diff --git a/src/util.h b/src/util.h @@ -3,6 +3,8 @@ #include "ws2812.h" #include "led.h" +#include "pico/time.h" + #include <stdbool.h> #include <stdint.h> #include <stdarg.h> @@ -49,6 +51,12 @@ claim_unused_sm(PIO pio) return (uint) tmp; } +static inline uint64_t +board_micros(void) +{ + return to_us_since_boot(get_absolute_time()); +} + extern char warnlog[]; extern int log_level_min; extern int log_group_mask;