diff --git a/config.h b/config.h index 5bafe1a..8aa63bc 100644 --- a/config.h +++ b/config.h @@ -1,4 +1,4 @@ -// Copyright 2025 EPOMAKER (@Epomaker) +// Copyright 2025 EPOMAKER (@Epomaker) // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -54,9 +54,11 @@ #define HS_RGB_BLINK_INDEX_MAC 14 /* UART */ -#define SERIAL_DRIVER SD3 -#define SD1_TX_PIN C10 -#define SD1_RX_PIN C11 +#define UART_DRIVER SD3 +#define UART_TX_PIN C10 +#define UART_RX_PIN C11 +#define UART_TX_PAL_MODE 7 +#define UART_RX_PAL_MODE 7 #define SERIAL_USART_DRIVER SD1 #define SERIAL_USART_TX_PIN A9 @@ -80,7 +82,7 @@ /* Flash */ #define EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN C12 -#define WEAR_LEVELING_BACKING_SIZE (8 * 1024) +#define WEAR_LEVELING_BACKING_SIZE (8 * 1024) #define WEAR_LEVELING_LOGICAL_SIZE (WEAR_LEVELING_BACKING_SIZE / 2) #define FEE_PAGE_COUNT (WEAR_LEVELING_BACKING_SIZE / FEE_PAGE_SIZE) @@ -91,6 +93,7 @@ /* WS2812 */ #define WS2812_SPI_DRIVER SPIDM2 #define WS2812_SPI_DIVISOR 32 +#define WS2812_BYTE_ORDER WS2812_BYTE_ORDER_RGB /* rgb_record */ #define ENABLE_RGB_MATRIX_RGBR_PLAY @@ -98,5 +101,5 @@ #define EECONFIG_CONFINFO_USE_SIZE (4 + 16) #define EECONFIG_RGBREC_USE_SIZE (RGBREC_CHANNEL_NUM * MATRIX_ROWS * MATRIX_COLS * 2) #define EECONFIG_USER_DATA_SIZE (EECONFIG_RGBREC_USE_SIZE + EECONFIG_CONFINFO_USE_SIZE) -#define RGBREC_EECONFIG_ADDR (uint8_t *)(EECONFIG_USER_DATABLOCK) -#define CONFINFO_EECONFIG_ADDR (uint32_t *)((uint32_t)RGBREC_EECONFIG_ADDR + (uint32_t)EECONFIG_RGBREC_USE_SIZE) +#define RGBREC_EECONFIG_OFFSET 0 +#define CONFINFO_EECONFIG_OFFSET (RGBREC_EECONFIG_OFFSET + (uint32_t)EECONFIG_RGBREC_USE_SIZE) diff --git a/howto.jpg b/howto.jpg new file mode 100644 index 0000000..060e9e4 Binary files /dev/null and b/howto.jpg differ diff --git a/keyboard.json b/keyboard.json index 5ba4f2e..d2abc44 100644 --- a/keyboard.json +++ b/keyboard.json @@ -4,7 +4,8 @@ "maintainer": "EPOMAKER", "bootloader": "wb32-dfu", "bootmagic": { - "matrix": [0, 0] + "enabled": true, + "matrix": [1, 0] }, "debounce": 1, "diode_direction": "ROW2COL", @@ -231,6 +232,9 @@ }, "handedness": { "pin": "B9" + }, + "bootmagic": { + "matrix": [11, 8] } }, "tap_keycode_delay": 10, diff --git a/keymap.c b/keymaps/default/keymap.c similarity index 100% rename from keymap.c rename to keymaps/default/keymap.c diff --git a/keymaps/via/keymap.c b/keymaps/via/keymap.c new file mode 100644 index 0000000..e24194a --- /dev/null +++ b/keymaps/via/keymap.c @@ -0,0 +1,63 @@ +// Copyright 2025 EPOMAKER (@Epomaker) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H +#include "rgb_record/rgb_record.h" + +enum layers { + _BL = 0, + _FL, + _MBL, + _MFL, +}; + +#define ______ HS_BLACK + +// clang-format off +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + + [_BL] = LAYOUT( /* Base */ + QK_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_MUTE, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN, + KC_LCTL, KC_LCMD, KC_LALT, KC_SPC, KC_SPC, KC_RALT, MO(_FL), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [_FL] = LAYOUT( /* Base */ + KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, EE_CLR, KC_MUTE, + RGB_MOD, KC_BT1, KC_BT2, KC_BT3, KC_2G4, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, RGB_HUD, RGB_HUI, KC_BSLS, KC_INS, + KC_CAPS, KC_A, TO(_MBL), KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, RGB_SAD, RGB_SAI, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, RGB_TOG, KC_C, KC_V, HS_BATQ, NK_TOGG, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, RGB_VAI, KC_END, + KC_FILP, GU_TOGG, KC_LALT, KC_BATQ, KC_SPC, KC_RALT, KC_NO, KC_RCTL, RGB_SPD, RGB_VAD, RGB_SPI), + + [_MBL] = LAYOUT( /* Base */ + QK_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_MUTE, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN, + KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_SPC, KC_RGUI, MO(_MFL), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + [_MFL] = LAYOUT( /* Base */ + KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, EE_CLR, KC_MUTE, + RGB_MOD, KC_BT1, KC_BT2, KC_BT3, KC_2G4, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, RGB_HUD, RGB_HUI, KC_BSLS, KC_INS, + KC_CAPS, TO(_BL), KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, RGB_SAD, RGB_SAI, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, RGB_TOG, KC_C, KC_V, HS_BATQ, NK_TOGG, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, RGB_VAI, KC_END, + KC_FILP, KC_LALT, KC_LGUI, KC_BATQ, KC_SPC, KC_RGUI, KC_RALT, KC_RCTL, RGB_SPD, RGB_VAD, RGB_SPI), + +}; + + +#ifdef ENCODER_MAP_ENABLE +const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = { + [0] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)}, + [1] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)}, + [2] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)}, + [3] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)}, +}; +#endif +// clang-format on + +bool is_keyboard_master(void) { + setPinInput(SPLIT_HAND_PIN); + return readPin(SPLIT_HAND_PIN); +} + diff --git a/keymaps/via/rules.mk b/keymaps/via/rules.mk new file mode 100644 index 0000000..f1adcab --- /dev/null +++ b/keymaps/via/rules.mk @@ -0,0 +1,2 @@ +VIA_ENABLE = yes +ENCODER_MAP_ENABLE = yes diff --git a/linker/wireless/lowpower.c b/linker/wireless/lowpower.c new file mode 100644 index 0000000..7df6a31 --- /dev/null +++ b/linker/wireless/lowpower.c @@ -0,0 +1,326 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "wireless.h" +#include "usb_main.h" + +#ifndef LPWR_TIMEOUT +# define LPWR_TIMEOUT 300000 // 5min +#endif + +#ifndef LPWR_PRESLEEP_DELAY +# define LPWR_PRESLEEP_DELAY 200 +#endif + +#ifndef LPWR_STOP_DELAY +# define LPWR_STOP_DELAY 200 +#endif + +#ifndef LPWR_WAKEUP_DELAY +# define LPWR_WAKEUP_DELAY 200 +#endif + +static lpwr_state_t lpwr_state = LPWR_NORMAL; +static lpwr_mode_t lpwr_mode = LPWR_MODE_TIMEOUT; +static uint32_t lpwr_timeout_value = LPWR_TIMEOUT; +static uint32_t lpwr_timestamp = 0x00; +static lpwr_wakeupcd_t lpwr_wakeupcd = LPWR_WAKEUP_NONE; +static bool manual_timeout = false; + +static bool rgb_enable_bak = false; + +void last_matrix_activity_trigger(void); + +void lpwr_clock_enable(void); +void lpwr_enter_stop(void); +void lpwr_exti_init(void); +void mcu_stop_mode(void); + +extern void matrix_init_pins(void); + +lpwr_state_t lpwr_get_state(void) { + return lpwr_state; +} + +void lpwr_set_state(lpwr_state_t state) { + lpwr_state = state; +} + +lpwr_mode_t lpwr_get_mode(void) { + return lpwr_mode; +} + +void lpwr_set_mode(lpwr_mode_t mode) { + lpwr_mode = mode; +} + +void lpwr_set_timeout_value(uint32_t timeout) { + lpwr_timeout_value = timeout; +} + +uint32_t lpwr_timeout_value_read(void) { + return lpwr_timeout_value; +} + +void lpwr_update_timestamp(void) { + lpwr_timestamp = sync_timer_read32(); +} + +uint32_t lpwr_timestamp_read(void) { + return lpwr_timestamp; +} + +void lpwr_set_sleep_wakeupcd(lpwr_wakeupcd_t wakeupcd) { + lpwr_wakeupcd = wakeupcd; +} + +lpwr_wakeupcd_t lpwr_get_sleep_wakeupcd(void) { + return lpwr_wakeupcd; +} + +void lpwr_clock_enable(void) __attribute__((weak)); +void lpwr_clock_enable(void) {} + +void lpwr_exti_init(void) __attribute__((weak)); +void lpwr_exti_init(void) {} + +void mcu_stop_mode(void) __attribute__((weak)); +void mcu_stop_mode(void) {} + +void lpwr_enter_stop(void) { + chSysLock(); + lpwr_exti_init(); + chSysUnlock(); + + chSysDisable(); + mcu_stop_mode(); + lpwr_clock_enable(); + matrix_init_pins(); + chSysEnable(); +} + +void lpwr_set_timeout_manual(bool enable) { + manual_timeout = enable; +} + +bool lpwr_get_timeout_manual(void) { + return manual_timeout; +} + +// 2.4g mode, host state +void md_receive_host_cb(bool resume) { + + if (resume) { + if (lpwr_get_state() != LPWR_NORMAL) { + lpwr_update_timestamp(); + lpwr_set_state(LPWR_WAKEUP); + } + } else { + if (lpwr_get_state() == LPWR_NORMAL) { + manual_timeout = true; + } + } +} + +bool lpwr_is_allow_timeout_hook(void) __attribute__((weak)); +bool lpwr_is_allow_timeout_hook(void) { + return true; +} + +bool lpwr_is_allow_timeout(void) __attribute__((weak)); +bool lpwr_is_allow_timeout(void) { + uint32_t timeout = lpwr_timeout_value_read(); + + if (lpwr_is_allow_timeout_hook() != true) { + manual_timeout = false; + return false; + } + + if ((wireless_get_current_devs() == DEVS_USB) && (USB_DRIVER.state == USB_ACTIVE)) { + manual_timeout = false; + return false; + } + + if (manual_timeout || (timeout && (last_input_activity_elapsed() >= timeout))) { + manual_timeout = false; + return true; + } + + return false; +} + +bool lpwr_is_allow_presleep_hook(void) __attribute__((weak)); +bool lpwr_is_allow_presleep_hook(void) { + extern bool charging_state; + if ((wireless_get_current_devs() == DEVS_USB) && (!charging_state)) { + + if (USB_DRIVER.state != USB_STOP) { + usb_power_disconnect(); + usbDisconnectBus(&USBD1); + usbStop(&USBD1); + } + } + return true; +} + +bool lpwr_is_allow_presleep(void) __attribute__((weak)); +bool lpwr_is_allow_presleep(void) { + uint32_t delay = LPWR_PRESLEEP_DELAY; + + if (lpwr_is_allow_presleep_hook() != true) { + return false; + } + + if (!delay || (sync_timer_elapsed32(lpwr_timestamp_read()) >= delay)) { + return true; + } + + return false; +} + +bool lpwr_is_allow_stop_hook(void) __attribute__((weak)); +bool lpwr_is_allow_stop_hook(void) { + return true; +} + +bool lpwr_is_allow_stop(void) __attribute__((weak)); +bool lpwr_is_allow_stop(void) { + uint32_t delay = LPWR_STOP_DELAY; + + if (lpwr_is_allow_stop_hook() != true) { + return false; + } + + if (!delay || (sync_timer_elapsed32(lpwr_timestamp_read()) >= delay)) { + return true; + } + + return false; +} + +bool lpwr_is_allow_wakeup_hook(void) __attribute__((weak)); +bool lpwr_is_allow_wakeup_hook(void) { + if (wireless_get_current_devs() == DEVS_USB && USB_DRIVER.state == USB_STOP) + { + usb_power_connect(); + restart_usb_driver(&USBD1); + wireless_devs_change(!DEVS_USB, DEVS_USB, false); + } + return true; +} + +bool lpwr_is_allow_wakeup(void) __attribute__((weak)); +bool lpwr_is_allow_wakeup(void) { + uint32_t delay = LPWR_WAKEUP_DELAY; + + if (lpwr_is_allow_wakeup_hook() != true) { + return false; + } + + if (!delay || (sync_timer_elapsed32(lpwr_timestamp_read()) >= delay)) { + return true; + } + + return false; +} + +void lpwr_presleep_hook(void) __attribute__((weak)); +void lpwr_presleep_hook(void) {} + +void lpwr_presleep_cb(void) __attribute__((weak)); +void lpwr_presleep_cb(void) { + +#if defined(RGB_MATRIX_ENABLE) + rgb_enable_bak = rgb_matrix_is_enabled(); + rgb_matrix_disable_noeeprom(); +#elif defined(RGBLIGHT_ENABLE) + rgb_enable_bak = rgblight_is_enabled(); + rgblight_disable_noeeprom(); +#else + rgb_enable_bak = false; +#endif + suspend_power_down(); + lpwr_presleep_hook(); +} + +void lpwr_stop_hook_pre(void) __attribute__((weak)); +void lpwr_stop_hook_pre(void) {} + +void lpwr_stop_hook_post(void) __attribute__((weak)); +void lpwr_stop_hook_post(void) {} + +void lpwr_stop_cb(void) __attribute__((weak)); +void lpwr_stop_cb(void) { + + lpwr_set_sleep_wakeupcd(LPWR_WAKEUP_NONE); + + lpwr_stop_hook_pre(); + lpwr_enter_stop(); + + switch (lpwr_get_sleep_wakeupcd()) { + case LPWR_WAKEUP_UART: { + lpwr_set_state(LPWR_STOP); + } break; + default: { + lpwr_set_state(LPWR_WAKEUP); + } break; + } + + lpwr_stop_hook_post(); +} + +void lpwr_wakeup_hook(void) __attribute__((weak)); +void lpwr_wakeup_hook(void) {} + +void lpwr_wakeup_cb(void) __attribute__((weak)); +void lpwr_wakeup_cb(void) { + + if (rgb_enable_bak) { +#if defined(RGB_MATRIX_ENABLE) + rgb_matrix_enable_noeeprom(); +#elif defined(RGBLIGHT_ENABLE) + rgblight_enable_noeeprom(); +#endif + } + + suspend_wakeup_init(); + lpwr_wakeup_hook(); + + last_matrix_activity_trigger(); +} + +void lpwr_task(void) __attribute__((weak)); +void lpwr_task(void) { + + switch (lpwr_get_state()) { + case LPWR_NORMAL: { + if (lpwr_is_allow_timeout()) { + lpwr_update_timestamp(); + lpwr_set_state(LPWR_PRESLEEP); + } + } break; + case LPWR_PRESLEEP: { + if (lpwr_is_allow_presleep()) { + lpwr_presleep_cb(); + lpwr_update_timestamp(); + lpwr_set_state(LPWR_STOP); + } + } break; + case LPWR_STOP: { + if (lpwr_is_allow_stop()) { + lpwr_update_timestamp(); + lpwr_stop_cb(); + } + } break; + case LPWR_WAKEUP: { + if (lpwr_is_allow_wakeup()) { + lpwr_wakeup_cb(); + lpwr_update_timestamp(); + lpwr_set_state(LPWR_NORMAL); + } + } break; + default: + break; + } +} diff --git a/linker/wireless/lowpower.h b/linker/wireless/lowpower.h new file mode 100644 index 0000000..e7d60a4 --- /dev/null +++ b/linker/wireless/lowpower.h @@ -0,0 +1,39 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +typedef enum { + LPWR_NORMAL = 0, + LPWR_PRESLEEP, + LPWR_STOP, + LPWR_WAKEUP, +} lpwr_state_t; + +typedef enum { + LPWR_WAKEUP_NONE = 0, + LPWR_WAKEUP_MATRIX, + LPWR_WAKEUP_UART, + LPWR_WAKEUP_CABLE, + LPWR_WAKEUP_USB, + LPWR_WAKEUP_ONEKEY, + LPWR_WAKEUP_ENCODER, + LPWR_WAKEUP_SWITCH, +} lpwr_wakeupcd_t; + +typedef enum { + LPWR_MODE_TIMEOUT = 0, +} lpwr_mode_t; + +lpwr_state_t lpwr_get_state(void); +lpwr_mode_t lpwr_get_mode(void); +uint32_t lpwr_timestamp_read(void); +uint32_t lpwr_timeout_value_read(void); +void lpwr_set_sleep_wakeupcd(lpwr_wakeupcd_t wakeupcd); +lpwr_wakeupcd_t lpwr_get_sleep_wakeupcd(void); +void lpwr_update_timestamp(void); +void lpwr_set_timeout_manual(bool enable); +bool lpwr_get_timeout_manual(void); +void lpwr_set_state(lpwr_state_t state); +void lpwr_set_mode(lpwr_mode_t mode); +void lpwr_task(void); diff --git a/linker/wireless/lpwr_wb32.c b/linker/wireless/lpwr_wb32.c new file mode 100644 index 0000000..1cec1c3 --- /dev/null +++ b/linker/wireless/lpwr_wb32.c @@ -0,0 +1,237 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "wireless.h" +#include "util.h" + +#ifndef LPWR_UART_WAKEUP_DISABLE +# include "uart.h" +#endif + +static ioline_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; +static ioline_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; + +#if PAL_USE_CALLBACKS != TRUE +# error PAL_USE_CALLBACKS must be set to TRUE! +#endif + +#if !((DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)) +# error DIODE_DIRECTION must be one of COL2ROW or ROW2COL! +#endif + +// clang-format off +static const uint32_t pre_lp_code[] = {553863175u, 554459777u, 1208378049u, 4026624001u, 688390415u, 554227969u, 3204472833u, 1198571264u, 1073807360u, 1073808388u}; +#define PRE_LP() ((void (*)(void))((unsigned int)(pre_lp_code) | 0x01))() + +static const uint32_t post_lp_code[] = {553863177u, 554459777u, 1208509121u, 51443856u, 4026550535u, 1745485839u, 3489677954u, 536895496u, 673389632u, 1198578684u, 1073807360u, 536866816u, 1073808388u}; +#define POST_LP() ((void (*)(void))((unsigned int)(post_lp_code) | 0x01))() +// clang-format on + +extern void __early_init(void); +extern void matrix_init_pins(void); + +void palcallback_cb(uint8_t line) __attribute__((weak)); +void palcallback_cb(uint8_t line) {} + +void palcallback(void *arg) { + uint8_t line = (uint32_t)arg & 0xFF; + + switch (line) { +#ifndef LPWR_UART_WAKEUP_DISABLE + case PAL_PAD(UART_RX_PIN): { + lpwr_set_sleep_wakeupcd(LPWR_WAKEUP_UART); + } break; +#endif + default: { + lpwr_set_sleep_wakeupcd(LPWR_WAKEUP_MATRIX); + } break; + } + + palcallback_cb(line); + + irqDeinit(); + EXTI->PR = 0xFFFFFFFF; +} + +void pal_events_init(void) { + + for (uint8_t i = 0; i < 16; i++) { + _pal_events[i].cb = palcallback; + _pal_events[i].arg = (void *)(uint32_t)i; + } +} + +void lpwr_exti_init_hook(void) __attribute__((weak)); +void lpwr_exti_init_hook(void) {} + +void lpwr_exti_init(void) { + + pal_events_init(); + +#if DIODE_DIRECTION == ROW2COL + for (uint8_t i = 0; i < ARRAY_SIZE(col_pins); i++) { + if (col_pins[i] != NO_PIN) { + setPinOutputOpenDrain(col_pins[i]); + writePinLow(col_pins[i]); + } + } + + for (uint8_t i = 0; i < ARRAY_SIZE(row_pins); i++) { + if (row_pins[i] != NO_PIN) { + setPinInputHigh(row_pins[i]); + waitInputPinDelay(); + palEnableLineEvent(row_pins[i], PAL_EVENT_MODE_FALLING_EDGE); + } + } +#elif DIODE_DIRECTION == COL2ROW + for (uint8_t i = 0; i < ARRAY_SIZE(row_pins); i++) { + if (row_pins[i] != NO_PIN) { + setPinOutputOpenDrain(row_pins[i]); + writePinLow(row_pins[i]); + } + } + + for (uint8_t i = 0; i < ARRAY_SIZE(col_pins); i++) { + if (col_pins[i] != NO_PIN) { + setPinInputHigh(col_pins[i]); + waitInputPinDelay(); + palEnableLineEvent(col_pins[i], PAL_EVENT_MODE_FALLING_EDGE); + } + } +#endif + +#ifndef LPWR_UART_WAKEUP_DISABLE + setPinInput(UART_RX_PIN); + waitInputPinDelay(); + palEnableLineEvent(UART_RX_PIN, PAL_EVENT_MODE_BOTH_EDGES); +#endif + + lpwr_exti_init_hook(); + + /* IRQ subsystem initialization.*/ + irqInit(); +} + +void lpwr_clock_enable_user(void) __attribute__((weak)); +void lpwr_clock_enable_user(void) {} + +void lpwr_clock_enable(void) { + + __early_init(); + + PWR->ANAKEY1 = 0x03; + PWR->ANAKEY2 = 0x0C; + ANCTL->USBPCR &= ~(ANCTL_USBPCR_DMSTEN | ANCTL_USBPCR_DPSTEN); + /* Locks write to ANCTL registers */ + PWR->ANAKEY1 = 0x00; + PWR->ANAKEY2 = 0x00; + + /* Enable SFM clock */ + RCC->AHBENR1 |= RCC_AHBENR1_CRCSFMEN; + + /* Enable USB peripheral clock */ + RCC->AHBENR1 |= RCC_AHBENR1_USBEN; + + /* Configure USB FIFO clock source */ + RCC->USBFIFOCLKSRC = RCC_USBFIFOCLKSRC_USBCLK; + + /* Enable USB FIFO clock */ + RCC->USBFIFOCLKENR = RCC_USBFIFOCLKENR_CLKEN; + + /* Configure and enable USBCLK */ +# if (WB32_USBPRE == WB32_USBPRE_DIV1P5) + RCC->USBCLKENR = RCC_USBCLKENR_CLKEN; + RCC->USBPRE = RCC_USBPRE_SRCEN; + RCC->USBPRE |= RCC_USBPRE_RATIO_1_5; + RCC->USBPRE |= RCC_USBPRE_DIVEN; +# elif (WB32_USBPRE == WB32_USBPRE_DIV1) + RCC->USBCLKENR = RCC_USBCLKENR_CLKEN; + RCC->USBPRE = RCC_USBPRE_SRCEN; + RCC->USBPRE |= 0x00; +# elif (WB32_USBPRE == WB32_USBPRE_DIV2) + RCC->USBCLKENR = RCC_USBCLKENR_CLKEN; + RCC->USBPRE = RCC_USBPRE_SRCEN; + RCC->USBPRE |= RCC_USBPRE_RATIO_2; + RCC->USBPRE |= RCC_USBPRE_DIVEN; +# elif (WB32_USBPRE == WB32_USBPRE_DIV3) + RCC->USBCLKENR = RCC_USBCLKENR_CLKEN; + RCC->USBPRE = RCC_USBPRE_SRCEN; + RCC->USBPRE |= RCC_USBPRE_RATIO_3; + RCC->USBPRE |= RCC_USBPRE_DIVEN; +#endif + rccEnableEXTI(); + +#if WB32_SERIAL_USE_UART1 + rccEnableUART1(); +#endif +#if WB32_SERIAL_USE_UART2 + rccEnableUART2(); +#endif +#if WB32_SERIAL_USE_UART3 + rccEnableUART3(); +#endif +#if WB32_SPI_USE_QSPI + rccEnableQSPI(); +#endif +#if WB32_SPI_USE_SPIM2 + rccEnableSPIM2(); +#endif +#if WB32_I2C_USE_I2C1 + rccEnableI2C1(); +#endif +#if WB32_I2C_USE_I2C2 + rccEnableI2C2(); +#endif + +#ifndef LPWR_UART_WAKEUP_DISABLE + palSetLineMode(UART_RX_PIN, PAL_MODE_ALTERNATE(UART_RX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); +#endif + + lpwr_clock_enable_user(); +} + +void wb32_stop_mode(void) { + + SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; + + /* Prevent the chip from being unable to enter stop mode due to pending interrupts */ +#if 1 + EXTI->PR = 0x7FFFF; + for (uint8_t i = 0; i < 8; i++) { + for (uint8_t j = 0; j < 32; j++) { + if (NVIC->ISPR[i] & (0x01UL < j)) { + NVIC->ICPR[i] = (0x01UL < j); + } + } + } + SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk; // Clear Systick IRQ Pending +#endif + + /* Clear all bits except DBP and FCLKSD bit */ + PWR->CR0 &= 0x09U; + + // STOP LP4 MODE S32KON + PWR->CR0 |= 0x3B004U; + PWR->CFGR = 0x3B3; + + PRE_LP(); + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* Request Wait For Interrupt */ + __WFI(); + + POST_LP(); + + /* Clear SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR &= (~SCB_SCR_SLEEPDEEP_Msk); + + SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; +} + +void mcu_stop_mode(void) { + + wb32_stop_mode(); +} diff --git a/linker/wireless/md_raw.c b/linker/wireless/md_raw.c new file mode 100644 index 0000000..eebfc94 --- /dev/null +++ b/linker/wireless/md_raw.c @@ -0,0 +1,30 @@ +// Copyright 2024 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#if RAW_ENABLE + +# include "quantum.h" +# include "wireless.h" +# include "usb_endpoints.h" +# include "usb_main.h" + +void replaced_hid_send(uint8_t *data, uint8_t length) { + + if (length != RAW_EPSIZE) { + return; + } + + if (get_transport() == TRANSPORT_USB) { + send_report(USB_ENDPOINT_IN_RAW, data, length); + } else { + md_send_raw(data, length); + } +} + +void md_receive_raw_cb(uint8_t *data, uint8_t length) { + void raw_hid_receive(uint8_t * data, uint8_t length); + + raw_hid_receive(data, length); +} + +#endif diff --git a/linker/wireless/md_raw.h b/linker/wireless/md_raw.h new file mode 100644 index 0000000..9ec762b --- /dev/null +++ b/linker/wireless/md_raw.h @@ -0,0 +1,10 @@ +// Copyright 2024 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define RENAME_WITH_LINE(A, B) COMBINE(A, B) +#define COMBINE(A, B) A##B +#define raw_hid_send(a, b) RENAME_WITH_LINE(_temp_rhs_, __LINE__)(a, b) +#define _temp_rhs_29 replaced_hid_send // raw_hid.h +#define _temp_rhs_464 replaced_hid_send // via.c diff --git a/linker/wireless/module.c b/linker/wireless/module.c new file mode 100644 index 0000000..7ae8af0 --- /dev/null +++ b/linker/wireless/module.c @@ -0,0 +1,553 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "module.h" +#include "smsg.h" +#include "uart.h" + +#ifndef MD_BAUD_RATE +# define MD_BAUD_RATE 115200 +#endif + +#ifndef MD_SNED_PKT_TIMEOUT +# define MD_SNED_PKT_TIMEOUT 10 +#endif + +#ifndef MD_SEND_PKT_RETRY +# define MD_SEND_PKT_RETRY 40 +#endif + +#ifndef MD_SEND_PKT_PAYLOAD_MAX +# define MD_SEND_PKT_PAYLOAD_MAX ((MD_RAW_SIZE) + 4) +#endif + +#ifndef MD_BT1_NAME +# define MD_BT1_NAME PRODUCT " BT1" +#endif + +#ifndef MD_BT2_NAME +# define MD_BT2_NAME PRODUCT " BT2" +#endif + +#ifndef MD_BT3_NAME +# define MD_BT3_NAME PRODUCT " BT3" +#endif + +#ifndef MD_BT4_NAME +# define MD_BT4_NAME PRODUCT " BT4" +#endif + +#ifndef MD_BT5_NAME +# define MD_BT5_NAME PRODUCT " BT5" +#endif + +#ifndef MD_DONGLE_MANUFACTURER +# define MD_DONGLE_MANUFACTURER MANUFACTURER +#endif + +#ifndef MD_DONGLE_PRODUCT +# define MD_DONGLE_PRODUCT PRODUCT " Dongle" +#endif + +#ifndef MD_RAW_SIZE +# define MD_RAW_SIZE 32 +#endif + +#define USBCONCAT(a, b) a##b +#define USBSTR(s) USBCONCAT(L, s) + +typedef struct +{ + uint8_t state; + uint8_t indicator; + uint8_t version; + uint8_t bat; +} md_info_t; + +static uint8_t md_pkt_payload[MD_SEND_PKT_PAYLOAD_MAX] = {0}; +static uint8_t md_rev_payload[MD_SEND_PKT_PAYLOAD_MAX] = {0}; +static uint8_t md_raw_payload[MD_RAW_SIZE] = {0}; + +static md_info_t md_info = { + .bat = 100, + .indicator = 0, + .version = 0, + .state = MD_STATE_NONE, +}; + +static void md_send_ack(void) { + + uint8_t sdata[0x03] = {0x61, 0x0D, 0x0A}; + uart_transmit(sdata, sizeof(sdata)); +} + +static bool md_check_sum(const uint8_t *data, uint32_t length) { + uint8_t sum = 0; + + for (uint32_t i = 0; i < (length - 1); i++) { + sum += data[i]; + } + + return sum == data[length - 1]; +} + +static void md_calc_check_sum(uint8_t *data, uint32_t length) { + uint8_t sum = 0; + + for (uint32_t i = 0; i < length; i++) { + sum += data[i]; + } + + data[length] = sum; +} + +bool md_receive_process_user(uint8_t *pdata, uint8_t len) __attribute__((weak)); +bool md_receive_process_user(uint8_t *pdata, uint8_t len) { + return true; +} + +bool md_receive_process_kb(uint8_t *pdata, uint8_t len) __attribute__((weak)); +bool md_receive_process_kb(uint8_t *pdata, uint8_t len) { + return md_receive_process_user(pdata, len); +} + +void md_receive_raw_cb(uint8_t *pdata, uint8_t len) __attribute__((weak)); +void md_receive_raw_cb(uint8_t *pdata, uint8_t len) {} + +void md_receive_host_cb(bool resume) __attribute__((weak)); +void md_receive_host_cb(bool resume) {} + +static void md_receive_msg_task(void) { + static uint32_t data_count = 0x00; + static uint8_t data_remain = 0x00; + + while (uart_available()) { + uint8_t data = uart_read(); + + switch (data_count) { + case 0: { // cmd + switch (data) { + case MD_REV_CMD_RAW: + case MD_REV_CMD_INDICATOR: + case MD_REV_CMD_DEVCTRL: + case MD_REV_CMD_BATVOL: + case MD_REV_CMD_MD_FW_VERSION: + case MD_REV_CMD_HOST_STATE: + case 0x61: { + md_rev_payload[data_count++] = data; + data_remain = 2; + } break; + default: { + data_count = 0; + } break; + } + continue; + } break; + case 1: { + md_rev_payload[data_count++] = data; + data_remain--; + continue; + } break; + case 2: { + // ACK + if ((md_rev_payload[0] == 0x61) && (md_rev_payload[1] == 0x0D) && (data == 0x0A)) { + if (smsg_get_state() == smsg_state_busy) { + smsg_set_state(smsg_state_replied); + } + data_count = 0; + return; + } + + // raw data + if ((md_rev_payload[0] == MD_REV_CMD_RAW) && (md_rev_payload[1] == MD_REV_CMD_RAW_OUT)) { + md_rev_payload[data_count++] = data; + data_remain = data + 1; + continue; + } + } + default: { + md_rev_payload[data_count++] = data; + data_remain--; + + if (data_remain) { + continue; + } + } break; + } + + if (md_check_sum(md_rev_payload, data_count)) { + md_send_ack(); + + if (md_receive_process_kb(md_rev_payload, data_count) != true) { + return; + } + + switch (md_rev_payload[0]) { + case MD_REV_CMD_RAW: { + uint8_t *pdata; + uint8_t len; + + len = md_rev_payload[2]; + pdata = &md_rev_payload[3]; + + if (len == sizeof(md_raw_payload)) { + memcpy(md_raw_payload, pdata, len); + md_receive_raw_cb(md_raw_payload, len); + } + } break; + case MD_REV_CMD_INDICATOR: { + md_info.indicator = md_rev_payload[1]; + } break; + case MD_REV_CMD_DEVCTRL: { + switch (md_rev_payload[1]) { + case MD_REV_CMD_DEVCTRL_PAIRING: { + md_info.state = MD_STATE_PAIRING; + } break; + case MD_REV_CMD_DEVCTRL_CONNECTED: { + md_info.state = MD_STATE_CONNECTED; + } break; + case MD_REV_CMD_DEVCTRL_DISCONNECTED: { + md_info.state = MD_STATE_DISCONNECTED; + } break; + case MD_REV_CMD_DEVCTRL_REJECT: { + md_info.state = MD_STATE_REJECT; + } break; + default: + break; + } + } break; + case MD_REV_CMD_BATVOL: { + md_info.bat = md_rev_payload[1]; + } break; + case MD_REV_CMD_MD_FW_VERSION: { + md_info.version = md_rev_payload[1]; + } break; + case MD_REV_CMD_HOST_STATE: { + md_receive_host_cb(md_rev_payload[1] == MD_REV_CMD_HOST_STATE_RESUME); + } break; + default: + break; + } + } + data_count = 0; + } +} + +static void md_send_pkt_task(void) { + static uint32_t smsg_timer = 0x00; + static uint8_t smsg_retry = 0; + + switch (smsg_get_state()) { + case smsg_state_busy: { + if (sync_timer_elapsed32(smsg_timer) > (MD_SNED_PKT_TIMEOUT)) { + smsg_retry = 0; + smsg_set_state(smsg_state_retry); + } + } break; + case smsg_state_retry: { + if (++smsg_retry > MD_SEND_PKT_RETRY) { + smsg_retry = 0; + smsg_pop(); + } + smsg_set_state(smsg_state_free); + } break; + case smsg_state_replied: { + smsg_pop(); + smsg_set_state(smsg_state_free); + } // break; + case smsg_state_free: { + uint32_t size = smsg_peek(md_pkt_payload); + if (size) { + md_send_pkt(md_pkt_payload, size); + smsg_timer = sync_timer_read32(); + smsg_set_state(smsg_state_busy); + } + } break; + default: + break; + } +} + +void md_init(void) { + + uart_init(MD_BAUD_RATE); + smsg_init(); + + memset(md_pkt_payload, 0, sizeof(md_pkt_payload)); +} + +void md_main_task(void) { + + md_send_pkt_task(); + md_receive_msg_task(); +} + +uint8_t *md_getp_state(void) { + + return &md_info.state; +} + +uint8_t *md_getp_bat(void) { + + return &md_info.bat; +} + +uint8_t *md_getp_indicator(void) { + + return &md_info.indicator; +} + +uint8_t md_get_version(void) { + + return md_info.version; +} + +void md_send_pkt(uint8_t *data, uint32_t len) { + + if (!data || !len) { + return; + } + + // send + uart_transmit(data, len); +} + +void md_send_kb(uint8_t *data) { + uint8_t sdata[MD_SND_CMD_KB_LEN + 2] = {0x00}; + + sdata[0] = MD_SND_CMD_SEND_KB; + memcpy(&sdata[1], data, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_nkro(uint8_t *data) { + uint8_t sdata[MD_SND_CMD_NKRO_LEN + 2] = {0x00}; + + sdata[0] = MD_SND_CMD_SEND_NKRO; + memcpy(&sdata[1], data, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_consumer(uint8_t *data) { + uint8_t sdata[MD_SND_CMD_CONSUMER_LEN + 2] = {0x00}; + + sdata[0] = MD_SND_CMD_SEND_CONSUMER; + memcpy(&sdata[1], data, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_system(uint8_t *data) { + uint8_t sdata[MD_SND_CMD_SYSTEM_LEN + 2] = {0x00}; + + sdata[0] = MD_SND_CMD_SEND_SYSTEM; + memcpy(&sdata[1], data, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_fn(uint8_t *data) { + uint8_t sdata[MD_SND_CMD_FN_LEN + 2] = {0x00}; + + sdata[0] = MD_SND_CMD_SEND_FN; + memcpy(&sdata[1], data, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_mouse(uint8_t *data) { + uint8_t sdata[MD_SND_CMD_MOUSE_LEN + 2] = {0x00}; + + sdata[0] = MD_SND_CMD_SEND_MOUSE; + memcpy(&sdata[1], data, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_devinfo(const char *name) { + uint8_t sdata[MD_SND_CMD_DEVINFO_LEN + 3] = {0x00}; + uint8_t infolen = strlen((const char *)name); + + if (infolen > MD_SND_CMD_DEVINFO_LEN) { + return; + } + + sdata[0] = MD_SND_CMD_SEND_DEVINFO; + sdata[1] = infolen; + + memcpy(&sdata[2], name, infolen); + md_calc_check_sum(sdata, infolen + 2); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_devctrl(uint8_t cmd) { + uint8_t sdata[3] = {0x00}; + + sdata[0] = MD_SND_CMD_DEVCTRL; + memcpy(&sdata[1], &cmd, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_devctrl_bat(uint8_t cmd) { + uint8_t sdata[3] = {0x00}; + + sdata[0] = MD_SND_CMD_DEVCTRL_BAT; + memcpy(&sdata[1], &cmd, sizeof(sdata) - 2); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_rf_send_carrier(uint8_t channel, uint8_t tx_power, uint8_t phy) { + uint8_t sdata[5] = {0x00}; + + sdata[0] = CONTINUE; + sdata[1] = channel; + sdata[2] = tx_power; + sdata[3] = phy; + // md_calc_check_sum(sdata, sizeof(sdata) - 1); + sdata[4] = sdata[0] + sdata[1] - sdata[3]; + smsg_push(sdata, sizeof(sdata)); +} + +void md_rf_send_stop(void) { + uint8_t sdata[3] = {0xB4, 0x00, 0xB4}; + + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_manufacturer(char *str, uint8_t len) { + uint8_t sdata[MD_SND_CMD_MANUFACTURER_LEN + 3] = {0x00}; + + if (len > MD_SND_CMD_MANUFACTURER_LEN) { + return; + } + + sdata[0] = MD_SND_CMD_MANUFACTURER; + sdata[1] = len; + memcpy(&sdata[2], str, len); + md_calc_check_sum(sdata, len + 2); + smsg_push(sdata, len + 3); +} + +void md_send_product(char *str, uint8_t len) { + uint8_t sdata[MD_SND_CMD_PRODUCT_LEN + 3] = {0x00}; + + if (len > MD_SND_CMD_PRODUCT_LEN) { + return; + } + + sdata[0] = MD_SND_CMD_PRODUCT; + sdata[1] = len; + memcpy(&sdata[2], str, len); + md_calc_check_sum(sdata, len + 2); + smsg_push(sdata, len + 3); +} + +void md_send_vpid(uint16_t vid, uint16_t pid) { + uint8_t sdata[4 + 2] = {0x00}; + uint32_t vpid; + + vpid = (pid << 16) | vid; + + sdata[0] = MD_SND_CMD_VPID; + memcpy(&sdata[1], &vpid, sizeof(vpid)); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_send_raw(uint8_t *data, uint8_t length) { + uint8_t sdata[MD_RAW_SIZE + 4] = {0x00}; + + if (length != MD_RAW_SIZE) { + return; + } + + sdata[0] = MD_SND_CMD_RAW; + sdata[1] = MD_SND_CMD_RAW_IN; + sdata[2] = length; + memcpy(&sdata[3], data, length); + md_calc_check_sum(sdata, sizeof(sdata) - 1); + smsg_push(sdata, sizeof(sdata)); +} + +void md_devs_change(uint8_t devs, bool reset) __attribute__((weak)); +void md_devs_change(uint8_t devs, bool reset) { + + switch (devs) { + case DEVS_USB: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_USB); + } break; + case DEVS_2G4: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_2G4); + if (reset) { + // if (md_get_version() < 48) { + // md_send_manufacturer(MD_DONGLE_MANUFACTURER, strlen(MD_DONGLE_MANUFACTURER)); + // md_send_product(MD_DONGLE_PRODUCT, strlen(MD_DONGLE_PRODUCT)); + // } else { // Add Unicode character support starting from v48. + md_send_manufacturer((char *)USBSTR(MD_DONGLE_MANUFACTURER), sizeof(USBSTR(MD_DONGLE_MANUFACTURER))); + md_send_product((char *)USBSTR(MD_DONGLE_PRODUCT), sizeof(USBSTR(MD_DONGLE_PRODUCT))); + // } + md_send_vpid(VENDOR_ID, PRODUCT_ID); + md_send_devctrl(MD_SND_CMD_DEVCTRL_CLEAN); + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } + } break; + case DEVS_BT1: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT1); + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_CLEAN); + md_send_devinfo(MD_BT1_NAME); + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } + } break; + case DEVS_BT2: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT2); + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_CLEAN); + md_send_devinfo(MD_BT2_NAME); + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } + } break; + case DEVS_BT3: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT3); + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_CLEAN); + md_send_devinfo(MD_BT3_NAME); + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } + } break; + case DEVS_BT4: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT4); + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_CLEAN); + md_send_devinfo(MD_BT4_NAME); + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } + } break; + case DEVS_BT5: { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT5); + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_CLEAN); + md_send_devinfo(MD_BT5_NAME); + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } + } break; + default: + break; + } +} + +bool md_inquire_bat(void) { + + if (smsg_is_busy()) { + return false; + } + + md_send_devctrl(MD_SND_CMD_DEVCTRL_INQVOL); + + return true; +} diff --git a/linker/wireless/module.h b/linker/wireless/module.h new file mode 100644 index 0000000..854bab1 --- /dev/null +++ b/linker/wireless/module.h @@ -0,0 +1,134 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// device index +enum { + DEVS_USB = 0, + DEVS_BT1, + DEVS_BT2, + DEVS_BT3, + DEVS_BT4, + DEVS_BT5, + DEVS_2G4, +}; + +enum { + MD_STATE_NONE = 0, + MD_STATE_PAIRING, + MD_STATE_CONNECTED, + MD_STATE_DISCONNECTED, + MD_STATE_REJECT, +}; + +enum { + MD_SND_CMD_KB_LEN = 8, + MD_SND_CMD_NKRO_LEN = 14, + MD_SND_CMD_CONSUMER_LEN = 2, + MD_SND_CMD_SYSTEM_LEN = 1, + MD_SND_CMD_FN_LEN = 1, + MD_SND_CMD_MOUSE_LEN = 5, + MD_SND_CMD_DEVINFO_LEN = 18, + MD_SND_CMD_MANUFACTURER_LEN = 46, + MD_SND_CMD_PRODUCT_LEN = 46, +}; + +enum { + /* send report */ + MD_SND_CMD_SEND_KB = 0xA1, + MD_SND_CMD_SEND_NKRO = 0xA2, + MD_SND_CMD_SEND_CONSUMER = 0xA3, + MD_SND_CMD_SEND_SYSTEM = 0xA4, + MD_SND_CMD_SEND_FN = 0xA5, + MD_SND_CMD_SEND_MOUSE = 0xA8, + MD_SND_CMD_SEND_DEVINFO = 0xA9, + /* Dongle */ + MD_SND_CMD_MANUFACTURER = 0xAB, + MD_SND_CMD_PRODUCT = 0xAC, + MD_SND_CMD_VPID = 0xAD, + MD_SND_CMD_RAW = 0xAF, + MD_SND_CMD_RAW_IN = 0x61, + /* device ctrl */ + MD_SND_CMD_DEVCTRL = 0xA6, + MD_SND_CMD_DEVCTRL_BAT = 0xA7, + MD_SND_CMD_DEVCTRL_USB = 0x11, + MD_SND_CMD_DEVCTRL_2G4 = 0x30, + MD_SND_CMD_DEVCTRL_BT1 = 0x31, + MD_SND_CMD_DEVCTRL_BT2 = 0x32, + MD_SND_CMD_DEVCTRL_BT3 = 0x33, + MD_SND_CMD_DEVCTRL_BT4 = 0x34, + MD_SND_CMD_DEVCTRL_BT5 = 0x35, + MD_SND_CMD_DEVCTRL_PAIR = 0x51, + MD_SND_CMD_DEVCTRL_CLEAN = 0x52, + MD_SND_CMD_DEVCTRL_INQVOL = 0x53, + MD_SND_CMD_DEVCTRL_SLEEP_INSTANT = 0x54, // reserved + MD_SND_CMD_DEVCTRL_SLEEP_BT_EN = 0x55, // timeout 30min enable in BT mode + MD_SND_CMD_DEVCTRL_SLEEP_BT_DIS = 0x56, // timeout 30min disable in BT mode + MD_SND_CMD_DEVCTRL_SLEEP_2G4_EN = 0x57, // timeout 30min enable in 2.4G mode + MD_SND_CMD_DEVCTRL_SLEEP_2G4_DIS = 0x58, // timeout 30min enable in 2.4G mode + MD_SND_CMD_DEVCTRL_RSV_DEBUG = 0x60, // reserved + MD_SND_CMD_DEVCTRL_RSV_SLEEP = 0x61, // reserved + MD_SND_CMD_DEVCTRL_FORCED_PAIRING_BT = 0x62, // forced pairing, to be used in a factory environment. + MD_SND_CMD_DEVCTRL_FORCED_PAIRING_2G4 = 0x63, // forced pairing, to be used in a factory environment. + MD_SND_CMD_DEVCTRL_CHARGING = 0x64, // battery power control. + MD_SND_CMD_DEVCTRL_CHARGING_STOP = 0x65, // battery power control. + MD_SND_CMD_DEVCTRL_CHARGING_DONE = 0x66, // battery power control. + MD_SND_CMD_DEVCTRL_FW_VERSION = 0x70, // module fw version. + MD_SND_CMD_INVALID_DATA = 0x00, // unused +}; + +enum { + MD_REV_CMD_RAW = 0xAF, + MD_REV_CMD_RAW_OUT = 0x60, + MD_REV_CMD_INDICATOR = 0x5A, + MD_REV_CMD_DEVCTRL = 0x5B, + MD_REV_CMD_DEVCTRL_BAT_LOW = 0x21, // unused + MD_REV_CMD_DEVCTRL_BAT_PWROFF = 0x22, // unused + MD_REV_CMD_DEVCTRL_BAT_NORMAL = 0x23, // unused + MD_REV_CMD_DEVCTRL_PAIRING = 0x31, + MD_REV_CMD_DEVCTRL_CONNECTED = 0x32, + MD_REV_CMD_DEVCTRL_DISCONNECTED = 0x33, + MD_REV_CMD_DEVCTRL_DONE = 0x34, // reserved + MD_REV_CMD_DEVCTRL_RECONNECT = 0x35, // reserved + MD_REV_CMD_DEVCTRL_REJECT = 0x36, + MD_REV_CMD_DEVCTRL_UNPAIRED = 0x37, // reserved + MD_REV_CMD_DEVCTRL_MD_WAKEUP = 0x42, // unused + MD_REV_CMD_DEVCTRL_CLS_UART = 0x43, // unused + MD_REV_CMD_BATVOL = 0x5C, + MD_REV_CMD_MD_FW_VERSION = 0x5D, + MD_REV_CMD_HOST_STATE = 0x60, + MD_REV_CMD_HOST_STATE_SUSPEND = 0x00, + MD_REV_CMD_HOST_STATE_RESUME = 0x01, +}; + +enum { + BURST = 0xB2, + CONTINUE = 0xB3, + STOP = 0xB4, +}; + +void md_init(void); +void md_main_task(void); +void md_send_kb(uint8_t *data); +void md_send_nkro(uint8_t *data); +void md_send_consumer(uint8_t *data); +void md_send_system(uint8_t *data); +void md_send_fn(uint8_t *data); +void md_send_mouse(uint8_t *data); +void md_send_devctrl(uint8_t cmd); +void md_send_manufacturer(char *str, uint8_t len); +void md_send_product(char *str, uint8_t len); +void md_send_vpid(uint16_t vid, uint16_t pid); +void md_send_raw(uint8_t *data, uint8_t length); +void md_send_pkt(uint8_t *data, uint32_t len); +bool md_receive_process_user(uint8_t *pdata, uint8_t len); +void md_devs_change(uint8_t devs, bool reset); +bool md_inquire_bat(void); +uint8_t md_get_version(void); +uint8_t *md_getp_state(void); +uint8_t *md_getp_bat(void); +uint8_t *md_getp_indicator(void); +void md_rf_send_carrier(uint8_t channel, uint8_t tx_power, uint8_t phy); +void md_rf_send_stop(void); +void md_send_devctrl_bat(uint8_t cmd); diff --git a/linker/wireless/rgb_matrix_blink.c b/linker/wireless/rgb_matrix_blink.c new file mode 100644 index 0000000..80366fd --- /dev/null +++ b/linker/wireless/rgb_matrix_blink.c @@ -0,0 +1,174 @@ +// Copyright 2024 JoyLee (@itarze) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "rgb_matrix.h" +#include "rgb_matrix_blink.h" +#include "timer.h" + +#define NUM_BLINK_RGBS (sizeof(blink_rgbs) / sizeof(blink_rgbs[0])) + +// /* Example */ +// blink_rgb_t blink_rgbs[RGB_MATRIX_BLINK_COUNT] = { +// {.index = 1, .interval = 250, .times = 5, .color = {.r = 0xFF, .g = 0xFF, .b = 0xFF}, .blink_cb = NULL}, +// {.index = 0xFF, .interval = 250, .times = 5, .color = {.r = 0xFF, .g = 0x00, .b = 0x00}, .blink_cb = NULL}, +// }; + +bool rgb_matrix_blink_set(uint8_t index) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + if (blink_rgbs[i].times < 1) { + return false; + } + blink_rgbs[i].remain_time = blink_rgbs[i].interval * blink_rgbs[i].times * 2 + 1; + if (blink_rgbs[i].times == 0xFF) { + blink_rgbs[i].remain_time = blink_rgbs[i].interval + 1; + } + return true; + } + } + + return false; +} + +bool rgb_matrix_blink_set_color(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + blink_rgbs[i].color.r = r; + blink_rgbs[i].color.g = g; + blink_rgbs[i].color.b = b; + return true; + } + } + + return false; +} + +bool rgb_matrix_blink_set_cb(uint8_t index, void *blink_cb) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + blink_rgbs[i].blink_cb = blink_cb; + return true; + } + } + + return false; +} + +bool rgb_matrix_blink_set_interval(uint8_t index, uint32_t interval) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + blink_rgbs[i].interval = interval; + return true; + } + } + + return false; +} + +bool rgb_matrix_blink_set_times(uint8_t index, uint32_t times) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + blink_rgbs[i].times = times; + return true; + } + } + + return false; +} + +bool rgb_matrix_blink_set_remain_time(uint8_t index, uint32_t time) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + blink_rgbs[i].remain_time = time; + return true; + } + } + + return false; +} + +bool rgb_matrix_blink_set_interval_times(uint8_t index, uint32_t interval, uint32_t times) { + + for (uint8_t i = 0; i < NUM_BLINK_RGBS; i++) { + if (blink_rgbs[i].index == index) { + blink_rgbs[i].interval = interval; + blink_rgbs[i].times = times; + blink_rgbs[i].time = 0x00; + blink_rgbs[i].flip = false; + return true; + } + } + + return false; +} + +__attribute__((weak)) bool rgb_matrix_blink_user(blink_rgb_t *blink_rgb) { + return true; +} + +bool rgb_matrix_blink_task(uint8_t led_min, uint8_t led_max) { + + for (uint8_t rgb_index = 0; rgb_index < NUM_BLINK_RGBS; rgb_index++) { + if (blink_rgbs[rgb_index].remain_time != 0) { + if ((blink_rgbs[rgb_index].time == 0) || (timer_elapsed32(blink_rgbs[rgb_index].time) >= blink_rgbs[rgb_index].interval)) { + blink_rgbs[rgb_index].flip = !blink_rgbs[rgb_index].flip; + blink_rgbs[rgb_index].time = timer_read32(); + + if (blink_rgbs[rgb_index].remain_time >= blink_rgbs[rgb_index].interval) { + blink_rgbs[rgb_index].remain_time -= blink_rgbs[rgb_index].interval; + } else { + blink_rgbs[rgb_index].remain_time = 0; + blink_rgbs[rgb_index].flip = false; + blink_rgbs[rgb_index].time = 0; + } + } + + if (blink_rgbs[rgb_index].remain_time == 0) { + if (blink_rgbs[rgb_index].blink_cb != NULL) { + blink_rgbs[rgb_index].blink_cb(blink_rgbs[rgb_index].index); + } + if (blink_rgbs[rgb_index].index == 0xFF) { + rgb_matrix_set_color_all(0x00, 0x00, 0x00); + } else if (blink_rgbs[rgb_index].index < RGB_MATRIX_LED_COUNT) { + rgb_matrix_set_color(blink_rgbs[rgb_index].index, 0x00, 0x00, 0x00); + } + continue; + } + + if (rgb_matrix_blink_user(&blink_rgbs[rgb_index]) != true) { + continue; + } + + if (blink_rgbs[rgb_index].flip) { + if (blink_rgbs[rgb_index].index == 0xFF) { + rgb_matrix_set_color_all(blink_rgbs[rgb_index].color.r, + blink_rgbs[rgb_index].color.g, + blink_rgbs[rgb_index].color.b); + } else if (blink_rgbs[rgb_index].index < RGB_MATRIX_LED_COUNT) { + rgb_matrix_set_color(blink_rgbs[rgb_index].index, + blink_rgbs[rgb_index].color.r, + blink_rgbs[rgb_index].color.g, + blink_rgbs[rgb_index].color.b); + } + } else { + if (blink_rgbs[rgb_index].index == 0xFF) { + rgb_matrix_set_color_all(0x00, 0x00, 0x00); + } else if (blink_rgbs[rgb_index].index < RGB_MATRIX_LED_COUNT) { + rgb_matrix_set_color(blink_rgbs[rgb_index].index, 0x00, 0x00, 0x00); + } + } + } else { + blink_rgbs[rgb_index].flip = false; + blink_rgbs[rgb_index].time = 0; + } + } + + return true; +} diff --git a/linker/wireless/rgb_matrix_blink.h b/linker/wireless/rgb_matrix_blink.h new file mode 100644 index 0000000..485e4f9 --- /dev/null +++ b/linker/wireless/rgb_matrix_blink.h @@ -0,0 +1,31 @@ +// Copyright 2024 JoyLee (@itarze) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +typedef struct { + uint32_t interval; + uint32_t remain_time; + uint32_t times; + uint32_t time; + uint8_t index; + uint8_t flip; + void (*blink_cb)(uint8_t); + RGB color; +} blink_rgb_t; + +#ifndef RGB_MATRIX_BLINK_COUNT +# define RGB_MATRIX_BLINK_COUNT 0 +#endif + +extern blink_rgb_t blink_rgbs[RGB_MATRIX_BLINK_COUNT]; + +bool rgb_matrix_blink_set(uint8_t index); +bool rgb_matrix_blink_set_color(uint8_t index, uint8_t r, uint8_t g, uint8_t b); +bool rgb_matrix_blink_set_cb(uint8_t index, void *blink_cb); +bool rgb_matrix_blink_set_interval(uint8_t index, uint32_t interval); +bool rgb_matrix_blink_set_times(uint8_t index, uint32_t times); +bool rgb_matrix_blink_set_remain_time(uint8_t index, uint32_t time); +bool rgb_matrix_blink_set_interval_times(uint8_t index, uint32_t interval, uint32_t times); +bool rgb_matrix_blink_task(uint8_t led_min, uint8_t led_max); +bool rgb_matrix_blink_user(blink_rgb_t *blink_rgb); diff --git a/linker/wireless/smsg.c b/linker/wireless/smsg.c new file mode 100644 index 0000000..cfa9571 --- /dev/null +++ b/linker/wireless/smsg.c @@ -0,0 +1,122 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "smsg.h" +#include + +#ifndef SMSG_NUM +# define SMSG_NUM 40 +#endif + +#ifndef SMSG_PAYLOAD_LEN +# define SMSG_PAYLOAD_LEN 50 +#endif + +#define SMSG_BUF_SIZE (SMSG_NUM * SMSG_PAYLOAD_LEN) +#define END_PTR ((smsg_ptr_t *)&smsg_instance.ptr[SMSG_NUM - 1]) +#define FREE_SPACE ((uint32_t)(&smsg_buffer[SMSG_BUF_SIZE - 1] - smsg_instance.buffer)) + +typedef struct { + uint8_t *head; + uint8_t *tail; +} smsg_ptr_t; + +typedef struct { + smsg_states_t state; + smsg_ptr_t *ptr; + smsg_ptr_t *in_ptr; + smsg_ptr_t *out_ptr; + uint8_t *buffer; +} smsg_t; + +static smsg_ptr_t smsg_ptr[SMSG_NUM]; +static uint8_t smsg_buffer[SMSG_BUF_SIZE]; +static smsg_t smsg_instance; + +void smsg_init(void) { + + smsg_instance.buffer = smsg_buffer; + smsg_instance.ptr = smsg_ptr; + smsg_instance.ptr->head = smsg_instance.buffer; + smsg_instance.ptr->tail = smsg_instance.buffer; + smsg_instance.in_ptr = smsg_instance.ptr; + smsg_instance.out_ptr = smsg_instance.ptr; + smsg_instance.state = smsg_state_free; +} + +bool smsg_push(uint8_t *buf, uint32_t size) { + + if (smsg_instance.in_ptr == END_PTR) { + if (smsg_instance.ptr == smsg_instance.out_ptr) { + return false; + } + } else { + if ((smsg_instance.in_ptr + 1) == smsg_instance.out_ptr) { + return false; + } + } + + if (FREE_SPACE < SMSG_PAYLOAD_LEN) { + smsg_instance.buffer = smsg_buffer; + } + + if (size > SMSG_PAYLOAD_LEN) { + return false; + } + + memcpy(smsg_instance.buffer, buf, size); + smsg_instance.in_ptr->head = smsg_instance.buffer; + smsg_instance.buffer += size; + smsg_instance.in_ptr->tail = smsg_instance.buffer; + if (smsg_instance.in_ptr == END_PTR) { + smsg_instance.in_ptr = smsg_instance.ptr; + } else { + smsg_instance.in_ptr++; + } + + return true; +} + +uint32_t smsg_peek(uint8_t *buf) { + + if (smsg_instance.out_ptr != smsg_instance.in_ptr) { + uint32_t size; + + size = smsg_instance.out_ptr->tail - smsg_instance.out_ptr->head; + memcpy(buf, smsg_instance.out_ptr->head, size); + + return size; + } + + return 0; +} + +void smsg_pop(void) { + + if (smsg_instance.out_ptr != smsg_instance.in_ptr) { + if (smsg_instance.out_ptr == END_PTR) { + smsg_instance.out_ptr = smsg_instance.ptr; + } else { + smsg_instance.out_ptr++; + } + } +} + +smsg_states_t smsg_get_state(void) { + + return smsg_instance.state; +} + +void smsg_set_state(smsg_states_t state) { + + smsg_instance.state = state; +} + +bool smsg_is_busy(void) { + + if (smsg_instance.out_ptr != smsg_instance.in_ptr) { + return true; + } + + return false; +} diff --git a/linker/wireless/smsg.h b/linker/wireless/smsg.h new file mode 100644 index 0000000..ea08630 --- /dev/null +++ b/linker/wireless/smsg.h @@ -0,0 +1,22 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +typedef enum { + smsg_state_free = 0, + smsg_state_busy, + smsg_state_retry, + smsg_state_replied +} smsg_states_t; + +void smsg_init(void); +bool smsg_push(uint8_t *buf, uint32_t size); +uint32_t smsg_peek(uint8_t *buf); +void smsg_pop(void); +smsg_states_t smsg_get_state(void); +void smsg_set_state(smsg_states_t state); +bool smsg_is_busy(void); diff --git a/linker/wireless/transport.c b/linker/wireless/transport.c new file mode 100644 index 0000000..a8dd23e --- /dev/null +++ b/linker/wireless/transport.c @@ -0,0 +1,171 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "module.h" +#include "usb_device_state.h" +#include "usb_main.h" +#include "transport.h" + +#ifndef USB_POWER_DOWN_DELAY +# define USB_POWER_DOWN_DELAY 7000 +#endif + +extern host_driver_t chibios_driver; +extern host_driver_t wireless_driver; + +static transport_t transport = TRANSPORT_USB; +bool temp; + +void wls_transport_enable(bool enable) __attribute__((weak)); +void wls_transport_enable(bool enable) { + + if (enable) { + if (host_get_driver() != &wireless_driver) { + host_set_driver(&wireless_driver); + usb_device_state_set_protocol(USB_PROTOCOL_REPORT); // default with true + } + } else { + if (*md_getp_state() == MD_STATE_CONNECTED) { + wireless_driver.send_keyboard(NULL); + wireless_driver.send_nkro(NULL); + } + } +} + +/* Control USB device connection and disconnection by + * controlling the power supply of the USB DP pull-up resistor. + * Overwrite these two functions. */ +void usb_power_connect(void) __attribute__((weak)); +void usb_power_connect(void) {} + +void usb_power_disconnect(void) __attribute__((weak)); +void usb_power_disconnect(void) {} + +void usb_transport_enable(bool enable) __attribute__((weak)); +void usb_transport_enable(bool enable) { + + if (enable) { + if (host_get_driver() != &chibios_driver) { + extern bool last_suspend_state; + + /* This flag is not set to 1 with probability after usb restart */ + last_suspend_state = true; +#if !defined(KEEP_USB_CONNECTION_IN_WIRELESS_MODE) + usb_power_connect(); + restart_usb_driver(&USBD1); +#endif + host_set_driver(&chibios_driver); + } + } else { + if (USB_DRIVER.state == USB_ACTIVE) { + chibios_driver.send_keyboard(NULL); + chibios_driver.send_nkro(NULL); + } + +#if !defined(KEEP_USB_CONNECTION_IN_WIRELESS_MODE) + usbStop(&USBD1); + usbDisconnectBus(&USBD1); + usb_power_disconnect(); +#endif + } +} + +void set_transport(transport_t new_transport) { + + if (transport != new_transport) { + transport = new_transport; + + switch (transport) { + case TRANSPORT_USB: { + wls_transport_enable(false); + usb_transport_enable(true); + } break; + case TRANSPORT_WLS: { + usb_transport_enable(false); + wls_transport_enable(true); + } break; + default: + break; + } + } +} + +transport_t get_transport(void) { + + return transport; +} +uint32_t suspend_timer = 0x00; +void usb_remote_wakeup(void) { + +#ifdef USB_REMOTE_USE_QMK + if (USB_DRIVER.state == USB_SUSPENDED) { + dprintln("suspending keyboard"); + while (USB_DRIVER.state == USB_SUSPENDED) { + /* Do this in the suspended state */ + suspend_power_down(); // on AVR this deep sleeps for 15ms + /* Remote wakeup */ + if ((USB_DRIVER.status & 2U) && suspend_wakeup_condition()) { + usbWakeupHost(&USB_DRIVER); +# if USB_SUSPEND_WAKEUP_DELAY > 0 + // Some hubs, kvm switches, and monitors do + // weird things, with USB device state bouncing + // around wildly on wakeup, yielding race + // conditions that can corrupt the keyboard state. + // + // Pause for a while to let things settle... + wait_ms(USB_SUSPEND_WAKEUP_DELAY); +# endif + } + } + /* Woken up */ + } +#else + + if ((USB_DRIVER.state == USB_SUSPENDED)) { + if (!suspend_timer) suspend_timer = sync_timer_read32(); + if (sync_timer_elapsed32(suspend_timer) >= USB_POWER_DOWN_DELAY) { + suspend_timer = 0x00; + extern void lpwr_set_timeout_manual(bool enable); + temp = true; + // suspend_power_down(); + lpwr_set_timeout_manual(true); + } + } else { + suspend_timer = 0x00; + } +#endif +} + +#ifndef USB_REMOTE_USE_QMK +void usb_remote_host(void) { + + if (USB_DRIVER.state == USB_SUSPENDED) { + if ((USB_DRIVER.status & 2U) && suspend_wakeup_condition()) { + usbWakeupHost(&USB_DRIVER); +# if USB_SUSPEND_WAKEUP_DELAY > 0 + // Some hubs, kvm switches, and monitors do + // weird things, with USB device state bouncing + // around wildly on wakeup, yielding race + // conditions that can corrupt the keyboard state. + // + // Pause for a while to let things settle... + wait_ms(USB_SUSPEND_WAKEUP_DELAY); +# endif + } +# if !defined(USB_REMOTE_USE_QMK) && USB_POWER_DOWN_DELAY + suspend_wakeup_init(); +# endif + } +} + +bool process_action_kb(keyrecord_t *record) { + + (void)record; + if (get_transport() == TRANSPORT_USB){ + usb_remote_host(); + } + + return true; +} +#endif diff --git a/linker/wireless/transport.h b/linker/wireless/transport.h new file mode 100644 index 0000000..e6ff663 --- /dev/null +++ b/linker/wireless/transport.h @@ -0,0 +1,18 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +typedef enum { + TRANSPORT_NONE, + TRANSPORT_USB, + TRANSPORT_WLS, +} transport_t; + +void wls_transport_enable(bool enable); +void usb_transport_enable(bool enable); +void set_transport(transport_t new_transport); +transport_t get_transport(void); +void usb_power_connect(void); +void usb_power_disconnect(void); +void usb_remote_wakeup(void); diff --git a/linker/wireless/wireless.c b/linker/wireless/wireless.c new file mode 100644 index 0000000..0a52cbb --- /dev/null +++ b/linker/wireless/wireless.c @@ -0,0 +1,306 @@ + +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "wireless.h" + +#ifndef WLS_INQUIRY_BAT_TIME +# define WLS_INQUIRY_BAT_TIME 3000 +#endif + +static uint8_t wls_devs = DEVS_USB; +bool im_test_rate_flag; + +void last_matrix_activity_trigger(void); + +uint8_t wireless_keyboard_leds(void); +void wireless_send_keyboard(report_keyboard_t *report); +void wireless_send_nkro(report_nkro_t *report); +void wireless_send_mouse(report_mouse_t *report); +void wireless_send_extra(report_extra_t *report); + +host_driver_t wireless_driver = { + .keyboard_leds = wireless_keyboard_leds, + .send_keyboard = wireless_send_keyboard, + .send_nkro = wireless_send_nkro, + .send_mouse = wireless_send_mouse, + .send_extra = wireless_send_extra, +}; + +void wireless_init(void) { + + md_init(); +} + +uint8_t wireless_keyboard_leds(void) { + + if (*md_getp_state() == MD_STATE_CONNECTED) { + return *md_getp_indicator(); + } + + return 0; +} + +void wireless_send_keyboard(report_keyboard_t *report) { + if(MD_STATE_PAIRING == *md_getp_state()){ + return; + } + uint8_t wls_report_kb[MD_SND_CMD_KB_LEN] = {0}; + + if (*md_getp_state() != MD_STATE_CONNECTED) { + wireless_devs_change(wls_devs, wls_devs, false); + return; + } + + if (report != NULL) { + memcpy(wls_report_kb, (uint8_t *)report, sizeof(wls_report_kb)); + } + md_send_kb(wls_report_kb); +} + +void wireless_send_nkro(report_nkro_t *report) { + static report_keyboard_t temp_report_keyboard = {0}; + uint8_t wls_report_nkro[MD_SND_CMD_NKRO_LEN] = {0}; + + if(MD_STATE_PAIRING == *md_getp_state()){ + return; + } + + if (*md_getp_state() != MD_STATE_CONNECTED) { + wireless_devs_change(wls_devs, wls_devs, false); + return; + } + + if (report != NULL) { + report_nkro_t temp_report_nkro = *report; + uint8_t key_count = 0; + + temp_report_keyboard.mods = temp_report_nkro.mods; + for (uint8_t i = 0; i < NKRO_REPORT_BITS; i++) { + key_count += __builtin_popcount(temp_report_nkro.bits[i]); + } + + // find key up and del it. + for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS && temp_report_keyboard.keys[i]; i++) { + uint8_t usageid = 0x00; + uint8_t n; + + for (uint8_t c = 0; c < key_count; c++) { + for (n = 0; n < NKRO_REPORT_BITS && !temp_report_nkro.bits[n]; n++) {} + usageid = (n << 3) | biton(temp_report_nkro.bits[n]); +#ifdef NKRO_ENABLE + del_key_bit(&temp_report_nkro, usageid); +#endif + if (usageid == temp_report_keyboard.keys[i]) { + break; + } + } + + if (usageid != temp_report_keyboard.keys[i]) { + temp_report_keyboard.keys[i] = 0x00; + } + } + + /* + * Use NKRO for sending when more than 6 keys are pressed + * to solve the issue of the lack of a protocol flag in wireless mode. + */ + + temp_report_nkro = *report; + + for (uint8_t i = 0; i < key_count; i++) { + uint8_t usageid; + uint8_t idx, n = 0; + + for (n = 0; n < NKRO_REPORT_BITS && !temp_report_nkro.bits[n]; n++) {} + usageid = (n << 3) | biton(temp_report_nkro.bits[n]); +#ifdef NKRO_ENABLE + del_key_bit(&temp_report_nkro, usageid); +#endif + + for (idx = 0; idx < KEYBOARD_REPORT_KEYS; idx++) { + if (temp_report_keyboard.keys[idx] == usageid) { + break; + } + if (temp_report_keyboard.keys[idx] == 0x00) { + temp_report_keyboard.keys[idx] = usageid; + break; + } + } + + if (idx == KEYBOARD_REPORT_KEYS && (usageid < (MD_SND_CMD_NKRO_LEN * 8))) { + wls_report_nkro[usageid / 8] |= 0x01 << (usageid % 8); + } + } + } else { + memset(&temp_report_keyboard, 0, sizeof(temp_report_keyboard)); + } + + // wireless_driver.send_keyboard(&temp_report_keyboard); + while(smsg_is_busy()) wireless_task(); + host_keyboard_send(&temp_report_keyboard); + md_send_nkro(wls_report_nkro); +} + +void wireless_send_mouse(report_mouse_t *report) { + + if(MD_STATE_PAIRING == *md_getp_state()){ + return; + } + + typedef struct { + uint8_t buttons; + int8_t x; + int8_t y; + int8_t z; + int8_t h; + } __attribute__((packed)) wls_report_mouse_t; + + wls_report_mouse_t wls_report_mouse = {0}; + + if (*md_getp_state() != MD_STATE_CONNECTED) { + wireless_devs_change(wls_devs, wls_devs, false); + return; + } + + if (report != NULL) { + wls_report_mouse.buttons = report->buttons; + wls_report_mouse.x = report->x; + wls_report_mouse.y = report->y; + wls_report_mouse.z = report->h; + wls_report_mouse.h = report->v; + } + + md_send_mouse((uint8_t *)&wls_report_mouse); +} + +void wireless_send_extra(report_extra_t *report) { + if(MD_STATE_PAIRING == *md_getp_state()){ + return; + } + + uint16_t usage = 0; + + if (*md_getp_state() != MD_STATE_CONNECTED) { + wireless_devs_change(wls_devs, wls_devs, false); + return; + } + + if (report != NULL) { + usage = report->usage; + + switch (usage) { + case 0x81: + case 0x82: + case 0x83: { // system usage + usage = 0x01 << (usage - 0x81); + md_send_system((uint8_t *)&usage); + } break; + default: { + md_send_consumer((uint8_t *)&usage); + } break; + } + } +} + +void wireless_devs_change_user(uint8_t old_devs, uint8_t new_devs, bool reset) __attribute__((weak)); +void wireless_devs_change_user(uint8_t old_devs, uint8_t new_devs, bool reset) {} + +void wireless_devs_change_kb(uint8_t old_devs, uint8_t new_devs, bool reset) __attribute__((weak)); +void wireless_devs_change_kb(uint8_t old_devs, uint8_t new_devs, bool reset) {} + +void wireless_devs_change(uint8_t old_devs, uint8_t new_devs, bool reset) { + bool changed = (old_devs == DEVS_USB) ? (new_devs != DEVS_USB) : (new_devs == DEVS_USB); + + if (changed) { + set_transport((new_devs != DEVS_USB) ? TRANSPORT_WLS : TRANSPORT_USB); + } + + if ((wls_devs != new_devs) || reset) { + *md_getp_state() = MD_STATE_DISCONNECTED; + *md_getp_indicator() = 0; + } + + wls_devs = new_devs; + last_matrix_activity_trigger(); + + md_devs_change(new_devs, reset); + wireless_devs_change_kb(old_devs, new_devs, reset); + wireless_devs_change_user(old_devs, new_devs, reset); +} + +uint8_t wireless_get_current_devs(void) { + return wls_devs; +} + +void usb_mode_test_report_task(void) { + extern void host_mouse_send(report_mouse_t * report); + + static uint8_t flip = 0; + static report_mouse_t mouse_format = {0}; + + switch (flip) { + case 0: { + mouse_format.x = 10; + mouse_format.y = 0; + host_mouse_send(&mouse_format); + flip = 1; + } break; + case 1: { + mouse_format.x = 0; + mouse_format.y = -10; + host_mouse_send(&mouse_format); + flip = 2; + } break; + case 2: { + mouse_format.x = -10; + mouse_format.y = 0; + host_mouse_send(&mouse_format); + flip = 3; + } break; + case 3: { + mouse_format.x = 0; + mouse_format.y = 10; + host_mouse_send(&mouse_format); + flip = 0; + } break; + default: { + flip = 0; + } break; + } +} + +void wireless_pre_task(void) __attribute__((weak)); +void wireless_pre_task(void) {} + +void wireless_post_task(void) __attribute__((weak)); +void wireless_post_task(void) {} + +void wireless_task(void) { + + wireless_pre_task(); + lpwr_task(); + md_main_task(); + wireless_post_task(); + + /* usb_remote_wakeup() should be invoked last so that we have chance + * to switch to wireless after start-up when usb is not connected + */ + if (get_transport() == TRANSPORT_USB) { + usb_remote_wakeup(); + } else if (lpwr_get_state() == LPWR_NORMAL) { + static uint32_t inqtimer = 0x00; + + if (sync_timer_elapsed32(inqtimer) >= (WLS_INQUIRY_BAT_TIME)) { + if (md_inquire_bat()) { + inqtimer = sync_timer_read32(); + } + } + } +} + +void housekeeping_task_kb(void) { + if (wireless_get_current_devs() == DEVS_USB && im_test_rate_flag) usb_mode_test_report_task(); + wireless_task(); +} \ No newline at end of file diff --git a/linker/wireless/wireless.h b/linker/wireless/wireless.h new file mode 100644 index 0000000..606b6f8 --- /dev/null +++ b/linker/wireless/wireless.h @@ -0,0 +1,16 @@ +// Copyright 2024 Su (@isuua) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "transport.h" +#include "lowpower.h" +#include "module.h" +#include "smsg.h" + +void wireless_init(void); +void wireless_devs_change(uint8_t old_devs, uint8_t new_devs, bool reset); +uint8_t wireless_get_current_devs(void); +void wireless_pre_task(void); +void wireless_post_task(void); +void wireless_task(void); diff --git a/linker/wireless/wireless.mk b/linker/wireless/wireless.mk new file mode 100644 index 0000000..b84c103 --- /dev/null +++ b/linker/wireless/wireless.mk @@ -0,0 +1,27 @@ +WIRELESS_ENABLE ?= yes +WIRELESS_DIR = $(TOP_DIR)/keyboards/$(KEYBOARD)/linker/wireless + +ifeq ($(strip $(WIRELESS_ENABLE)), yes) + OPT_DEFS += -DWIRELESS_ENABLE -DNO_USB_STARTUP_CHECK + + OPT_DEFS += -include $(WIRELESS_DIR)/md_raw.h + + UART_DRIVER_REQUIRED ?= yes + WIRELESS_LPWR_STOP_ENABLE ?= yes + + VPATH += $(WIRELESS_DIR) + + SRC += \ + $(WIRELESS_DIR)/wireless.c \ + $(WIRELESS_DIR)/transport.c \ + $(WIRELESS_DIR)/lowpower.c \ + $(WIRELESS_DIR)/md_raw.c \ + $(WIRELESS_DIR)/smsg.c \ + $(WIRELESS_DIR)/rgb_matrix_blink.c \ + $(WIRELESS_DIR)/module.c + + ifeq ($(strip $(WIRELESS_LPWR_STOP_ENABLE)), yes) + OPT_DEFS += -DWIRELESS_LPWR_STOP_ENABLE + SRC += $(WIRELESS_DIR)/lpwr_wb32.c + endif +endif diff --git a/post_rules.mk b/post_rules.mk index cc78b9e..bf8832e 100644 --- a/post_rules.mk +++ b/post_rules.mk @@ -1,4 +1,4 @@ RGB_MATRIX_CUSTOM_USER = yes -include keyboards/leo/epomaker_split65/rgb_record/rgb_record.mk -include keyboards/leo/epomaker_split65/wls/wls.mk -include keyboards/linker/wireless/wireless.mk +include keyboards/$(KEYBOARD)/rgb_record/rgb_record.mk +include keyboards/$(KEYBOARD)/wls/wls.mk +include keyboards/$(KEYBOARD)/linker/wireless/wireless.mk diff --git a/readme.md b/readme.md index 7aebe40..b8ec5df 100644 --- a/readme.md +++ b/readme.md @@ -4,19 +4,25 @@ * Hardware Supported: EPOMAKER Split65 * Hardware Availability: EPOMAKER Split65 +Put this repo in the `keyboards/epomaker` directory. + + git clone https://github.com/gwangyi/Split65 $(qmk env QMK_HOME)/keyboards/epomaker/split65 + Make example for this keyboard (after setting up your build environment): - make leo/epomaker_split65:default + qmk compile -kb epomaker/split65 -km via Flashing example for this keyboard: - make leo/epomaker_split65:default + qmk flash -kb epomaker/split65 -km via To reset the board into bootloader mode, do one of the following: -* Hold the Reset switch mounted on the bottom side of the PCB while connecting the USB cable -* Hold the Escape key while connecting the USB cable (also erases persistent settings) -* Fn+R_Shift+Esc will reset the board to bootloader mode if you have flashed the default QMK keymap +* Hold the Escape key while connecting the USB cable to the left half (it might erase persistent settings) +* Move the switch behind of RShift key (you should remove the keycap) lower position. Remove both the RSpace keycap and switch. Poke two holes just beside of the big hole with a tweezer or paper clip while connecting the USB cable to the right half. + - After flashing this firmware, you can do this by holding Right arrow key instead of poking the holes. + - **NOTE**: Don't forget making switch back! It won't work unless the switch is in the correct place. + ![Howto](https://github.com/gwangyi/Split65/raw/main/howto.jpg) See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). @@ -24,7 +30,8 @@ See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_to Enter the bootloader in 3 ways: -* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard +* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard. + Note that Escape key of this keyboard (EPOMAKER Split65) has (1, 0) matrix key. * **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead * **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available diff --git a/rgb_record.c b/rgb_record/rgb_record.c similarity index 91% rename from rgb_record.c rename to rgb_record/rgb_record.c index d0cf96a..249d3f3 100644 --- a/rgb_record.c +++ b/rgb_record/rgb_record.c @@ -4,6 +4,7 @@ #include "rgb_record.h" #include "rgb_matrix.h" #include "eeprom.h" +#include "quantum/nvm/nvm_eeconfig.h" #define RGBREC_STATE_ON 1 #define RGBREC_STATE_OFF 0 @@ -121,14 +122,14 @@ bool rgbrec_start(uint8_t channel) { } void rgbrec_update_current_channel(uint8_t channel) { - uint32_t addr = 0; + uint32_t offset = 0; if (channel >= RGBREC_CHANNEL_NUM) { return; } - addr = (uint32_t)(RGBREC_EECONFIG_ADDR) + (channel * sizeof(rgbrec_buffer)); - eeprom_update_block(rgbrec_buffer, (void *)addr, sizeof(rgbrec_buffer)); + offset = (uint32_t)(RGBREC_EECONFIG_OFFSET) + (channel * sizeof(rgbrec_buffer)); + nvm_eeconfig_update_user_datablock(rgbrec_buffer, offset, sizeof(rgbrec_buffer)); } bool rgbrec_end(uint8_t channel) { @@ -185,15 +186,15 @@ void rgbrec_set_close_all(uint8_t h, uint8_t s, uint8_t v) { } void rgbrec_read_current_channel(uint8_t channel) { - uint32_t addr = 0; + uint32_t offset = 0; if (channel >= RGBREC_CHANNEL_NUM) { return; } - addr = (uint32_t)(RGBREC_EECONFIG_ADDR) + (channel * sizeof(rgbrec_buffer)); - eeprom_read_block(rgbrec_buffer, (void *)addr, sizeof(rgbrec_buffer)); + offset = (uint32_t)(RGBREC_EECONFIG_OFFSET) + (channel * sizeof(rgbrec_buffer)); + nvm_eeconfig_read_user_datablock(rgbrec_buffer, offset, sizeof(rgbrec_buffer)); } bool rgbrec_is_started(void) { @@ -265,8 +266,9 @@ void record_rgbmatrix_increase(uint8_t *last_mode) { uint8_t record_color_read_data(void) { uint8_t hs_mode = find_index(); - const uint8_t *ptr = (const uint8_t *)(((uint32_t)CONFINFO_EECONFIG_ADDR + 4) + hs_mode); - uint8_t hs_c = eeprom_read_byte(ptr); + const uint32_t offset = (((uint32_t)CONFINFO_EECONFIG_OFFSET + 4) + hs_mode); + uint8_t hs_c; + nvm_eeconfig_read_user_datablock(&hs_c, offset, 1); if (hs_c > RGB_HSV_MAX) { return 0; @@ -302,8 +304,8 @@ uint8_t record_color_hsv(bool status) { rgb_matrix_sethsv(rgb_hsvs[rgb_hsv_index][0], rgb_hsvs[rgb_hsv_index][1], rgb_matrix_get_val()); - uint8_t *ptr = (uint8_t *)(((uint32_t)CONFINFO_EECONFIG_ADDR + 4) + find_index()); - eeprom_write_byte(ptr, rgb_hsv_index); + uint32_t offset = ((uint32_t)CONFINFO_EECONFIG_OFFSET + 4) + find_index(); + nvm_eeconfig_update_user_datablock(&rgb_hsv_index, offset, 1); return rgb_hsv_index; } @@ -318,6 +320,7 @@ void query(void) { #else rgb_matrix_set_color_all(0x00, 0x00, 0x00); #endif +#ifdef WIRELESS_ENABLE for (uint8_t i = 0; i < 10; i++) { uint8_t mi_index[10] = RGB_MATRIX_BAT_INDEX_MAP; if ((i < (*md_getp_bat() / 10)) || (i < 1)) { @@ -332,5 +335,6 @@ void query(void) { rgb_matrix_set_color(mi_index[i], 0x00, 0x00, 0x00); } } +#endif } } diff --git a/rgb_record.h b/rgb_record/rgb_record.h similarity index 98% rename from rgb_record.h rename to rgb_record/rgb_record.h index acb01fb..5e3b8b0 100644 --- a/rgb_record.h +++ b/rgb_record/rgb_record.h @@ -24,7 +24,9 @@ #include "color.h" #include "eeprom.h" #include "quantum.h" +#ifdef WIRELESS_ENABLE #include "wireless.h" +#endif #define HS_GET_H(value) ((uint8_t)(value >> 8)) #define HS_GET_S(value) ((uint8_t)(value & 0xFF)) diff --git a/rgb_record.mk b/rgb_record/rgb_record.mk similarity index 100% rename from rgb_record.mk rename to rgb_record/rgb_record.mk diff --git a/epomaker_split65.c b/split65.c similarity index 98% rename from epomaker_split65.c rename to split65.c index ef436cf..c5ea81f 100644 --- a/epomaker_split65.c +++ b/split65.c @@ -2,11 +2,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include QMK_KEYBOARD_H -#include "wls/wls.h" #include "rgb_record/rgb_record.h" #include "quantum.h" #include "serial_usart.h" #ifdef WIRELESS_ENABLE +# include "wls/wls.h" # include "wireless.h" # include "usb_main.h" # include "lowpower.h" @@ -199,7 +199,9 @@ void keyboard_post_init_kb(void) { start_hsv = rgb_matrix_get_hsv(); +#ifdef WIRELESS_ENABLE pov = *md_getp_bat(); +#endif // usart_init(); transaction_register_rpc(USER_SYNC_MMS, user_sync_mms_slave_handler); } @@ -255,7 +257,7 @@ bool lpwr_is_allow_timeout_hook(void) { return false; } - return true; + return false; // TODO: figure out why sleep/wakeup doesn't working } void wireless_post_task(void) { @@ -391,9 +393,11 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { rgb_matrix_set_color_all(0x00, 0x00, 0x00); } +#ifdef WIRELESS_ENABLE if (*md_getp_state() == MD_STATE_CONNECTED) { hs_rgb_blink_set_timer(timer_read32()); } +#endif switch (keycode) { case MO(_FL): @@ -407,7 +411,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } break; } - + case RGB_MOD: break; default: { @@ -518,7 +522,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { register_code(KC_LCTL); register_code(KC_Z); - } + } else{ unregister_code(KC_LCTL); unregister_code(KC_Z); @@ -528,7 +532,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { register_code(KC_LCTL); register_code(KC_X); - } + } else{ unregister_code(KC_LCTL); unregister_code(KC_X); @@ -538,7 +542,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { register_code(KC_LCTL); register_code(KC_C); - } + } else{ unregister_code(KC_LCTL); unregister_code(KC_C); @@ -548,7 +552,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { register_code(KC_LCTL); register_code(KC_V); - } + } else{ unregister_code(KC_LCTL); unregister_code(KC_V); @@ -583,7 +587,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { case KC_F3:{ if(confinfo.filp){ if (keymap_is_mac_system()) { - + if (record->event.pressed) { register_code16(KC_VOLU); } else { @@ -649,7 +653,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { case KC_F8:{ if(confinfo.filp){ if (keymap_is_mac_system()) { - + if (record->event.pressed) { register_code16(KC_MNXT); } else { @@ -663,7 +667,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { case KC_F9:{ if(confinfo.filp){ if (keymap_is_mac_system()) { - + if (record->event.pressed) { register_code16(KC_MAIL); } else { @@ -677,7 +681,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { case KC_F10:{ if(confinfo.filp){ if (keymap_is_mac_system()) { - + if (record->event.pressed) { register_code16(KC_WHOM); } else { @@ -691,7 +695,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { case KC_F11:{ if(confinfo.filp){ if (keymap_is_mac_system()) { - + if (record->event.pressed) { register_code16(KC_CALC); } else { @@ -705,7 +709,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { case KC_F12:{ if(confinfo.filp){ if (keymap_is_mac_system()) { - + if (record->event.pressed) { register_code16(KC_WSCH); } else { @@ -822,7 +826,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { rgb_matrix_decrease_val(); } - + } return false; } @@ -988,12 +992,12 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { } break; case KC_BATQ:{ if (record->event.pressed) { - + im_bat_req_charging_flag = true; } else{ im_bat_req_charging_flag = false; - + } }break; case QK_BOOT: { @@ -1071,7 +1075,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { } } } break; - + case TO(_BL): { if (record->event.pressed) { rgb_matrix_hs_set_remain_time(HS_RGB_BLINK_INDEX_MAC, 0); @@ -1096,7 +1100,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { return false; } break; - + case RGB_MOD: { if(record->event.pressed){ uint8_t mode = rgb_matrix_get_mode(); @@ -1135,11 +1139,13 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { return true; } break; +#ifdef WIRELESS_ENABLE case HS_BATQ: { extern bool rk_bat_req_flag; rk_bat_req_flag = (confinfo.devs != DEVS_USB) && record->event.pressed; return false; } break; +#endif default: break; @@ -1149,6 +1155,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { } void housekeeping_task_user(void) { // loop +#ifdef WIRELESS_ENABLE uint8_t hs_now_mode; static uint32_t hs_current_time; @@ -1170,13 +1177,16 @@ void housekeeping_task_user(void) { // loop md_send_devctrl(hs_now_mode); md_send_devctrl(MD_SND_CMD_DEVCTRL_INQVOL); } +#endif if (is_keyboard_master()) { static uint32_t last_sync = 0; if (timer_elapsed32(last_sync) > 2000) { last_sync = timer_read32(); +#ifdef WIRELESS_ENABLE pov = *md_getp_bat(); master_sync_mms_slave(wireless_get_current_devs(), wireless_get_current_devs(), pov); +#endif } } } @@ -1488,7 +1498,7 @@ bool rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) { if (host_keyboard_led_state().caps_lock) rgb_matrix_set_color(HS_RGB_INDEX_CAPS, 0x20, 0x20, 0x20); - + if (!keymap_is_mac_system() && keymap_config.no_gui) rgb_matrix_set_color(HS_RGB_INDEX_WIN_LOCK, 0x20, 0x20, 0x20); @@ -1547,11 +1557,11 @@ void hs_reset_settings(void) { rgblight_enable(); #endif - keymap_config.raw = eeconfig_read_keymap(); + eeconfig_read_keymap(&keymap_config); #if defined(NKRO_ENABLE) && defined(FORCE_NKRO) keymap_config.nkro = 0; - eeconfig_update_keymap(keymap_config.raw); + eeconfig_update_keymap(&keymap_config); #endif // #if defined(WIRELESS_ENABLE) @@ -1562,12 +1572,16 @@ void hs_reset_settings(void) { return; } +#ifdef WIRELESS_ENABLE hs_rgb_blink_set_timer(timer_read32()); +#endif keyboard_post_init_kb(); } void lpwr_wakeup_hook(void) { +#ifdef WIRELESS_ENABLE hs_mode_scan(false, confinfo.devs, confinfo.last_btdevs); +#endif if (rgb_matrix_get_val() != 0){ gpio_write_pin_high(LED_POWER_EN_PIN); @@ -1586,7 +1600,9 @@ void user_sync_mms_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t switch(m2s->cmd) { case 0x55: //sync multimode +#ifdef WIRELESS_ENABLE wireless_devs_change(m2s->body[0], m2s->body[1], false); +#endif s2m->resp = 0x00; break; case 0xDD: @@ -1595,4 +1611,4 @@ void user_sync_mms_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t break; default :break; } -} \ No newline at end of file +} diff --git a/via.json b/via.json new file mode 100644 index 0000000..3b2981c --- /dev/null +++ b/via.json @@ -0,0 +1,271 @@ +{ + "name": "EPOMAKER Split65", + "vendorId": "0x342d", + "productId": "0xe4c6", + "keycodes": ["qmk_lighting"], + "menus": [ + { + "label": "Lighting", + "content": [ + { + "label": "Backlight", + "content": [ + { + "label": "Brightness", + "type": "range", + "options": [0, 255], + "content": ["id_qmk_rgb_matrix_brightness", 3, 1] + }, + { + "label": "Effect", + "type": "dropdown", + "content": ["id_qmk_rgb_matrix_effect", 3, 2], + "options": [ + ["All Off", 0], + ["Solid Color", 1], + ["Alphas Mods", 2], + ["Gradient Up Down", 3], + ["Gradient Left Right", 4], + ["Breathing", 5], + ["Band Sat", 6], + ["Band Val", 7], + ["Band Pinwheel Sat", 8], + ["Band Pinwheel Val", 9], + ["Band Spiral Sat", 10], + ["Band Spiral Val", 11], + ["Cycle All", 12], + ["Cycle Left Right", 13], + ["Cycle Up Down", 14], + ["Rainbow Moving Chevron", 15], + ["Cycle Out In", 16], + ["Cycle Out In Dual", 17], + ["Cycle Pinwheel", 18], + ["Cycle Spiral", 19], + ["Dual Beacon", 20], + ["Rainbow Beacon", 21], + ["Rainbow Pinwheels", 22], + ["Raindrops", 23], + ["Jellybean Raindrops", 24], + ["Hue Breathing", 25], + ["Hue Pendulum", 26], + ["Hue Wave", 27], + ["Pixel Rain", 28], + ["Pixel Flow", 29], + ["Pixel Fractal", 30], + ["Typing Heatmap", 31], + ["Digital Rain", 32], + ["Solid Reactive Simple", 33], + ["Solid Reactive", 34], + ["Solid Reactive Wide", 35], + ["Solid Reactive Multiwide", 36], + ["Solid Reactive Cross", 37], + ["Solid Reactive Multicross", 38], + ["Solid Reactive Nexus", 39], + ["Solid Reactive Multinexus", 40], + ["Splash", 41], + ["Multisplash", 42], + ["Solid Splash", 43], + ["Solid Multisplash", 44], + ["Close All", 45] + ] + }, + { + "showIf": "{id_qmk_rgb_matrix_effect} != 0", + "label": "Effect Speed", + "type": "range", + "options": [0, 255], + "content": ["id_qmk_rgb_matrix_effect_speed", 3, 3] + }, + { + "showIf": "{id_qmk_rgb_matrix_effect} != 0 && {id_qmk_rgb_matrix_effect} != 24 && {id_qmk_rgb_matrix_effect} != 28 && {id_qmk_rgb_matrix_effect} != 29 && {id_qmk_rgb_matrix_effect} != 32", + "label": "Color", + "type": "color", + "content": ["id_qmk_rgb_matrix_color", 3, 4] + } + ] + } + ] + } + ], + "matrix": {"rows": 12, "cols": 9}, + "customKeycodes": [ + {"name": "BT DEV1","title": "BT Device 1","shortName": "DEV1"}, + {"name": "BT DEV2","title": "BT Device 2","shortName": "DEV2"}, + {"name": "BT DEV3","title": "BT Device 3","shortName": "DEV3"}, + {"name": "2.4G","title": "2.4G","shortName": "DEV 2.4G"}, + {"name": "RL_MOD","title": "RL_MOD","shortName": "RL_MOD"}, + {"name": "Batt Lvl", "title": "Battery Level", "shortName": "BatLv"}, + {"name": "Fn Flip", "title": "Swap F-row and Num-row", "shortName": "FnFlp"}, + {"name": "Batt Ind", "title": "Battery Indicator", "shortName": "BatInd"} + ], + "layouts": { + "keymap": + [ + [ + { + "c": "#777777" + }, + "1,0", + { + "c": "#cccccc" + }, + "1,1", + "1,2", + "1,3", + "1,4", + "1,5", + "1,6", + "7,0", + "7,1", + "7,2", + "7,3", + "7,4", + "7,5", + { + "c": "#aaaaaa", + "w": 2 + }, + "7,7", + { + "x": 0.25, + "c": "#cccccc" + }, + "7,8\n\n\n\n\n\n\n\n\ne0" + ], + [ + { + "c": "#aaaaaa", + "w": 1.5 + }, + "2,0", + { + "c": "#cccccc" + }, + "2,1", + "2,2", + "2,3", + "2,4", + "2,5", + "8,0", + "8,1", + "8,2", + "8,3", + "8,4", + "8,5", + "8,6", + { + "w": 1.5 + }, + "8,7", + { + "x": 0.25 + }, + "8,8" + ], + [ + { + "c": "#aaaaaa", + "w": 1.75 + }, + "3,0", + { + "c": "#cccccc" + }, + "3,1", + "3,2", + "3,3", + "3,4", + "3,5", + "9,0", + "9,1", + "9,2", + "9,3", + "9,4", + "9,5", + { + "c": "#777777", + "w": 2.25 + }, + "9,7", + { + "x": 0.25, + "c": "#cccccc" + }, + "9,8" + ], + [ + { + "c": "#aaaaaa", + "w": 2.25 + }, + "4,0", + { + "c": "#cccccc" + }, + "4,1", + "4,2", + "4,3", + "4,4", + "4,5", + "10,0", + "10,1", + "10,2", + "10,3", + "10,4", + { + "c": "#aaaaaa", + "w": 1.75 + }, + "10,6", + { + "c": "#cccccc" + }, + "10,7", + { + "x": 0.25 + }, + "10,8" + ], + [ + { + "c": "#aaaaaa", + "w": 1.25 + }, + "5,0", + { + "w": 1.25 + }, + "5,1", + { + "w": 1.25 + }, + "5,2", + { + "c": "#cccccc", + "w": 3 + }, + "5,5", + { + "w": 3 + }, + "11,1", + { + "c": "#aaaaaa" + }, + "11,3", + "11,4", + "11,5", + "11,6", + { + "w": 1.25 + }, + "11,7", + { + "x": 0.25, + "c": "#cccccc" + }, + "11,8" + ] + ] + } +} diff --git a/wls b/wls deleted file mode 100644 index 8b13789..0000000 --- a/wls +++ /dev/null @@ -1 +0,0 @@ - diff --git a/wls.mk b/wls.mk deleted file mode 100644 index fe053a4..0000000 --- a/wls.mk +++ /dev/null @@ -1 +0,0 @@ -SRC += wls/wls.c diff --git a/wls.c b/wls/wls.c similarity index 100% rename from wls.c rename to wls/wls.c diff --git a/wls.h b/wls/wls.h similarity index 100% rename from wls.h rename to wls/wls.h diff --git a/wls/wls.mk b/wls/wls.mk new file mode 100644 index 0000000..dcaaf0d --- /dev/null +++ b/wls/wls.mk @@ -0,0 +1,4 @@ +WIRELESS_ENABLE ?= yes +ifeq ($(strip $(WIRELESS_ENABLE)), yes) +SRC += wls/wls.c +endif