From 7a48809103d67a9f7c89a000f20c87a992951ef8 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 Dec 2024 02:17:26 +0200 Subject: [PATCH 1/4] Rockfall 3 keyboard support added --- .../rockfall3/common/wireless/lowpower.c | 324 ++++++++ .../rockfall3/common/wireless/lowpower.h | 52 ++ .../rockfall3/common/wireless/lpwr_wb32.c | 222 ++++++ .../hator/rockfall3/common/wireless/md_raw.c | 43 ++ .../hator/rockfall3/common/wireless/md_raw.h | 23 + .../hator/rockfall3/common/wireless/module.c | 543 ++++++++++++++ .../hator/rockfall3/common/wireless/module.h | 135 ++++ .../hator/rockfall3/common/wireless/smsg.c | 135 ++++ .../hator/rockfall3/common/wireless/smsg.h | 35 + .../rockfall3/common/wireless/transport.c | 180 +++++ .../rockfall3/common/wireless/transport.h | 31 + .../rockfall3/common/wireless/wireless.c | 278 +++++++ .../rockfall3/common/wireless/wireless.h | 27 + .../rockfall3/common/wireless/wireless.mk | 26 + keyboards/hator/rockfall3/htk850/config.h | 57 ++ keyboards/hator/rockfall3/htk850/halconf.h | 24 + keyboards/hator/rockfall3/htk850/htk850.c | 690 ++++++++++++++++++ .../hator/rockfall3/htk850/keyboard.json | 288 ++++++++ .../rockfall3/htk850/keymaps/default/keymap.c | 69 ++ keyboards/hator/rockfall3/htk850/mcuconf.h | 48 ++ keyboards/hator/rockfall3/htk850/readme.md | 25 + keyboards/hator/rockfall3/htk850/rules.mk | 1 + 22 files changed, 3256 insertions(+) create mode 100644 keyboards/hator/rockfall3/common/wireless/lowpower.c create mode 100644 keyboards/hator/rockfall3/common/wireless/lowpower.h create mode 100644 keyboards/hator/rockfall3/common/wireless/lpwr_wb32.c create mode 100644 keyboards/hator/rockfall3/common/wireless/md_raw.c create mode 100644 keyboards/hator/rockfall3/common/wireless/md_raw.h create mode 100644 keyboards/hator/rockfall3/common/wireless/module.c create mode 100644 keyboards/hator/rockfall3/common/wireless/module.h create mode 100644 keyboards/hator/rockfall3/common/wireless/smsg.c create mode 100644 keyboards/hator/rockfall3/common/wireless/smsg.h create mode 100644 keyboards/hator/rockfall3/common/wireless/transport.c create mode 100644 keyboards/hator/rockfall3/common/wireless/transport.h create mode 100644 keyboards/hator/rockfall3/common/wireless/wireless.c create mode 100644 keyboards/hator/rockfall3/common/wireless/wireless.h create mode 100644 keyboards/hator/rockfall3/common/wireless/wireless.mk create mode 100644 keyboards/hator/rockfall3/htk850/config.h create mode 100644 keyboards/hator/rockfall3/htk850/halconf.h create mode 100644 keyboards/hator/rockfall3/htk850/htk850.c create mode 100644 keyboards/hator/rockfall3/htk850/keyboard.json create mode 100644 keyboards/hator/rockfall3/htk850/keymaps/default/keymap.c create mode 100644 keyboards/hator/rockfall3/htk850/mcuconf.h create mode 100644 keyboards/hator/rockfall3/htk850/readme.md create mode 100644 keyboards/hator/rockfall3/htk850/rules.mk diff --git a/keyboards/hator/rockfall3/common/wireless/lowpower.c b/keyboards/hator/rockfall3/common/wireless/lowpower.c new file mode 100644 index 00000000000..962bd306a4a --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/lowpower.c @@ -0,0 +1,324 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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) { + 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) { + 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/keyboards/hator/rockfall3/common/wireless/lowpower.h b/keyboards/hator/rockfall3/common/wireless/lowpower.h new file mode 100644 index 00000000000..4c5a9f3d3df --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/lowpower.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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/keyboards/hator/rockfall3/common/wireless/lpwr_wb32.c b/keyboards/hator/rockfall3/common/wireless/lpwr_wb32.c new file mode 100644 index 00000000000..70f37740365 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/lpwr_wb32.c @@ -0,0 +1,222 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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_BOTH_EDGES); + } + } +#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_BOTH_EDGES); + } + } +#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(); + + 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 +#if WB32_GPT_USE_TIM1 || WB32_ICU_USE_TIM1 || WB32_PWM_USE_TIM1 + rccEnableTIM1(); +#endif +#if WB32_ST_USE_TIM2 || WB32_GPT_USE_TIM2 || WB32_ICU_USE_TIM2 || WB32_PWM_USE_TIM2 + rccEnableTIM2(); +#endif +#if WB32_ST_USE_TIM3 || WB32_GPT_USE_TIM3 || WB32_ICU_USE_TIM3 || WB32_PWM_USE_TIM3 + rccEnableTIM3(); +#endif +#if WB32_ST_USE_TIM4 || WB32_GPT_USE_TIM4 || WB32_ICU_USE_TIM4 || WB32_PWM_USE_TIM4 + rccEnableTIM4(); +#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/keyboards/hator/rockfall3/common/wireless/md_raw.c b/keyboards/hator/rockfall3/common/wireless/md_raw.c new file mode 100644 index 00000000000..d030f7b5d36 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/md_raw.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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/keyboards/hator/rockfall3/common/wireless/md_raw.h b/keyboards/hator/rockfall3/common/wireless/md_raw.h new file mode 100644 index 00000000000..6a1b2aa763b --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/md_raw.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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_461 replaced_hid_send // via.c diff --git a/keyboards/hator/rockfall3/common/wireless/module.c b/keyboards/hator/rockfall3/common/wireless/module.c new file mode 100644 index 00000000000..e8eb6d6a8a8 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/module.c @@ -0,0 +1,543 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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_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; + case MD_REV_CMD_RAW: { + md_rev_payload[data_count++] = data; + data_remain = 33; + } 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; + } + } + 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; + pdata = &md_rev_payload[1]; + + memcpy(md_raw_payload, pdata, 32); + md_receive_raw_cb(md_raw_payload, 32); + + } 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) { + if (md_send_pkt(md_pkt_payload, size)) { + smsg_timer = sync_timer_read32(); + smsg_set_state(smsg_state_busy); + } else { + smsg_set_state(smsg_state_replied); + } + } + } 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; +} + +bool md_send_pkt(uint8_t *data, uint32_t len) { + bool retval = true; + + if (!data || !len) { + return false; + } + + // switch (*data) { + // case MD_SND_CMD_RAW: { + // retval = false; + // } break; + // default: + // break; + // } + + // send + uart_transmit(data, len); + + return retval; +} + +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_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 + 2] = {0x00}; + + if (length != MD_RAW_SIZE) { + return; + } + + sdata[0] = MD_SND_CMD_RAW; + memcpy(&sdata[1], 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/keyboards/hator/rockfall3/common/wireless/module.h b/keyboards/hator/rockfall3/common/wireless/module.h new file mode 100644 index 00000000000..0a2763c3865 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/module.h @@ -0,0 +1,135 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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 = 0x91, + /* device ctrl */ + MD_SND_CMD_DEVCTRL = 0xA6, + 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 = 0x81, + 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, +}; + +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); +bool 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); diff --git a/keyboards/hator/rockfall3/common/wireless/smsg.c b/keyboards/hator/rockfall3/common/wireless/smsg.c new file mode 100644 index 00000000000..1d3db89bd32 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/smsg.c @@ -0,0 +1,135 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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/keyboards/hator/rockfall3/common/wireless/smsg.h b/keyboards/hator/rockfall3/common/wireless/smsg.h new file mode 100644 index 00000000000..9c252f865d4 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/smsg.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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/keyboards/hator/rockfall3/common/wireless/transport.c b/keyboards/hator/rockfall3/common/wireless/transport.c new file mode 100644 index 00000000000..128960cc1ac --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/transport.c @@ -0,0 +1,180 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "quantum.h" +#include "module.h" +#include "usb_main.h" +#include "transport.h" + +#ifndef USB_POWER_DOWN_DELAY +# define USB_POWER_DOWN_DELAY 3000 +#endif + +extern host_driver_t chibios_driver; +extern host_driver_t wireless_driver; + +static transport_t transport = TRANSPORT_USB; + +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(true); // 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) { + report_keyboard_t empty_report = {0}; + report_nkro_t empty_nkro_report = {0}; + host_keyboard_send(&empty_report); + host_nkro_send(&empty_nkro_report); + } + +#if !defined(KEEP_USB_CONNECTION_IN_WIRELESS_MODE) + usbStop(&USBD1); + usbDisconnectBus(&USBD1); + usb_power_disconnect(); +#endif + } +} + +void set_transport(transport_t new_transport) { + + transport = new_transport; + + switch (transport) { + case TRANSPORT_USB: { + usb_transport_enable(true); + wls_transport_enable(false); + } break; + case TRANSPORT_WLS: { + wls_transport_enable(true); + usb_transport_enable(false); + } break; + default: + break; + } +} + +transport_t get_transport(void) { + + return transport; +} + +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 + static uint32_t suspend_timer = 0x00; + + 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; + suspend_power_down(); + } + } 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/keyboards/hator/rockfall3/common/wireless/transport.h b/keyboards/hator/rockfall3/common/wireless/transport.h new file mode 100644 index 00000000000..ae3687e71bc --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/transport.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#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/keyboards/hator/rockfall3/common/wireless/wireless.c b/keyboards/hator/rockfall3/common/wireless/wireless.c new file mode 100644 index 00000000000..39f95d01731 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/wireless.c @@ -0,0 +1,278 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "quantum.h" +#include "wireless.h" + +#ifndef WLS_INQUIRY_BAT_TIME +# define WLS_INQUIRY_BAT_TIME 3000 +#endif + +#ifndef WLS_KEYBOARD_REPORT_KEYS +# define WLS_KEYBOARD_REPORT_KEYS KEYBOARD_REPORT_KEYS +#endif + +static uint8_t wls_devs = DEVS_USB; + +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) __attribute__((weak)); +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) __attribute__((weak)); +void wireless_send_keyboard(report_keyboard_t *report) { + 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; + } + + _Static_assert((MD_SND_CMD_KB_LEN) - (WLS_KEYBOARD_REPORT_KEYS) >= 2, "WLS_KEYBOARD_REPORT_KEYS cannot be greater than MD_SND_CMD_KB_LEN - 2."); + + if (report != NULL) { + memcpy(wls_report_kb, (uint8_t *)&report->mods, WLS_KEYBOARD_REPORT_KEYS + 2); + } + + md_send_kb(wls_report_kb); +} + +void wireless_send_nkro(report_nkro_t *report) __attribute__((weak)); +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}; + +#ifdef NKRO_ENABLE + 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. + uint8_t nkro_keys = key_count; + for (uint8_t i = 0; i < WLS_KEYBOARD_REPORT_KEYS && temp_report_keyboard.keys[i]; i++) { + report_nkro_t found_report_nkro; + uint8_t usageid = 0x00; + uint8_t n; + + found_report_nkro = temp_report_nkro; + + for (uint8_t c = 0; c < nkro_keys; c++) { + for (n = 0; n < NKRO_REPORT_BITS && !found_report_nkro.bits[n]; n++) {} + usageid = (n << 3) | biton(found_report_nkro.bits[n]); + del_key_bit(&found_report_nkro, usageid); + if (usageid == temp_report_keyboard.keys[i]) { + del_key_bit(&temp_report_nkro, usageid); + nkro_keys--; + 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]); + del_key_bit(&temp_report_nkro, usageid); + + for (idx = 0; idx < WLS_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 == WLS_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)); + } +#endif + + wireless_driver.send_keyboard(&temp_report_keyboard); + md_send_nkro(wls_report_nkro); +} + +void wireless_send_mouse(report_mouse_t *report) __attribute__((weak)); +void wireless_send_mouse(report_mouse_t *report) { + 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) __attribute__((weak)); +void wireless_send_extra(report_extra_t *report) { + 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 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) { + + wireless_task(); +} diff --git a/keyboards/hator/rockfall3/common/wireless/wireless.h b/keyboards/hator/rockfall3/common/wireless/wireless.h new file mode 100644 index 00000000000..5c0878ff3af --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/wireless.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "transport.h" +#include "lowpower.h" +#include "module.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); diff --git a/keyboards/hator/rockfall3/common/wireless/wireless.mk b/keyboards/hator/rockfall3/common/wireless/wireless.mk new file mode 100644 index 00000000000..c8395dfe959 --- /dev/null +++ b/keyboards/hator/rockfall3/common/wireless/wireless.mk @@ -0,0 +1,26 @@ +WIRELESS_ENABLE ?= yes +WIRELESS_DIR = $(TOP_DIR)/keyboards/hator/rockfall3/common/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)/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/keyboards/hator/rockfall3/htk850/config.h b/keyboards/hator/rockfall3/htk850/config.h new file mode 100644 index 00000000000..0a0539608d6 --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/config.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifdef WIRELESS_ENABLE +# define LPWR_TIMEOUT RGB_MATRIX_TIMEOUT +# define WLS_KEYBOARD_REPORT_KEYS 5 +# undef LPWR_TIMEOUT +# define LPWR_TIMEOUT 600000 // 10min + +#endif + +#define USB_POWER_EN_PIN A14 +#define LED_POWER_EN_PIN A15 + +# define BT_CABLE_PIN B8 // +# define BT_CHARGE_PIN B9 // + +# define BT_MODE_SW_PIN C10 // +# define RF_MODE_SW_PIN D2 // + +/* UART */ +#define UART_TX_PIN A9 +#define UART_RX_PIN A10 + +/* SPI Config for spi flash*/ +#define SPI_DRIVER SPIDQ +#define SPI_SCK_PIN B3 +#define SPI_MOSI_PIN B5 +#define SPI_MISO_PIN B4 +#define SPI_MOSI_PAL_MODE 5 + +#define EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN C12 +#define WEAR_LEVELING_LOGICAL_SIZE (WEAR_LEVELING_BACKING_SIZE / 2) + +/* I2C Config for LED Driver */ +#define SNLED27351_I2C_ADDRESS_1 0b1110100 +#define SNLED27351_I2C_ADDRESS_2 0b1110111 +#define I2C1_OPMODE OPMODE_I2C +#define I2C1_CLOCK_SPEED 400000 /* 400000 */ + +#define RGB_MATRIX_FRAMEBUFFER_EFFECTS +#define RGB_MATRIX_KEYPRESSES diff --git a/keyboards/hator/rockfall3/htk850/halconf.h b/keyboards/hator/rockfall3/htk850/halconf.h new file mode 100644 index 00000000000..8a89d3ced8d --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/halconf.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#define HAL_USE_I2C TRUE +#define HAL_USE_SERIAL TRUE +#define HAL_USE_SPI TRUE +#define PAL_USE_CALLBACKS TRUE + +#include_next diff --git a/keyboards/hator/rockfall3/htk850/htk850.c b/keyboards/hator/rockfall3/htk850/htk850.c new file mode 100644 index 00000000000..5608ed21297 --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/htk850.c @@ -0,0 +1,690 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include QMK_KEYBOARD_H + +#ifdef WIRELESS_ENABLE +# include "wireless.h" +#endif +#ifdef RGB_MATRIX_ENABLE +const snled27351_led_t PROGMEM g_snled27351_leds[SNLED27351_LED_COUNT] = { +/* Refer to IS31 manual for these locations + * driver + * | R location + * | | G location + * | | | B location + * | | | | */ + {1, CB1_CA1, CB2_CA1, CB3_CA1}, + {1, CB1_CA2, CB2_CA2, CB3_CA2}, + {1, CB1_CA3, CB2_CA3, CB3_CA3}, + {1, CB1_CA4, CB2_CA4, CB3_CA4}, + {1, CB1_CA5, CB2_CA5, CB3_CA5}, + {1, CB1_CA6, CB2_CA6, CB3_CA6}, + {1, CB1_CA7, CB2_CA7, CB3_CA7}, + {1, CB1_CA8, CB2_CA8, CB3_CA8}, + {1, CB1_CA9, CB2_CA9, CB3_CA9}, + {1, CB1_CA10, CB2_CA10, CB3_CA10}, + {1, CB1_CA11, CB2_CA11, CB3_CA11}, + {1, CB1_CA12, CB2_CA12, CB3_CA12}, + {1, CB1_CA13, CB2_CA13, CB3_CA13}, + {1, CB1_CA14, CB2_CA14, CB3_CA14}, + {1, CB1_CA15, CB2_CA15, CB3_CA15}, + {1, CB1_CA16, CB2_CA16, CB3_CA16}, + + {0, CB1_CA1, CB2_CA1, CB3_CA1}, + {0, CB1_CA2, CB2_CA2, CB3_CA2}, + {0, CB1_CA3, CB2_CA3, CB3_CA3}, + {0, CB1_CA4, CB2_CA4, CB3_CA4}, + {0, CB1_CA5, CB2_CA5, CB3_CA5}, + {0, CB1_CA6, CB2_CA6, CB3_CA6}, + {0, CB1_CA7, CB2_CA7, CB3_CA7}, + {0, CB1_CA8, CB2_CA8, CB3_CA8}, + {0, CB1_CA9, CB2_CA9, CB3_CA9}, + {0, CB1_CA10, CB2_CA10, CB3_CA10}, + {0, CB1_CA11, CB2_CA11, CB3_CA11}, + {0, CB1_CA12, CB2_CA12, CB3_CA12}, + {0, CB1_CA13, CB2_CA13, CB3_CA13}, + {0, CB1_CA14, CB2_CA14, CB3_CA14}, + {1, CB4_CA1, CB5_CA1, CB6_CA1}, + {1, CB4_CA3, CB5_CA3, CB6_CA3}, + {1, CB4_CA5, CB5_CA5, CB6_CA5}, + + {0, CB4_CA1, CB5_CA1, CB6_CA1}, + {0, CB4_CA2, CB5_CA2, CB6_CA2}, + {0, CB4_CA3, CB5_CA3, CB6_CA3}, + {0, CB4_CA4, CB5_CA4, CB6_CA4}, + {0, CB4_CA5, CB5_CA5, CB6_CA5}, + {0, CB4_CA6, CB5_CA6, CB6_CA6}, + {0, CB4_CA7, CB5_CA7, CB6_CA7}, + {0, CB4_CA8, CB5_CA8, CB6_CA8}, + {0, CB4_CA9, CB5_CA9, CB6_CA9}, + {0, CB4_CA10, CB5_CA10, CB6_CA10}, + {0, CB4_CA11, CB5_CA11, CB6_CA11}, + {0, CB4_CA12, CB5_CA12, CB6_CA12}, + {0, CB4_CA13, CB5_CA13, CB6_CA13}, + {0, CB4_CA14, CB5_CA14, CB6_CA14}, + {1, CB4_CA2, CB5_CA2, CB6_CA2}, + {1, CB4_CA4, CB5_CA4, CB6_CA4}, + {1, CB4_CA6, CB5_CA6, CB6_CA6}, + + {0, CB7_CA1, CB8_CA1, CB9_CA1}, + {0, CB7_CA2, CB8_CA2, CB9_CA2}, + {0, CB7_CA3, CB8_CA3, CB9_CA3}, + {0, CB7_CA4, CB8_CA4, CB9_CA4}, + {0, CB7_CA5, CB8_CA5, CB9_CA5}, + {0, CB7_CA6, CB8_CA6, CB9_CA6}, + {0, CB7_CA7, CB8_CA7, CB9_CA7}, + {0, CB7_CA8, CB8_CA8, CB9_CA8}, + {0, CB7_CA9, CB8_CA9, CB9_CA9}, + {0, CB7_CA10, CB8_CA10, CB9_CA10}, + {0, CB7_CA11, CB8_CA11, CB9_CA11}, + {0, CB7_CA12, CB8_CA12, CB9_CA12}, + {0, CB1_CA15, CB2_CA15, CB3_CA15}, + {0, CB7_CA13, CB8_CA13, CB9_CA13}, + + {0, CB10_CA1, CB11_CA1, CB12_CA1}, + {0, CB1_CA16, CB2_CA16, CB3_CA16}, + {0, CB10_CA2, CB11_CA2, CB12_CA2}, + {0, CB10_CA3, CB11_CA3, CB12_CA3}, + {0, CB10_CA4, CB11_CA4, CB12_CA4}, + {0, CB10_CA5, CB11_CA5, CB12_CA5}, + {0, CB10_CA6, CB11_CA6, CB12_CA6}, + {0, CB10_CA7, CB11_CA7, CB12_CA7}, + {0, CB10_CA8, CB11_CA8, CB12_CA8}, + {0, CB10_CA9, CB11_CA9, CB12_CA9}, + {0, CB10_CA10, CB11_CA10, CB12_CA10}, + {0, CB10_CA11, CB11_CA11, CB12_CA11}, + {0, CB10_CA12, CB11_CA12, CB12_CA12}, + {1, CB4_CA9, CB5_CA9, CB6_CA9}, + + {0, CB10_CA13, CB11_CA13, CB12_CA13}, + {0, CB10_CA14, CB11_CA14, CB12_CA14}, + {0, CB10_CA15, CB11_CA15, CB12_CA15}, + {0, CB10_CA16, CB11_CA16, CB12_CA16}, + + {0, CB7_CA14, CB8_CA14, CB9_CA14}, + {0, CB7_CA15, CB8_CA15, CB9_CA15}, + {0, CB7_CA16, CB8_CA16, CB9_CA16}, + {0, CB4_CA16, CB5_CA16, CB6_CA16}, + + {0, CB4_CA15, CB5_CA15, CB6_CA15}, + {1, CB4_CA8, CB5_CA8, CB6_CA8}, + {1, CB4_CA7, CB5_CA7, CB6_CA7}, + + {1, CB4_CA10, CB5_CA10, CB6_CA10}, + {1, CB4_CA11, CB5_CA11, CB6_CA11}, +}; +#endif + +typedef union { + uint32_t raw; + struct { + uint8_t flag : 1; + uint8_t devs : 3; + uint8_t BTdevs : 3; + }; +} confinfo_t; +confinfo_t confinfo; + +uint32_t post_init_timer = 0x00; + +void eeconfig_confinfo_update(uint32_t raw) { + + eeconfig_update_kb(raw); +} + +uint32_t eeconfig_confinfo_read(void) { + + return eeconfig_read_kb(); +} + +void eeconfig_confinfo_default(void) { + + confinfo.flag = true; +#ifdef WIRELESS_ENABLE + confinfo.devs = DEVS_USB; + confinfo.BTdevs = DEVS_BT1; +#endif + + eeconfig_confinfo_update(confinfo.raw); +} + +void eeconfig_confinfo_init(void) { + + confinfo.raw = eeconfig_confinfo_read(); + if (!confinfo.raw) { + eeconfig_confinfo_default(); + } +} +static void bt_scan_mode(void) { +#ifdef BT_MODE_SW_PIN + if (readPin(RF_MODE_SW_PIN) && !readPin(BT_MODE_SW_PIN)) { + if ((wireless_get_current_devs() == DEVS_USB) || (wireless_get_current_devs() == DEVS_2G4)) { + wireless_devs_change(wireless_get_current_devs(), confinfo.BTdevs, false); + } + } + if (readPin(BT_MODE_SW_PIN) && !readPin(RF_MODE_SW_PIN)) { + if (wireless_get_current_devs() != DEVS_2G4) { + wireless_devs_change(wireless_get_current_devs(), DEVS_2G4, false); // 2_CA4G mode + + } + } + if (readPin(BT_MODE_SW_PIN) && readPin(RF_MODE_SW_PIN)) { + if (wireless_get_current_devs() != DEVS_USB) wireless_devs_change(wireless_get_current_devs(), DEVS_USB, false); // usb mode + } +#endif +} + +void keyboard_post_init_kb(void) { + +#ifdef CONSOLE_ENABLE + debug_enable = true; +#endif + + eeconfig_confinfo_init(); + +#ifdef LED_POWER_EN_PIN + gpio_set_pin_output(LED_POWER_EN_PIN); + gpio_write_pin_high(LED_POWER_EN_PIN); +#endif +#ifdef LED_SCROLL_LOCK_PIN_G + gpio_set_pin_output(LED_SCROLL_LOCK_PIN_G); + gpio_set_pin_output(LED_SCROLL_LOCK_PIN_B); + gpio_set_pin_output(LED_SCROLL_LOCK_PIN_R); + gpio_write_pin_high(LED_SCROLL_LOCK_PIN_G); + gpio_write_pin_high(LED_SCROLL_LOCK_PIN_B); + gpio_write_pin_high(LED_SCROLL_LOCK_PIN_R); +#endif + +#ifdef USB_POWER_EN_PIN + gpio_write_pin_low(USB_POWER_EN_PIN); + gpio_set_pin_output(USB_POWER_EN_PIN); +#endif +#ifdef BT_MODE_SW_PIN + gpio_set_pin_input_high(BT_MODE_SW_PIN); + gpio_set_pin_input_high(RF_MODE_SW_PIN); +#endif +#ifdef BT_CABLE_PIN + gpio_set_pin_input(BT_CABLE_PIN); + gpio_set_pin_input(BT_CHARGE_PIN); +#endif + +#ifdef WIRELESS_ENABLE + wireless_init(); + wireless_devs_change(!confinfo.devs, confinfo.devs, false); + post_init_timer = timer_read32(); +#endif + + keyboard_post_init_user(); +} + +#ifdef WIRELESS_ENABLE + + +void usb_power_connect(void) { + +# ifdef USB_POWER_EN_PIN + gpio_write_pin_low(USB_POWER_EN_PIN); +# endif +} + +void usb_power_disconnect(void) { + +# ifdef USB_POWER_EN_PIN + gpio_write_pin_high(USB_POWER_EN_PIN); +# endif +} + +void suspend_power_down_kb(void) { + +# ifdef LED_POWER_EN_PIN + gpio_write_pin_low(LED_POWER_EN_PIN); +# endif + suspend_power_down_user(); +} + +void suspend_wakeup_init_kb(void) { + +# ifdef LED_POWER_EN_PIN + gpio_write_pin_high(LED_POWER_EN_PIN); +# endif + + wireless_devs_change(wireless_get_current_devs(), wireless_get_current_devs(), false); + suspend_wakeup_init_user(); +} +void matrix_scan_kb(void) { +#ifdef LED_SCROLL_LOCK_PIN_G + gpio_write_pin(LED_SCROLL_LOCK_PIN_G, !host_keyboard_led_state().scroll_lock); + gpio_write_pin(LED_SCROLL_LOCK_PIN_B, !host_keyboard_led_state().scroll_lock); + gpio_write_pin(LED_SCROLL_LOCK_PIN_R, !host_keyboard_led_state().scroll_lock); +#endif + bt_scan_mode(); + matrix_scan_user(); +} +void wireless_post_task(void) { + + // auto switching devs + if (post_init_timer && timer_elapsed32(post_init_timer) >= 100) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_FW_VERSION); // get the module fw version. + md_send_devctrl(MD_SND_CMD_DEVCTRL_SLEEP_BT_EN); // timeout 30min to sleep in bt mode, enable + md_send_devctrl(MD_SND_CMD_DEVCTRL_SLEEP_2G4_EN); // timeout 30min to sleep in 2.4g mode, enable + wireless_devs_change(!confinfo.devs, confinfo.devs, false); + post_init_timer = 0x00; + } +} + +uint32_t wls_process_long_press(uint32_t trigger_time, void *cb_arg) { + uint16_t keycode = *((uint16_t *)cb_arg); + + switch (keycode) { + case KC_BT1: { + if(wireless_get_current_devs() == DEVS_BT1) + wireless_devs_change(wireless_get_current_devs(), DEVS_BT1, true); + } break; + case KC_BT2: { + if(wireless_get_current_devs() == DEVS_BT2) + wireless_devs_change(wireless_get_current_devs(), DEVS_BT2, true); + } break; + case KC_BT3: { + if(wireless_get_current_devs() == DEVS_BT3) + wireless_devs_change(wireless_get_current_devs(), DEVS_BT3, true); + } break; + case KC_2G4: { + if(wireless_get_current_devs() == DEVS_2G4) + wireless_devs_change(wireless_get_current_devs(), DEVS_2G4, true); + } break; + default: + break; + } + + return 0; +} + +bool process_record_wls(uint16_t keycode, keyrecord_t *record) { + static uint16_t keycode_shadow = 0x00; + static deferred_token wls_process_long_press_token = INVALID_DEFERRED_TOKEN; + + keycode_shadow = keycode; + +# ifndef WLS_KEYCODE_PAIR_TIME +# define WLS_KEYCODE_PAIR_TIME 3000 +# endif + +# define WLS_KEYCODE_EXEC(wls_dev) \ + do { \ + if (record->event.pressed) { \ + wireless_devs_change(wireless_get_current_devs(), wls_dev, false); \ + if (wls_process_long_press_token == INVALID_DEFERRED_TOKEN) { \ + wls_process_long_press_token = defer_exec(WLS_KEYCODE_PAIR_TIME, wls_process_long_press, &keycode_shadow); \ + } \ + } else { \ + cancel_deferred_exec(wls_process_long_press_token); \ + wls_process_long_press_token = INVALID_DEFERRED_TOKEN; \ + } \ + } while (false) + + switch (keycode) { + case KC_BT1: { + if ((wireless_get_current_devs() != DEVS_USB) && (wireless_get_current_devs() != DEVS_2G4)) { + WLS_KEYCODE_EXEC(DEVS_BT1); + } + } break; + case KC_BT2: { + if ((wireless_get_current_devs() != DEVS_USB) && (wireless_get_current_devs() != DEVS_2G4)) { + WLS_KEYCODE_EXEC(DEVS_BT2); + } + } break; + case KC_BT3: { + if ((wireless_get_current_devs() != DEVS_USB) && (wireless_get_current_devs() != DEVS_2G4)) { + WLS_KEYCODE_EXEC(DEVS_BT3); + } + } break; + case KC_2G4: { + if (wireless_get_current_devs() == DEVS_2G4) { + WLS_KEYCODE_EXEC(DEVS_2G4); + } + } break; + case KC_USB: { + if (record->event.pressed) { + // wireless_devs_change(wireless_get_current_devs(), DEVS_USB, false); + } + } break; + default: + return true; + } + + return false; +} +#endif + +bool process_record_kb(uint16_t keycode, keyrecord_t *record) { + + if (process_record_user(keycode, record) != true) { + return false; + } + +#ifdef WIRELESS_ENABLE + if (process_record_wls(keycode, record) != true) { + return false; + } +#endif + + switch (keycode) { + default: + return true; + } + + return false; +} + +#ifdef RGB_MATRIX_ENABLE + +# ifdef WIRELESS_ENABLE +bool wls_rgb_indicator_reset = false; +uint32_t wls_rgb_indicator_timer = 0x00; +uint32_t wls_rgb_indicator_interval = 0; +uint32_t wls_rgb_indicator_times = 0; +uint32_t wls_rgb_indicator_index = 0; +RGB wls_rgb_indicator_rgb = {0}; + +void rgb_matrix_wls_indicator_set(uint8_t index, RGB rgb, uint32_t interval, uint8_t times) { + + wls_rgb_indicator_timer = timer_read32(); + + wls_rgb_indicator_index = index; + wls_rgb_indicator_interval = interval; + wls_rgb_indicator_times = times * 2; + wls_rgb_indicator_rgb = rgb; +} + +void wireless_devs_change_kb(uint8_t old_devs, uint8_t new_devs, bool reset) { + + wls_rgb_indicator_reset = reset; + + if (confinfo.devs != wireless_get_current_devs()) { + confinfo.devs = wireless_get_current_devs(); + if ((wireless_get_current_devs() != DEVS_USB) && (wireless_get_current_devs() != DEVS_2G4)) { + confinfo.BTdevs = wireless_get_current_devs(); + } + eeconfig_confinfo_update(confinfo.raw); + } + + switch (new_devs) { + case DEVS_BT1: { + if (reset) { + rgb_matrix_wls_indicator_set(17, (RGB){.r = 0, .g = 0, .b = 255}, 200, 1); + } else { + rgb_matrix_wls_indicator_set(17, (RGB){.r = 0, .g = 0, .b = 255}, 500, 1); + } + } break; + case DEVS_BT2: { + if (reset) { + rgb_matrix_wls_indicator_set(18, (RGB){.r = 0, .g = 0, .b = 255}, 200, 1); + } else { + rgb_matrix_wls_indicator_set(18, (RGB){.r = 0, .g = 0, .b = 255}, 500, 1); + } + } break; + case DEVS_BT3: { + if (reset) { + rgb_matrix_wls_indicator_set(19, (RGB){.r = 0, .g = 0, .b = 255}, 200, 1); + } else { + rgb_matrix_wls_indicator_set(19, (RGB){.r = 0, .g = 0, .b = 255}, 500, 1); + } + } break; + case DEVS_2G4: { + if (reset) { + rgb_matrix_wls_indicator_set(20, (RGB){.r = 0, .g = 255, .b = 0}, 200, 1); + } else { + rgb_matrix_wls_indicator_set(20, (RGB){.r = 0, .g = 255, .b = 0}, 500, 1); + } + } break; + default: + break; + } +} + +bool rgb_matrix_wls_indicator_cb(void) { + + if (*md_getp_state() != MD_STATE_CONNECTED) { + wireless_devs_change_kb(wireless_get_current_devs(), wireless_get_current_devs(), wls_rgb_indicator_reset); + return true; + } + + // refresh led + led_wakeup(); + + return false; +} + +void rgb_matrix_wls_indicator(void) { + + if (wls_rgb_indicator_timer) { + + if (timer_elapsed32(wls_rgb_indicator_timer) >= wls_rgb_indicator_interval) { + wls_rgb_indicator_timer = timer_read32(); + + if (wls_rgb_indicator_times) { + wls_rgb_indicator_times--; + } + + if (wls_rgb_indicator_times <= 0) { + wls_rgb_indicator_timer = 0x00; + if (rgb_matrix_wls_indicator_cb() != true) { + return; + } + } + } + + if (wls_rgb_indicator_times % 2) { + rgb_matrix_set_color(wls_rgb_indicator_index, wls_rgb_indicator_rgb.r, wls_rgb_indicator_rgb.g, wls_rgb_indicator_rgb.b); + } else { + rgb_matrix_set_color(wls_rgb_indicator_index, 0x00, 0x00, 0x00); + } + } +} +# endif + +bool rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) { + + if (rgb_matrix_indicators_advanced_user(led_min, led_max) != true) { + return false; + } + +# ifdef WIRELESS_ENABLE + rgb_matrix_wls_indicator(); +# endif +# if defined(BT_CABLE_PIN) && defined(BT_CHARGE_PIN) + // Charging access + static uint16_t charging_time; + static uint16_t full_time; + if (readPin(BT_CABLE_PIN)) { + if (!readPin(BT_CHARGE_PIN)) { + // Charging + if (timer_elapsed(charging_time) >= 500) { + rgb_matrix_set_color(90, 100, 0, 0); + } else { + rgb_matrix_set_color(90, 0, 0, 0); + } + full_time = timer_read32(); + } else { + // full + charging_time = timer_read32(); + if (timer_elapsed(full_time) >= 500) { + rgb_matrix_set_color(90, 0, 100, 0); + } else { + rgb_matrix_set_color(90, 0, 0, 0); + } + } + } else { + if(*md_getp_bat()>5){ + rgb_matrix_set_color(90, 0, 0, 0); + } else { + static bool Low_power_bink; + static uint16_t Low_power_time; + if (timer_elapsed(Low_power_time) >= 300) { + Low_power_bink = !Low_power_bink; + Low_power_time = timer_read32(); + } + if (Low_power_bink) { + rgb_matrix_set_color(90, 100, 0, 0); + } else { + rgb_matrix_set_color(90, 0, 0, 0); + } + } + } +# endif + // caps lock red + if (host_keyboard_led_state().caps_lock) { + rgb_matrix_set_color(89, 100, 100, 100); + } else { + rgb_matrix_set_color(89, 0, 0, 0); + } + // scroll lock red + if (host_keyboard_led_state().scroll_lock) { + rgb_matrix_set_color(14, 100, 0, 0); + } + // GUI lock red + if (keymap_config.no_gui) { + rgb_matrix_set_color(79, 100, 0, 0); + } + return true; +} + + +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: { + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } else { + md_send_devctrl(MD_SND_CMD_DEVCTRL_2G4); + } + } break; + case DEVS_BT1: { + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } else { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT1); + } + } break; + case DEVS_BT2: { + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } else { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT2); + } + } break; + case DEVS_BT3: { + if (reset) { + md_send_devctrl(MD_SND_CMD_DEVCTRL_PAIR); + } else { + md_send_devctrl(MD_SND_CMD_DEVCTRL_BT3); + } + } break; + default: + break; + } +} + +#endif +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}; + +#ifdef NKRO_ENABLE + + 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]); + } + + /* + * 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. + */ + + 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]); + del_key_bit(&temp_report_nkro, usageid); + + for (idx = 0; idx < WLS_KEYBOARD_REPORT_KEYS; idx++) { + if (temp_report_keyboard.keys[idx] == usageid) { + goto next; + } + } + + for (idx = 0; idx < WLS_KEYBOARD_REPORT_KEYS; idx++) { + if (temp_report_keyboard.keys[idx] == 0x00) { + temp_report_keyboard.keys[idx] = usageid; + break; + } + } + next: + if (idx == WLS_KEYBOARD_REPORT_KEYS && (usageid < (MD_SND_CMD_NKRO_LEN * 8))) { + wls_report_nkro[usageid / 8] |= 0x01 << (usageid % 8); + } + } + + temp_report_nkro = *report; + + // find key up and del it. + uint8_t nkro_keys = key_count; + for (uint8_t i = 0; i < WLS_KEYBOARD_REPORT_KEYS; i++) { + report_nkro_t found_report_nkro; + uint8_t usageid = 0x00; + uint8_t n; + + found_report_nkro = temp_report_nkro; + + for (uint8_t c = 0; c < nkro_keys; c++) { + for (n = 0; n < NKRO_REPORT_BITS && !found_report_nkro.bits[n]; n++) {} + usageid = (n << 3) | biton(found_report_nkro.bits[n]); + del_key_bit(&found_report_nkro, usageid); + if (usageid == temp_report_keyboard.keys[i]) { + del_key_bit(&temp_report_nkro, usageid); + nkro_keys--; + break; + } + } + + if (usageid != temp_report_keyboard.keys[i]) { + temp_report_keyboard.keys[i] = 0x00; + } + } + } else { + memset(&temp_report_keyboard, 0, sizeof(temp_report_keyboard)); + } +#endif + void wireless_task(void); + bool smsg_is_busy(void); + while(smsg_is_busy()) { + wireless_task(); + } + extern host_driver_t wireless_driver; + wireless_driver.send_keyboard(&temp_report_keyboard); + md_send_nkro(wls_report_nkro); +} diff --git a/keyboards/hator/rockfall3/htk850/keyboard.json b/keyboards/hator/rockfall3/htk850/keyboard.json new file mode 100644 index 00000000000..adb03a8d156 --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/keyboard.json @@ -0,0 +1,288 @@ +{ + "manufacturer": "HATOR", + "keyboard_name": "Rockfall 3 Wireless", + "url": "https://hator.com/", + "maintainer": "AlexHtr", + "bootloader": "wb32-dfu", + "bootmagic": { + "matrix": [0, 0] + }, + "diode_direction": "ROW2COL", + "eeprom": { + "driver": "wear_leveling", + "wear_leveling": { + "backing_size": 4096, + "driver": "spi_flash" + } + }, + "features": { + "bootmagic": true, + "command": false, + "console": false, + "deferred_exec": true, + "extrakey": true, + "haptic": false, + "mousekey": true, + "nkro": true, + "rgb_matrix": true, + "rgblight": false + }, + "keycodes": [ + { + "key": "KC_USB" + }, + { + "key": "KC_BT1" + }, + { + "key": "KC_BT2" + }, + { + "key": "KC_BT3" + }, + { + "key": "KC_BT4" + }, + { + "key": "KC_BT5" + }, + { + "key": "KC_2G4" + } + ], + "matrix_pins": { + "cols": ["C1","C2","C3","A0","A1","A2","A3","A4","A5","A6","A7","C4","C5","B0","B1","B2","B10"], + "rows": ["B15", "C6", "C7", "C8", "C9", "B14"] + }, + "indicators": { + "caps_lock": "C0", + "on_state": 0 + }, + "processor": "WB32FQ95", + "rgb_matrix": { + "animations": { + "breathing": true, + "cycle_all": true, + "cycle_left_right": true, + "cycle_out_in": true, + "cycle_out_in_dual": true, + "cycle_pinwheel": true, + "cycle_spiral": true, + "cycle_up_down": true, + "dual_beacon": true, + "multisplash": true, + "rainbow_beacon": true, + "rainbow_moving_chevron": true, + "raindrops": true, + "solid_color": true, + "solid_reactive": true, + "solid_reactive_simple": true, + "typing_heatmap": true + }, + "driver": "snled27351", + "layout": [ + { "flags": 4, "matrix": [0,0], "x": 6, "y": 8 }, + { "flags": 4, "matrix": [0,1], "x": 31, "y": 8 }, + { "flags": 4, "matrix": [0,2], "x": 43, "y": 8 }, + { "flags": 4, "matrix": [0,3], "x": 55, "y": 8 }, + { "flags": 4, "matrix": [0,4], "x": 68, "y": 8 }, + { "flags": 4, "matrix": [0,5], "x": 86, "y": 8 }, + { "flags": 4, "matrix": [0,6], "x": 98, "y": 8 }, + { "flags": 4, "matrix": [0,7], "x": 110, "y": 8 }, + { "flags": 4, "matrix": [0,8], "x": 123, "y": 8 }, + { "flags": 4, "matrix": [0,9], "x": 141, "y": 8 }, + { "flags": 4, "matrix": [0,10], "x": 153, "y": 8 }, + { "flags": 4, "matrix": [0,11], "x": 166, "y": 8 }, + { "flags": 4, "matrix": [0,12], "x": 178, "y": 8 }, + { "flags": 4, "matrix": [0,14], "x": 193, "y": 8 }, + { "flags": 4, "matrix": [0,15], "x": 206, "y": 8 }, + { "flags": 4, "matrix": [0,16], "x": 218, "y": 8 }, + { "flags": 4, "matrix": [1,0], "x": 6, "y": 21}, + { "flags": 4, "matrix": [1,1], "x": 18, "y": 21}, + { "flags": 4, "matrix": [1,2], "x": 31, "y": 21}, + { "flags": 4, "matrix": [1,3], "x": 43, "y": 21}, + { "flags": 4, "matrix": [1,4], "x": 55, "y": 21}, + { "flags": 4, "matrix": [1,5], "x": 68, "y": 21}, + { "flags": 4, "matrix": [1,6], "x": 80, "y": 21}, + { "flags": 4, "matrix": [1,7], "x": 92, "y": 21}, + { "flags": 4, "matrix": [1,8], "x": 104, "y": 21}, + { "flags": 4, "matrix": [1,9], "x": 117, "y": 21}, + { "flags": 4, "matrix": [1,10], "x": 129, "y": 21}, + { "flags": 4, "matrix": [1,11], "x": 141, "y": 21}, + { "flags": 4, "matrix": [1,12], "x": 153, "y": 21}, + { "flags": 4, "matrix": [1,13], "x": 172, "y": 21}, + { "flags": 4, "matrix": [1,14], "x": 193, "y": 21}, + { "flags": 4, "matrix": [1,15], "x": 206, "y": 21}, + { "flags": 4, "matrix": [1,16], "x": 218, "y": 21}, + { "flags": 4, "matrix": [2,0], "x": 9, "y": 31}, + { "flags": 4, "matrix": [2,1], "x": 25, "y": 31}, + { "flags": 4, "matrix": [2,2], "x": 37, "y": 31}, + { "flags": 4, "matrix": [2,3], "x": 49, "y": 31}, + { "flags": 4, "matrix": [2,4], "x": 61, "y": 31}, + { "flags": 4, "matrix": [2,5], "x": 74, "y": 31}, + { "flags": 4, "matrix": [2,6], "x": 86, "y": 31}, + { "flags": 4, "matrix": [2,7], "x": 98, "y": 31}, + { "flags": 4, "matrix": [2,8], "x": 110, "y": 31}, + { "flags": 4, "matrix": [2,9], "x": 123, "y": 31}, + { "flags": 4, "matrix": [2,10], "x": 135, "y": 31}, + { "flags": 4, "matrix": [2,11], "x": 147, "y": 31}, + { "flags": 4, "matrix": [2,12], "x": 160, "y": 31}, + { "flags": 4, "matrix": [2,13], "x": 175, "y": 31}, + { "flags": 4, "matrix": [2,14], "x": 193, "y": 31}, + { "flags": 4, "matrix": [2,15], "x": 206, "y": 31}, + { "flags": 4, "matrix": [2,16], "x": 218, "y": 31}, + { "flags": 1, "matrix": [3,0], "x": 11, "y": 41}, + { "flags": 4, "matrix": [3,1], "x": 28, "y": 41}, + { "flags": 4, "matrix": [3,2], "x": 40, "y": 41}, + { "flags": 4, "matrix": [3,3], "x": 52, "y": 41}, + { "flags": 4, "matrix": [3,4], "x": 64, "y": 41}, + { "flags": 4, "matrix": [3,5], "x": 77, "y": 41}, + { "flags": 4, "matrix": [3,6], "x": 89, "y": 41}, + { "flags": 4, "matrix": [3,7], "x": 101, "y": 41}, + { "flags": 4, "matrix": [3,8], "x": 114, "y": 41}, + { "flags": 4, "matrix": [3,9], "x": 126, "y": 41}, + { "flags": 4, "matrix": [3,10], "x": 138, "y": 41}, + { "flags": 4, "matrix": [3,11], "x": 150, "y": 41}, + { "flags": 4, "matrix": [3,12], "x": 162, "y": 41}, + { "flags": 1, "matrix": [3,13], "x": 170, "y": 41}, + { "flags": 1, "matrix": [4,0], "x": 14, "y": 51}, + { "flags": 1, "matrix": [5,3], "x": 22, "y": 51}, + { "flags": 4, "matrix": [4,1], "x": 34, "y": 51}, + { "flags": 4, "matrix": [4,2], "x": 46, "y": 51}, + { "flags": 4, "matrix": [4,3], "x": 58, "y": 51}, + { "flags": 4, "matrix": [4,4], "x": 71, "y": 51}, + { "flags": 4, "matrix": [4,5], "x": 83, "y": 51}, + { "flags": 4, "matrix": [4,6], "x": 95, "y": 51}, + { "flags": 4, "matrix": [4,7], "x": 107, "y": 51}, + { "flags": 4, "matrix": [4,8], "x": 120, "y": 51}, + { "flags": 4, "matrix": [4,9], "x": 132, "y": 51}, + { "flags": 4, "matrix": [4,10], "x": 144, "y": 51}, + { "flags": 1, "matrix": [4,13], "x": 167, "y": 51}, + { "flags": 1, "matrix": [4,15], "x": 206, "y": 51}, + { "flags": 1, "matrix": [5,0], "x": 8, "y": 62}, + { "flags": 1, "matrix": [5,1], "x": 23, "y": 62}, + { "flags": 1, "matrix": [5,2], "x": 38, "y": 62}, + { "flags": 4, "matrix": [5,5], "x": 84, "y": 62}, + { "flags": 1, "matrix": [5,10], "x": 130, "y": 62}, + { "flags": 1, "matrix": [5,11], "x": 146, "y": 62}, + { "flags": 1, "matrix": [5,12], "x": 161, "y": 62}, + { "flags": 1, "matrix": [5,13], "x": 176, "y": 62}, + { "flags": 1, "matrix": [5,14], "x": 193, "y": 62}, + { "flags": 1, "matrix": [5,15], "x": 206, "y": 62}, + { "flags": 1, "matrix": [5,16], "x": 218, "y": 62}, + + { "flags": 1}, + { "flags": 1} + ], + "max_brightness": 180, + "sleep": false, + "speed_steps": 64, + "timeout": 60000, + "val_steps": 45 + }, + "usb": { + "device_version": "1.1.1", + "force_nkro": true, + "pid": "0x0300", + "suspend_wakeup_delay": 1000, + "vid": "0x379A" + }, + "dynamic_keymap": { + "layer_count": 6 + }, + "layouts": { + "LAYOUT_ansi": { + "layout": [ + { "matrix": [0,0], "x": 0, "y": 0 }, + { "matrix": [0,1], "x": 2, "y": 0 }, + { "matrix": [0,2], "x": 3, "y": 0 }, + { "matrix": [0,3], "x": 4, "y": 0 }, + { "matrix": [0,4], "x": 5, "y": 0 }, + { "matrix": [0,5], "x": 6.5, "y": 0 }, + { "matrix": [0,6], "x": 7.5, "y": 0 }, + { "matrix": [0,7], "x": 8.5, "y": 0 }, + { "matrix": [0,8], "x": 9.5, "y": 0 }, + { "matrix": [0,9], "x": 11, "y": 0 }, + { "matrix": [0,10], "x": 12, "y": 0 }, + { "matrix": [0,11], "x": 13, "y": 0 }, + { "matrix": [0,12], "x": 14, "y": 0 }, + { "matrix": [0,14], "x": 15.25, "y": 0 }, + { "matrix": [0,15], "x": 16.25, "y": 0 }, + { "matrix": [0,16], "x": 17.25, "y": 0 }, + { "matrix": [1,0], "x": 0, "y": 1.25 }, + { "matrix": [1,1], "x": 1, "y": 1.25 }, + { "matrix": [1,2], "x": 2, "y": 1.25 }, + { "matrix": [1,3], "x": 3, "y": 1.25 }, + { "matrix": [1,4], "x": 4, "y": 1.25 }, + { "matrix": [1,5], "x": 5, "y": 1.25 }, + { "matrix": [1,6], "x": 6, "y": 1.25 }, + { "matrix": [1,7], "x": 7, "y": 1.25 }, + { "matrix": [1,8], "x": 8, "y": 1.25 }, + { "matrix": [1,9], "x": 9, "y": 1.25 }, + { "matrix": [1,10], "x": 10, "y": 1.25 }, + { "matrix": [1,11], "x": 11, "y": 1.25 }, + { "matrix": [1,12], "x": 12, "y": 1.25 }, + { "matrix": [1,13], "x": 14, "y": 1.25 }, + { "matrix": [1,14], "x": 15.25, "y": 1.25 }, + { "matrix": [1,15], "x": 16.25, "y": 1.25 }, + { "matrix": [1,16], "x": 17.25, "y": 1.25 }, + { "matrix": [2,0], "w": 1.5, "x": 0, "y": 2.25 }, + { "matrix": [2,1], "x": 1.5, "y": 2.25 }, + { "matrix": [2,2], "x": 2.5, "y": 2.25 }, + { "matrix": [2,3], "x": 3.5, "y": 2.25 }, + { "matrix": [2,4], "x": 4.5, "y": 2.25 }, + { "matrix": [2,5], "x": 5.5, "y": 2.25 }, + { "matrix": [2,6], "x": 6.5, "y": 2.25 }, + { "matrix": [2,7], "x": 7.5, "y": 2.25 }, + { "matrix": [2,8], "x": 8.5, "y": 2.25 }, + { "matrix": [2,9], "x": 9.5, "y": 2.25 }, + { "matrix": [2,10], "x": 10.5, "y": 2.25 }, + { "matrix": [2,11], "x": 11.5, "y": 2.25 }, + { "matrix": [2,12], "x": 12.5, "y": 2.25 }, + { "matrix": [2,13], "w": 1.5, "x": 13.5, "y": 2.25 }, + { "matrix": [2,14], "x": 15.25, "y": 2.25 }, + { "matrix": [2,15], "x": 16.25, "y": 2.25 }, + { "matrix": [2,16], "x": 17.25, "y": 2.25 }, + { "matrix": [3,0], "w": 1.75, "x": 0, "y": 3.25 }, + { "matrix": [3,1], "x": 1.75, "y": 3.25 }, + { "matrix": [3,2], "x": 2.75, "y": 3.25 }, + { "matrix": [3,3], "x": 3.75, "y": 3.25 }, + { "matrix": [3,4], "x": 4.75, "y": 3.25 }, + { "matrix": [3,5], "x": 5.75, "y": 3.25 }, + { "matrix": [3,6], "x": 6.75, "y": 3.25 }, + { "matrix": [3,7], "x": 7.75, "y": 3.25 }, + { "matrix": [3,8], "x": 8.75, "y": 3.25 }, + { "matrix": [3,9], "x": 9.75, "y": 3.25 }, + { "matrix": [3,10], "x": 10.75, "y": 3.25 }, + { "matrix": [3,11], "x": 11.75, "y": 3.25 }, + { "matrix": [3,12], "x": 12.75, "y": 3.25 }, + { "matrix": [3,13], "w": 2.25, "x": 12.75, "y": 3.25 }, + { "matrix": [4,0], "w": 2.25, "x": 0, "y": 4.25 }, + { "matrix": [5,3], "x": 1.25, "y": 4.25 }, + { "matrix": [4,1], "x": 2.25, "y": 4.25 }, + { "matrix": [4,2], "x": 3.25, "y": 4.25 }, + { "matrix": [4,3], "x": 4.25, "y": 4.25 }, + { "matrix": [4,4], "x": 5.25, "y": 4.25 }, + { "matrix": [4,5], "x": 6.25, "y": 4.25 }, + { "matrix": [4,6], "x": 7.25, "y": 4.25 }, + { "matrix": [4,7], "x": 8.25, "y": 4.25 }, + { "matrix": [4,8], "x": 9.25, "y": 4.25 }, + { "matrix": [4,9], "x": 10.25, "y": 4.25 }, + { "matrix": [4,10], "x": 11.25, "y": 4.25 }, + { "matrix": [4,13], "w": 2.75, "x": 12.25, "y": 4.25 }, + { "matrix": [4,15], "x": 16.25, "y": 4.25 }, + { "matrix": [5,0], "w": 1.25, "x": 0, "y": 5.25 }, + { "matrix": [5,1], "w": 1.25, "x": 1.25, "y": 5.25 }, + { "matrix": [5,2], "w": 1.25, "x": 2.5, "y": 5.25 }, + { "matrix": [5,5], "w": 6.25, "x": 3.75, "y": 5.25 }, + { "matrix": [5,10], "w": 1.25, "x": 10, "y": 5.25 }, + { "matrix": [5,11], "w": 1.25, "x": 11.25, "y": 5.25 }, + { "matrix": [5,12], "w": 1.25, "x": 12.5, "y": 5.25 }, + { "matrix": [5,13], "w": 1.25, "x": 13.75, "y": 5.25 }, + { "matrix": [5,14], "x": 15.25, "y": 5.25 }, + { "matrix": [5,15], "x": 16.25, "y": 5.25 }, + { "matrix": [5,16], "x": 17.25, "y": 5.25 } + ] + } + } +} diff --git a/keyboards/hator/rockfall3/htk850/keymaps/default/keymap.c b/keyboards/hator/rockfall3/htk850/keymaps/default/keymap.c new file mode 100644 index 00000000000..419c68a8edc --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/keymaps/default/keymap.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include QMK_KEYBOARD_H + +// clang-format off +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + + [0] = LAYOUT_ansi( /* Base */ + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SCRL, KC_PAUS, + KC_GRV, 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_INS, KC_HOME, KC_PGUP, + 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_END, KC_PGDN, + 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_NUHS, KC_ENT, + KC_LSFT, KC_NUBS, 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_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), MO(4), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [1] = LAYOUT_ansi( /* FN1 */ + EE_CLR, KC_BRID, KC_BRIU, KC_MAIL, KC_WSCH, KC_CALC, KC_MSEL, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, _______, + NK_TOGG, KC_BT1, KC_BT2, KC_BT3, KC_2G4, _______, _______, _______, _______, _______, _______, _______, _______, RGB_MOD, _______, _______, RGB_HUI, + TO(2), _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_HUD, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_VAI, + _______, GU_TOGG, _______, _______, _______, _______, _______, _______, RGB_SPD, RGB_VAD, RGB_SPI), + + [2] = LAYOUT_ansi( /* Base */ + KC_ESC,KC_BRID,KC_BRIU,C(KC_UP),C(S(KC_DOWN)),KC_F5, KC_F6, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_PSCR, KC_SCRL, KC_PAUS, + KC_GRV, 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_INS, KC_HOME, KC_PGUP, + 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_END, KC_PGDN, + 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_NUHS, KC_ENT, + KC_LSFT, KC_NUBS, 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_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_RGUI, MO(3), MO(4), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [3] = LAYOUT_ansi( /* FN1 */ + EE_CLR, KC_F1, KC_F2, KC_F3, KC_F4, _______, _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, _______, + NK_TOGG, KC_BT1, KC_BT2, KC_BT3, KC_2G4, _______, _______, _______, _______, _______, _______, _______, _______, RGB_MOD, _______, _______, RGB_HUI, + TO(0), _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_HUD, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_VAI, + _______, _______, _______, _______, _______, _______, _______, _______, RGB_SPD, RGB_VAD, RGB_SPI), + + [4] = LAYOUT_ansi( /* FN2 */ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_MOD, _______, _______, RGB_HUI, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_HUD, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_VAI, + _______, _______, _______, _______, _______, _______, _______, _______, RGB_SPD, RGB_VAD, RGB_SPI), + + [5] = LAYOUT_ansi( /* FNx */ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______) +}; diff --git a/keyboards/hator/rockfall3/htk850/mcuconf.h b/keyboards/hator/rockfall3/htk850/mcuconf.h new file mode 100644 index 00000000000..75914f22576 --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/mcuconf.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2024 koosikus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include_next + +#undef WB32_USB_HOST_WAKEUP_DURATION +#define WB32_USB_HOST_WAKEUP_DURATION 2 + +#undef WB32_SERIAL_USE_UART1 +#define WB32_SERIAL_USE_UART1 TRUE + +#undef WB32_SPI_USE_QSPI +#define WB32_SPI_USE_QSPI TRUE + +// // The interrupt priority of the WS2812 driver must be higher than that of other SPI devices. +// #undef WB32_SPI_QSPI_IRQ_PRIORITY +// #define WB32_SPI_QSPI_IRQ_PRIORITY 9 + +// #undef WB32_SPI_SPIM2_IRQ_PRIORITY +// #define WB32_SPI_SPIM2_IRQ_PRIORITY 10 + +#undef WB32_I2C_USE_I2C1 +#define WB32_I2C_USE_I2C1 TRUE + +/* system clock set to 96Mhz */ +#undef WB32_PLLDIV_VALUE +#define WB32_PLLDIV_VALUE 2 + +#undef WB32_PLLMUL_VALUE +#define WB32_PLLMUL_VALUE 16 + +#undef WB32_USBPRE +#define WB32_USBPRE WB32_USBPRE_DIV2 diff --git a/keyboards/hator/rockfall3/htk850/readme.md b/keyboards/hator/rockfall3/htk850/readme.md new file mode 100644 index 00000000000..36bf7d90548 --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/readme.md @@ -0,0 +1,25 @@ +# Rockfall 3 Wireless +![Rockfall3](https://i.imgur.com/2epEIXa.png) + +TKL multimode keyboard + +* Keyboard Maintainer: [koosikus](https://github.com/koosikus) +* Hardware Supported: HATOR Rockfall 3 Wireless (HTK850) +* Hardware Availability: [Rockfall 3 Wireless](https://hator.com/keyboards/rockfall-3-mecha-tkl-wireless/) + +Make example for this keyboard (after setting up your build environment): + + make hator/rockfall3/htk850:default + +Flashing example for this keyboard: + + make hator/rockfall3/htk850:default:flash + +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). + +## Bootloader + +Enter the bootloader in 2 ways: + +* **Bootmagic reset**: Hold down the Hold down the top left key (commonly programmed as *Esc*) and plug in the keyboard +* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available diff --git a/keyboards/hator/rockfall3/htk850/rules.mk b/keyboards/hator/rockfall3/htk850/rules.mk new file mode 100644 index 00000000000..411b78537e9 --- /dev/null +++ b/keyboards/hator/rockfall3/htk850/rules.mk @@ -0,0 +1 @@ +include keyboards/hator/rockfall3/common/wireless/wireless.mk From b75e8cd14278d3d682bd599580c9d1d025503725 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 Dec 2024 02:40:08 +0200 Subject: [PATCH 2/4] maintainer changed --- keyboards/hator/rockfall3/htk850/keyboard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyboards/hator/rockfall3/htk850/keyboard.json b/keyboards/hator/rockfall3/htk850/keyboard.json index adb03a8d156..802b0d755b3 100644 --- a/keyboards/hator/rockfall3/htk850/keyboard.json +++ b/keyboards/hator/rockfall3/htk850/keyboard.json @@ -2,7 +2,7 @@ "manufacturer": "HATOR", "keyboard_name": "Rockfall 3 Wireless", "url": "https://hator.com/", - "maintainer": "AlexHtr", + "maintainer": "koosikus", "bootloader": "wb32-dfu", "bootmagic": { "matrix": [0, 0] From ac53d55450f34a840a53c92fe072816ce1f955d1 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 25 Dec 2024 12:42:30 +0200 Subject: [PATCH 3/4] rules.mk fix for lint --- keyboards/hator/rockfall3/htk850/{rules.mk => post_rules.mk} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename keyboards/hator/rockfall3/htk850/{rules.mk => post_rules.mk} (100%) diff --git a/keyboards/hator/rockfall3/htk850/rules.mk b/keyboards/hator/rockfall3/htk850/post_rules.mk similarity index 100% rename from keyboards/hator/rockfall3/htk850/rules.mk rename to keyboards/hator/rockfall3/htk850/post_rules.mk From ab08a74cb42cbb5e2b04675cd0a7323d2cdd9e42 Mon Sep 17 00:00:00 2001 From: Orest <142793347+AlexHtr@users.noreply.github.com> Date: Fri, 16 May 2025 20:48:18 +0300 Subject: [PATCH 4/4] Update to config.h --- keyboards/hator/rockfall3/htk850/config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/keyboards/hator/rockfall3/htk850/config.h b/keyboards/hator/rockfall3/htk850/config.h index 0a0539608d6..6615be44be1 100644 --- a/keyboards/hator/rockfall3/htk850/config.h +++ b/keyboards/hator/rockfall3/htk850/config.h @@ -36,6 +36,7 @@ /* UART */ #define UART_TX_PIN A9 #define UART_RX_PIN A10 +#define UART_RX_PAL_MODE 7 /* SPI Config for spi flash*/ #define SPI_DRIVER SPIDQ