summaryrefslogtreecommitdiffstats
path: root/keyboards/keychron/k15_pro/k15_pro.c
diff options
context:
space:
mode:
authorlokher <lokher@gmail.com>2023-10-25 15:08:46 +0800
committerGitHub <noreply@github.com>2023-10-25 15:08:46 +0800
commitd72ae351eabcf2baec05436b1e479182863bfda2 (patch)
treed18c407f6e996a309a27792ef12c604fd7a7e59c /keyboards/keychron/k15_pro/k15_pro.c
parenteca6feaf10c7077e00506c7dc5491cfde77546ce (diff)
parent1df560b679d2c8e8c6bf0e2156127d363eba0ce7 (diff)
Merge pull request #185 from KeychronMacro/keychron_k15_pro
Add keychron k15 pro
Diffstat (limited to 'keyboards/keychron/k15_pro/k15_pro.c')
-rwxr-xr-xkeyboards/keychron/k15_pro/k15_pro.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/keyboards/keychron/k15_pro/k15_pro.c b/keyboards/keychron/k15_pro/k15_pro.c
new file mode 100755
index 0000000000..ce3ef9c0ed
--- /dev/null
+++ b/keyboards/keychron/k15_pro/k15_pro.c
@@ -0,0 +1,342 @@
+/* Copyright 2023 @ Keychron (https://www.keychron.com)
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "k15_pro.h"
+#ifdef KC_BLUETOOTH_ENABLE
+# include "ckbt51.h"
+# include "bluetooth.h"
+# include "indicator.h"
+# include "transport.h"
+# include "battery.h"
+# include "bat_level_animation.h"
+# include "lpm.h"
+#endif
+
+#ifdef ENABLE_FACTORY_TEST
+# include "factory_test.h"
+#endif
+
+#define POWER_ON_LED_DURATION 3000
+
+typedef struct PACKED {
+ uint8_t len;
+ uint8_t keycode[3];
+} key_combination_t;
+
+static uint32_t factory_timer_buffer = 0;
+static uint32_t power_on_indicator_timer_buffer = 0;
+static uint32_t siri_timer_buffer = 0;
+static uint8_t mac_keycode[4] = {KC_LOPT, KC_ROPT, KC_LCMD, KC_RCMD};
+
+key_combination_t key_comb_list[4] = {
+ {2, {KC_LWIN, KC_TAB}}, // Task (win)
+ {2, {KC_LWIN, KC_E}}, // Files (win)
+ {3, {KC_LSFT, KC_LGUI, KC_4}}, // Snapshot (mac)
+ {2, {KC_LWIN, KC_C}} // Cortana (win)
+};
+
+#ifdef KC_BLUETOOTH_ENABLE
+bool firstDisconnect = true;
+bool bt_factory_reset = false;
+static virtual_timer_t pairing_key_timer;
+extern uint8_t g_pwm_buffer[DRIVER_COUNT][192];
+
+static void pairing_key_timer_cb(void *arg) {
+ bluetooth_pairing_ex(*(uint8_t *)arg, NULL);
+}
+#endif
+
+bool dip_switch_update_kb(uint8_t index, bool active) {
+ if (index == 0) {
+#ifdef INVERT_OS_SWITCH_STATTE
+ default_layer_set(1UL << (!active ? 0 : 2));
+#else
+ default_layer_set(1UL << (active ? 0 : 2));
+#endif
+ }
+ dip_switch_update_user(index, active);
+
+ return true;
+}
+
+#ifdef KC_BLUETOOTH_ENABLE
+bool process_record_kb_bt(uint16_t keycode, keyrecord_t *record) {
+#else
+bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
+#endif
+ static uint8_t host_idx = 0;
+
+ switch (keycode) {
+ case KC_MICT:
+ if (record->event.pressed) {
+ register_code(KC_MISSION_CONTROL);
+ } else {
+ unregister_code(KC_MISSION_CONTROL);
+ }
+ return false; // Skip all further processing of this key
+ case KC_LAPA:
+ if (record->event.pressed) {
+ register_code(KC_LAUNCHPAD);
+ } else {
+ unregister_code(KC_LAUNCHPAD);
+ }
+ return false; // Skip all further processing of this key
+ case KC_LOPTN:
+ case KC_ROPTN:
+ case KC_LCMMD:
+ case KC_RCMMD:
+ if (record->event.pressed) {
+ register_code(mac_keycode[keycode - KC_LOPTN]);
+ } else {
+ unregister_code(mac_keycode[keycode - KC_LOPTN]);
+ }
+ return false; // Skip all further processing of this key)
+ case KC_TASK:
+ case KC_FILE:
+ case KC_SNAP:
+ case KC_CTANA:
+ if (record->event.pressed) {
+ for (uint8_t i = 0; i < key_comb_list[keycode - KC_TASK].len; i++)
+ register_code(key_comb_list[keycode - KC_TASK].keycode[i]);
+ } else {
+ for (uint8_t i = 0; i < key_comb_list[keycode - KC_TASK].len; i++)
+ unregister_code(key_comb_list[keycode - KC_TASK].keycode[i]);
+ }
+ return false; // Skip all further processing of this key
+ case KC_SIRI:
+ if (record->event.pressed && siri_timer_buffer == 0) {
+ register_code(KC_LGUI);
+ register_code(KC_SPACE);
+ siri_timer_buffer = sync_timer_read32() | 1;
+ }
+ return false; // Skip all further processing of this key
+#ifdef KC_BLUETOOTH_ENABLE
+ case BT_HST1 ... BT_HST3:
+ if (get_transport() == TRANSPORT_BLUETOOTH) {
+ if (record->event.pressed) {
+ host_idx = keycode - BT_HST1 + 1;
+ chVTSet(&pairing_key_timer, TIME_MS2I(2000), (vtfunc_t)pairing_key_timer_cb, &host_idx);
+ bluetooth_connect_ex(host_idx, 0);
+ } else {
+ host_idx = 0;
+ chVTReset(&pairing_key_timer);
+ }
+ }
+ break;
+ case BAT_LVL:
+ if (get_transport() == TRANSPORT_BLUETOOTH && !usb_power_connected()) {
+ bat_level_animiation_start(battery_get_percentage());
+ }
+ break;
+#endif
+ default:
+#ifdef FACTORY_RESET_CHECK
+ FACTORY_RESET_CHECK(keycode, record);
+#endif
+ break;
+ }
+ return true;
+}
+
+#if defined(KC_BLUETOOTH_ENABLE) && defined(ENCODER_ENABLE)
+static void encoder_pad_cb(void *param) {
+ encoder_inerrupt_read((uint32_t)param & 0XFF);
+}
+#endif
+
+void keyboard_post_init_kb(void) {
+ dip_switch_read(true);
+
+#ifdef KC_BLUETOOTH_ENABLE
+ /* Currently we don't use this reset pin */
+ palSetLineMode(CKBT51_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL);
+ palWriteLine(CKBT51_RESET_PIN, PAL_HIGH);
+
+ /* IMPORTANT: DO NOT enable internal pull-up resistor
+ * as there is an external pull-down resistor.
+ */
+ palSetLineMode(USB_BT_MODE_SELECT_PIN, PAL_MODE_INPUT);
+
+ ckbt51_init(false);
+ bluetooth_init();
+
+ power_on_indicator_timer_buffer = sync_timer_read32() | 1;
+ writePin(BAT_LOW_LED_PIN, BAT_LOW_LED_PIN_ON_STATE);
+
+# ifdef ENCODER_ENABLE
+ pin_t encoders_pad_a[NUM_ENCODERS] = ENCODERS_PAD_A;
+ pin_t encoders_pad_b[NUM_ENCODERS] = ENCODERS_PAD_B;
+ for (uint32_t i = 0; i < NUM_ENCODERS; i++) {
+ palEnableLineEvent(encoders_pad_a[i], PAL_EVENT_MODE_BOTH_EDGES);
+ palEnableLineEvent(encoders_pad_b[i], PAL_EVENT_MODE_BOTH_EDGES);
+ palSetLineCallback(encoders_pad_a[i], encoder_pad_cb, (void *)i);
+ palSetLineCallback(encoders_pad_b[i], encoder_pad_cb, (void *)i);
+ }
+# endif
+#endif
+
+ keyboard_post_init_user();
+}
+
+void matrix_scan_kb(void) {
+ if (factory_timer_buffer && timer_elapsed32(factory_timer_buffer) > 2000) {
+ factory_timer_buffer = 0;
+ if (bt_factory_reset) {
+ bt_factory_reset = false;
+ palWriteLine(CKBT51_RESET_PIN, PAL_LOW);
+ wait_ms(5);
+ palWriteLine(CKBT51_RESET_PIN, PAL_HIGH);
+ }
+ }
+
+ if (power_on_indicator_timer_buffer) {
+ if (sync_timer_elapsed32(power_on_indicator_timer_buffer) > POWER_ON_LED_DURATION) {
+ power_on_indicator_timer_buffer = 0;
+ writePin(BAT_LOW_LED_PIN, !BAT_LOW_LED_PIN_ON_STATE);
+ } else {
+ writePin(BAT_LOW_LED_PIN, BAT_LOW_LED_PIN_ON_STATE);
+ }
+ }
+
+ if (siri_timer_buffer && sync_timer_elapsed32(siri_timer_buffer) > 500) {
+ siri_timer_buffer = 0;
+ unregister_code(KC_LGUI);
+ unregister_code(KC_SPACE);
+ }
+
+#ifdef FACTORY_RESET_TASK
+ FACTORY_RESET_TASK();
+#endif
+ matrix_scan_user();
+}
+
+#ifdef KC_BLUETOOTH_ENABLE
+static void ckbt51_param_init(void) {
+ /* Set bluetooth device name */
+ ckbt51_set_local_name(PRODUCT);
+ wait_ms(10);
+ /* Set bluetooth parameters */
+ module_param_t param = {.event_mode = 0x02,
+ .connected_idle_timeout = 7200,
+ .pairing_timeout = 180,
+ .pairing_mode = 0,
+ .reconnect_timeout = 5,
+ .report_rate = 90,
+ .vendor_id_source = 1,
+ .verndor_id = 0, // Must be 0x3434
+ .product_id = PRODUCT_ID};
+ ckbt51_set_param(&param);
+ wait_ms(10);
+}
+
+void bluetooth_enter_disconnected_kb(uint8_t host_idx) {
+ if (bt_factory_reset) {
+ ckbt51_param_init();
+ factory_timer_buffer = timer_read32();
+ }
+ /* CKBT51 bluetooth module boot time is slower, it enters disconnected after boot,
+ so we place initialization here. */
+ if (firstDisconnect && sync_timer_read32() < 1000 && get_transport() == TRANSPORT_BLUETOOTH) {
+ ckbt51_param_init();
+ bluetooth_connect();
+ firstDisconnect = false;
+ }
+}
+
+void ckbt51_default_ack_handler(uint8_t *data, uint8_t len) {
+ if (data[1] == 0x45) {
+ module_param_t param = {.event_mode = 0x02,
+ .connected_idle_timeout = 7200,
+ .pairing_timeout = 180,
+ .pairing_mode = 0,
+ .reconnect_timeout = 5,
+ .report_rate = 90,
+ .vendor_id_source = 1,
+ .verndor_id = 0, // Must be 0x3434
+ .product_id = PRODUCT_ID};
+ ckbt51_set_param(&param);
+ }
+}
+
+void bluetooth_pre_task(void) {
+ static uint8_t mode = 1;
+
+ if (readPin(USB_BT_MODE_SELECT_PIN) != mode) {
+ if (readPin(USB_BT_MODE_SELECT_PIN) != mode) {
+ mode = readPin(USB_BT_MODE_SELECT_PIN);
+ set_transport(mode == 0 ? TRANSPORT_BLUETOOTH : TRANSPORT_USB);
+ }
+ }
+}
+#endif
+
+void battery_calculte_voltage(uint16_t value) {
+ uint16_t voltage = ((uint32_t)value) * 2246 / 1000;
+
+#ifdef LED_MATRIX_ENABLE
+ if (led_matrix_is_enabled()) {
+ uint32_t totalBuf = 0;
+
+ for (uint8_t i = 0; i < DRIVER_COUNT; i++)
+ for (uint8_t j = 0; j < 192; j++)
+ totalBuf += g_pwm_buffer[i][j];
+ /* We assumpt it is linear relationship*/
+ voltage += (30 * totalBuf / LED_MATRIX_LED_COUNT / 255);
+ }
+#endif
+#ifdef RGB_MATRIX_ENABLE
+ if (rgb_matrix_is_enabled()) {
+ uint32_t totalBuf = 0;
+
+ for (uint8_t i = 0; i < DRIVER_COUNT; i++)
+ for (uint8_t j = 0; j < 192; j++)
+ totalBuf += g_pwm_buffer[i][j];
+ /* We assumpt it is linear relationship*/
+ uint32_t compensation = 60 * totalBuf / RGB_MATRIX_LED_COUNT / 255 / 3;
+ voltage += compensation;
+ }
+#endif
+ battery_set_voltage(voltage);
+}
+
+bool via_command_kb(uint8_t *data, uint8_t length) {
+ switch (data[0]) {
+#ifdef KC_BLUETOOTH_ENABLE
+ case 0xAA:
+ ckbt51_dfu_rx(data, length);
+ break;
+#endif
+#ifdef ENABLE_FACTORY_TEST
+ case 0xAB:
+ factory_test_rx(data, length);
+ break;
+#endif
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+#if !defined(VIA_ENABLE)
+void raw_hid_receive(uint8_t *data, uint8_t length) {
+ switch (data[0]) {
+ case RAW_HID_CMD:
+ via_command_kb(data, length);
+ break;
+ }
+}
+#endif