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 8e8c972cbec56d8de31847981149cde4a8fc16cd
parent cbb0ac4dac395ea287cf5e7cc211f81aef16e78f
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri, 16 Dec 2022 20:31:06 +0100

Add stdio command interface, matrix syncing and basic evaluation

Diffstat:
Msrc/hid.c | 37+++++++++++++++++++++++++++++++++++++
Msrc/hid.h | 4++++
Msrc/keymap.c | 15++++++++-------
Msrc/main.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/matrix.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/matrix.h | 9++++++---
Msrc/split.c | 12++++++------
Msrc/split.h | 8++++++++
Msrc/usb_stdio.c | 3+++
Msrc/util.c | 13+++++++------
10 files changed, 207 insertions(+), 58 deletions(-)

diff --git a/src/hid.c b/src/hid.c @@ -1,4 +1,10 @@ #include "hid.h" +#include "split.h" +#include "matrix.h" +#include "keysym.h" +#include "keymap.h" + +#include <pico/types.h> void hid_init(void) @@ -6,6 +12,37 @@ hid_init(void) } +inline uint +layer_index(uint x, uint y) +{ + if (y < KEY_ROWS) + return y * KEY_COLS + x; + else + return y * KEY_COLS + (KEY_COLS - 1 - x); +} + +bool +hid_gen_report(uint8_t *report) +{ + int keycnt; + uint x, y, p; + + keycnt = 0; + for (y = 0; y < KEY_ROWS * 2; y++) { + for (x = 0; x < KEY_COLS; x++) { + if (!state_matrix[y * KEY_COLS + x]) + continue; + if (keycnt >= 6) break; + DEBUG("PRESS %i %", x, y); + p = layer_index(x, y); + report[keycnt] = TO_CODE(keymap_layers_de[0][p]); + keycnt++; + } + } + + return keycnt > 0; +} + void hid_task(void) { diff --git a/src/hid.h b/src/hid.h @@ -1,4 +1,8 @@ #pragma once +#include <stdbool.h> +#include <stdint.h> + void hid_init(void); +bool hid_gen_report(uint8_t *keycode); void hid_task(void); diff --git a/src/keymap.c b/src/keymap.c @@ -1,4 +1,5 @@ #include "keymap.h" +#include "keycode.h" #include "keysym_de.h" #include "board.h" #include "util.h" @@ -19,8 +20,8 @@ 0x0, 0x0, 0x0, K44, K45, K46, \ K51, K52, K53, K54, K55, K56, \ K61, K62, K63, K64, K65, K66, \ - K31, K32, K33, K34, K35, K36, \ - K31, K32, K33, 0x0, 0x0, 0x0, \ + K71, K72, K73, K74, K75, K76, \ + K81, K82, K83, 0x0, 0x0, 0x0, \ } enum { @@ -31,12 +32,12 @@ static const uint32_t layer_base_de[] = KEYMAP( _______, DE_Q , DE_W , DE_F , DE_P , DE_B , _______, DE_A , DE_R , DE_S , DE_T , DE_G , _______, DE_Z , DE_X , DE_C , DE_D , DE_V , - KC_LALT, KC_LGUI, _______, + KC_LGUI, KC_LALT, _______, - _______, DE_J , DE_L , DE_U , DE_Y , _______, - _______, DE_N , DE_E , DE_I , DE_O , _______, - _______, DE_H , DE_SCLN, DE_DOT , DE_MINS, _______, - _______, _______, _______ + DE_J , DE_L , DE_U , DE_Y , DE_QUOT, _______, + DE_M , DE_N , DE_E , DE_I , DE_O , _______, + DE_K , DE_H , DE_COMM, DE_DOT , DE_MINS, _______, + _______, KC_SPC , KC_LCTL ); const uint32_t *keymap_layers_de[] = { diff --git a/src/main.c b/src/main.c @@ -1,6 +1,7 @@ #include "board.h" #include "usb_stdio.h" #include "matrix.h" +#include "keysym.h" #include "split.h" #include "led.h" #include "hid.h" @@ -21,9 +22,9 @@ #include <stdio.h> #include <string.h> -bool send_hid_report(int id, bool state); +bool send_hid_report(int id); +void cdc_task(void); -static bool hit_state = false; const uint32_t **keymap_layers = keymap_layers_de; int @@ -39,9 +40,11 @@ main(void) while (true) { tud_task(); + cdc_task(); led_task(); split_task(); //hid_task(); + send_hid_report(REPORT_ID_MIN); } return 0; @@ -88,7 +91,6 @@ tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) void tud_cdc_rx_cb(uint8_t itf) { - printf("ALIVE\n\r"); } uint16_t @@ -111,20 +113,22 @@ tud_hid_report_complete_cb(uint8_t instance, uint8_t id; for (id = report[0] + 1; id < REPORT_ID_MAX; id++) { - if (send_hid_report(id, hit_state)) + if (send_hid_report(id)) break; } } bool -send_keyboard_report(bool state) +send_keyboard_report(void) { static bool cleared = true; - uint8_t keycode[6] = { 0 }; + uint8_t report[6] = { 0 }; + bool any; - if (state) { - keycode[0] = HID_KEY_A; - tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); + any = hid_gen_report(report); + + if (any) { + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, report); cleared = false; return true; } else if (!cleared) { @@ -169,30 +173,85 @@ send_consumer_control_report(bool state) } bool -send_hid_report(int id, bool state) +send_hid_report(int id) { + if (!tud_hid_ready()) return false; + switch (id) { case REPORT_ID_KEYBOARD: - return send_keyboard_report(state); + return send_keyboard_report(); case REPORT_ID_MOUSE: - return send_mouse_report(state); + return send_mouse_report(false); case REPORT_ID_CONSUMER_CONTROL: - return send_consumer_control_report(state); + return send_consumer_control_report(false); } return false; } void -send_hid_report_timed(void) +process_cmd(char *cmd) { - const uint32_t period_ms = 1000; - static uint32_t start_ms = 0; + char *arg, *tok; + + tok = strchr(cmd, ' '); + if (tok) { + *tok = '\0'; + arg = tok + 1; + } else { + arg = cmd + strlen(cmd); + } - if (!tud_hid_ready()) return; + if (!strcmp(cmd, "log")) { + if (!strcmp(arg, "")) { + printf("Levels: debug, info, warn, err\n"); + } else if (!strcmp(arg, "debug")) { + loglevel = LOG_DEBUG; + } else if (!strcmp(arg, "info")) { + loglevel = LOG_INFO; + } else if (!strcmp(arg, "warn")) { + loglevel = LOG_WARN; + } else if (!strcmp(arg, "warn")) { + loglevel = LOG_ERR; + } else { + printf("Invalid log level: %s\n", arg); + } + } else { + printf("Invalid command: %s\n", cmd); + } +} + +void +cdc_task(void) +{ + static char cmdbuf[256]; + static int cmdlen = 0; + char c; - hit_state = (board_millis() - start_ms < period_ms); - if (hit_state) start_ms += period_ms; + do { + if (cmdlen) + tud_task(); - send_hid_report(REPORT_ID_MIN, hit_state); + if (tud_cdc_connected() && tud_cdc_available() + && tud_cdc_read(&c, 1)) { + if (c == '\r' || c == '\n') { + printf("\n"); + tud_cdc_write_flush(); + if (cmdlen) { + cmdbuf[cmdlen] = 0; + process_cmd(cmdbuf); + cmdlen = 0; + } + } else if (c == 4) { + printf("ALIVE!\n"); + } else if (cmdlen == ARRLEN(cmdbuf)) { + printf("\n--- cmd too long ---\n"); + cmdlen = 0; + } else { + printf("%c", c); + tud_cdc_write_flush(); + cmdbuf[cmdlen++] = c; + } + } + } while (cmdlen); } diff --git a/src/matrix.c b/src/matrix.c @@ -1,6 +1,7 @@ #include "keymap.h" #include "matrix.h" +#include "split.h" #include "pico/types.h" #include "hardware/gpio.h" #include "hardware/timer.h" @@ -12,23 +13,23 @@ 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]; +bool prev_state_matrix[KEY_COUNT * 2]; +bool state_matrix[KEY_COUNT * 2]; 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); + gpio_set_dir(matrix_col_pins[x], GPIO_IN); + gpio_pull_up(matrix_col_pins[x]); + } + + for (y = 0; y < KEY_ROWS; y++) { + gpio_init(matrix_row_pins[y]); + gpio_set_dir(matrix_row_pins[y], GPIO_OUT); } } @@ -36,18 +37,50 @@ void scan_matrix(void) { bool pressed; - uint x, y; + uint x, y, p; memcpy(prev_state_matrix, state_matrix, sizeof(state_matrix)); for (y = 0; y < KEY_ROWS; y++) { + gpio_put(matrix_row_pins[y], 0); + busy_wait_us(5); + for (x = 0; x < KEY_COLS; x++) { + pressed = !gpio_get(matrix_col_pins[x]); + p = MAT_OFFSET(SPLIT_SIDE) + y * KEY_COLS + x; + state_matrix[p] = pressed; + } + gpio_put(matrix_row_pins[y], 1); + busy_wait_us(5); + } +} + +uint32_t +matrix_encode_half(int side) +{ + uint32_t mask; + uint x, y, p; + + mask = 0; + for (y = 0; y < KEY_ROWS; y++) { + for (x = 0; x < KEY_COLS; x++) { + p = MAT_OFFSET(side) + y * KEY_COLS + x; + if (state_matrix[p]) + mask |= 1 << (y * KEY_COLS + x); + } + } + + return mask; +} + +void +matrix_decode_half(int side, uint32_t mask) +{ + uint x, y, p; + + 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); + p = MAT_OFFSET(side) + y * KEY_COLS + x; + state_matrix[p] = (mask >> (y * KEY_COLS + x)) & 1; } } } diff --git a/src/matrix.h b/src/matrix.h @@ -8,10 +8,13 @@ #define KEY_COLS 6 #define KEY_COUNT (KEY_ROWS * KEY_COLS) +#define MAT_OFFSET(side) ((side) == LEFT ? 0 : KEY_COUNT) + void matrix_init(void); void scan_matrix(void); +uint32_t matrix_encode_half(int side); +void matrix_decode_half(int side, uint32_t); -extern bool prev_state_matrix[KEY_COUNT]; -extern bool state_matrix[KEY_COUNT]; -extern uint32_t sym_matrix[KEY_COUNT]; +extern bool prev_state_matrix[KEY_COUNT * 2]; +extern bool state_matrix[KEY_COUNT * 2]; diff --git a/src/split.c b/src/split.c @@ -26,12 +26,6 @@ #define UART_TIMEOUT 20 #define UART_BAUD 9600 -#define LEFT 0 -#define RIGHT 1 - -#define SLAVE 0 -#define MASTER 1 - #if SPLIT_SIDE == LEFT #define UART_TX_PIN 0 #define UART_RX_PIN 1 @@ -68,6 +62,7 @@ static uint uart_tx_sm_offset; static uint uart_rx_sm; static uint uart_rx_sm_offset; +static uint32_t halfmat; static bool scan_pending = false; void @@ -237,6 +232,8 @@ handle_cmd(uint8_t cmd) WARN("Got SCAN_MATRIX_RESP as slave"); break; } + if (uart_recv((uint8_t *) &halfmat, 4) != 4) + WARN("Incomplete matrix received"); scan_pending = false; return; case CMD_STDIO_PUTS: @@ -295,6 +292,7 @@ split_task(void) WARN("Slave matrix scan timeout"); } else { DEBUG("Slave matrix scan success"); + matrix_decode_half(SPLIT_OPP(SPLIT_SIDE), halfmat); } scan_pending = false; } else { @@ -309,6 +307,8 @@ split_task(void) cmd = CMD_SCAN_MATRIX_RESP; DEBUG("Sending SCAN_MATRIX_RESP %i", cmd); ASSERT(uart_send(&cmd, 1) == 1); + halfmat = matrix_encode_half(SPLIT_SIDE); + ASSERT(uart_send((uint8_t *) &halfmat, 4) == 4); scan_pending = false; } } diff --git a/src/split.h b/src/split.h @@ -1,4 +1,12 @@ #pragma once +#define LEFT 0 +#define RIGHT 1 + +#define SLAVE 0 +#define MASTER 1 + +#define SPLIT_OPP(x) ((x) == LEFT ? RIGHT : LEFT) + void split_init(void); void split_task(void); diff --git a/src/usb_stdio.c b/src/usb_stdio.c @@ -1,5 +1,6 @@ #include "usb_stdio.h" +#include "pico/stdio.h" #include "pico/stdio/driver.h" #include "tusb.h" @@ -24,6 +25,7 @@ void usb_stdio_flush(void) { tud_cdc_write_flush(); + tud_task(); } int @@ -36,5 +38,6 @@ void usb_stdio_init(void) { stdio_set_driver_enabled(&usb_stdio, true); + stdio_set_translate_crlf(&usb_stdio, true); stdio_init_all(); } diff --git a/src/util.c b/src/util.c @@ -1,5 +1,6 @@ #include "util.h" #include "board.h" +#include "class/cdc/cdc_device.h" #include "led.h" #include "ws2812.h" @@ -19,7 +20,7 @@ panic_task(const char *fmtstr, va_list ap, uint32_t sleep_ms) static uint32_t start_ms = 0; va_list cpy; - if (!tud_cdc_available()) + if (!tud_cdc_connected()) return; if (!start_ms) start_ms = board_millis(); @@ -29,8 +30,8 @@ panic_task(const char *fmtstr, va_list ap, uint32_t sleep_ms) va_copy(cpy, ap); vprintf(fmtstr, cpy); - printf("\n\r"); - stdio_flush(); + printf("\n"); + tud_cdc_write_flush(); start_ms += sleep_ms; } @@ -41,7 +42,7 @@ stdio_log(int level, const char *fmtstr, ...) { va_list ap; - if (!tud_cdc_available()) + if (!tud_cdc_connected()) return; if (level > loglevel) @@ -50,8 +51,8 @@ stdio_log(int level, const char *fmtstr, ...) va_start(ap, fmtstr); vprintf(fmtstr, ap); va_end(ap); - printf("\n\r"); - stdio_flush(); + printf("\n"); + tud_cdc_write_flush(); } void