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:
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;