164 lines
4.9 KiB
C
164 lines
4.9 KiB
C
|
// Copyright 2023 sekigon-gonnoc
|
||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
|
||
|
#include QMK_KEYBOARD_H
|
||
|
|
||
|
#include "print.h"
|
||
|
#include "tusb.h"
|
||
|
#include "pio_usb_ll.h"
|
||
|
|
||
|
static uint8_t kbd_addr;
|
||
|
static uint8_t kbd_instance;
|
||
|
static int32_t led_count = -1;
|
||
|
static uint8_t hid_report_buffer[64];
|
||
|
static volatile uint8_t hid_report_size;
|
||
|
static uint8_t hid_instance;
|
||
|
static bool hid_disconnect_flag;
|
||
|
static uint8_t pre_keyreport[8];
|
||
|
#define LED_BLINK_TIME_MS 50
|
||
|
#define KQ_PIN_LED 7
|
||
|
#define MATRIX_MODIFIER_ROW 21
|
||
|
|
||
|
extern void busy_wait_us(uint64_t delay_us);
|
||
|
static bool send_led_report(uint8_t* leds);
|
||
|
|
||
|
void matrix_init_custom(void) {
|
||
|
// Configure LED pin
|
||
|
setPinOutput(KQ_PIN_LED);
|
||
|
writePinHigh(KQ_PIN_LED);
|
||
|
}
|
||
|
|
||
|
bool matrix_scan_custom(matrix_row_t current_matrix[]) {
|
||
|
bool matrix_has_changed = false;
|
||
|
|
||
|
// If keyboard is disconnected, clear matrix
|
||
|
if (hid_disconnect_flag) {
|
||
|
for (uint8_t rowIdx = 0; rowIdx < MATRIX_ROWS; rowIdx++) {
|
||
|
if (current_matrix[rowIdx] != 0) {
|
||
|
matrix_has_changed = true;
|
||
|
current_matrix[rowIdx] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hid_disconnect_flag = false;
|
||
|
|
||
|
return matrix_has_changed;
|
||
|
}
|
||
|
|
||
|
// If keyboard report is received, apply it to matrix
|
||
|
if (hid_report_size > 0) {
|
||
|
hid_report_size = 0;
|
||
|
dprintf("%02x %02x %02x %02x %02x %02x %02x %02x\n", hid_report_buffer[0], hid_report_buffer[1], hid_report_buffer[2], hid_report_buffer[3], hid_report_buffer[4], hid_report_buffer[5], hid_report_buffer[6], hid_report_buffer[7]);
|
||
|
if (memcmp(pre_keyreport, hid_report_buffer, 8) == 0) {
|
||
|
// no change
|
||
|
matrix_has_changed = false;
|
||
|
|
||
|
return matrix_has_changed;
|
||
|
} else {
|
||
|
matrix_has_changed = true;
|
||
|
memcpy(pre_keyreport, hid_report_buffer, 8);
|
||
|
}
|
||
|
|
||
|
// clear all bit
|
||
|
for (uint8_t rowIdx = 0; rowIdx < MATRIX_ROWS; rowIdx++) {
|
||
|
current_matrix[rowIdx] = 0;
|
||
|
}
|
||
|
|
||
|
// set bits
|
||
|
for (uint8_t keyIdx = 0; keyIdx < 6; keyIdx++) {
|
||
|
uint8_t key = hid_report_buffer[keyIdx + 2];
|
||
|
uint8_t rowIdx = key / (sizeof(uint8_t) * 8);
|
||
|
uint8_t colIdx = key - rowIdx * (sizeof(uint8_t) * 8);
|
||
|
current_matrix[rowIdx] |= (1 << colIdx);
|
||
|
}
|
||
|
|
||
|
// modifier bits
|
||
|
current_matrix[MATRIX_MODIFIER_ROW] = hid_report_buffer[0];
|
||
|
return matrix_has_changed;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return matrix_has_changed;
|
||
|
}
|
||
|
|
||
|
void housekeeping_task_kb(void) {
|
||
|
// Control keyboard indicator LED
|
||
|
static uint8_t keyboard_led;
|
||
|
if (keyboard_led != host_keyboard_leds()) {
|
||
|
uint8_t led_backup = keyboard_led;
|
||
|
keyboard_led = host_keyboard_leds();
|
||
|
if (!send_led_report(&keyboard_led)) {
|
||
|
keyboard_led = led_backup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Blink LED when USB reports are received
|
||
|
if (led_count >= 0) {
|
||
|
if (timer_elapsed(led_count) < LED_BLINK_TIME_MS) {
|
||
|
writePinLow(KQ_PIN_LED);
|
||
|
} else if (timer_elapsed(led_count) < 2 * LED_BLINK_TIME_MS) {
|
||
|
writePinHigh(KQ_PIN_LED);
|
||
|
} else {
|
||
|
led_count = -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool send_led_report(uint8_t* leds) {
|
||
|
if (kbd_addr != 0) {
|
||
|
return tuh_hid_set_report(kbd_addr, kbd_instance, 0, HID_REPORT_TYPE_OUTPUT, leds, sizeof(*leds));
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) {
|
||
|
dprintf("HID mounted:%d:%d\n", dev_addr, instance);
|
||
|
|
||
|
if (led_count < 0) {
|
||
|
led_count = timer_read();
|
||
|
}
|
||
|
|
||
|
for (int instance = 0; instance < tuh_hid_instance_count(dev_addr); instance++) {
|
||
|
tuh_hid_receive_report(dev_addr, instance);
|
||
|
|
||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||
|
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
|
||
|
kbd_addr = dev_addr;
|
||
|
kbd_instance = instance;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||
|
dprintf("HID unmounted:%d:%d\n", dev_addr, instance);
|
||
|
memset(pre_keyreport, 0, sizeof(pre_keyreport));
|
||
|
hid_disconnect_flag = true;
|
||
|
kbd_addr = 0;
|
||
|
kbd_instance = 0;
|
||
|
}
|
||
|
|
||
|
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
|
||
|
dprintf("Report received\n");
|
||
|
if (led_count < 0) {
|
||
|
led_count = timer_read();
|
||
|
}
|
||
|
|
||
|
if (len > 0 && instance == kbd_instance) {
|
||
|
int cnt = 0;
|
||
|
while (hid_report_size > 0 && cnt++ < 50000) {
|
||
|
busy_wait_us(1);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
hid_instance = instance;
|
||
|
memcpy(hid_report_buffer, report, len);
|
||
|
__DSB();
|
||
|
// hid_report_size is used as trigger of report parser
|
||
|
hid_report_size = len;
|
||
|
}
|
||
|
|
||
|
tuh_hid_receive_report(dev_addr, instance);
|
||
|
}
|