diff options
Diffstat (limited to 'keyboards')
60 files changed, 6035 insertions, 0 deletions
diff --git a/keyboards/keychron/bluetooth/bat_level_animation.c b/keyboards/keychron/bluetooth/bat_level_animation.c new file mode 100644 index 0000000000..83a4f91cae --- /dev/null +++ b/keyboards/keychron/bluetooth/bat_level_animation.c @@ -0,0 +1,132 @@ + +#include "quantum.h" +#include "bluetooth.h" +#include "indicator.h" +#include "lpm.h" +#if defined(PROTOCOL_CHIBIOS) +# include <usb_main.h> +#elif if defined(PROTOCOL_LUFA) +# include "lufa.h" +#endif + +#ifndef BAT_LEVEL_GROWING_INTERVAL +# define BAT_LEVEL_GROWING_INTERVAL 150 +#endif + +#ifndef BAT_LEVEL_ON_INTERVAL +# define BAT_LEVEL_ON_INTERVAL 3000 +#endif + +enum { + BAT_LVL_ANI_NONE, + BAT_LVL_ANI_GROWING, + BAT_LVL_ANI_BLINK_OFF, + BAT_LVL_ANI_BLINK_ON, +}; + +static uint8_t animation_state = 0; +static uint32_t bat_lvl_ani_timer_buffer = 0; +static uint8_t bat_percentage; +static uint8_t cur_percentage; +static uint32_t time_interval; +#ifdef RGB_MATRIX_ENABLE +static uint8_t r, g, b; +#endif + +extern indicator_config_t indicator_config; +extern backlight_state_t original_backlight_state; + +void bat_level_animiation_start(uint8_t percentage) { + /* Turn on backlight mode for indicator */ + indicator_enable(); + + animation_state = BAT_LVL_ANI_GROWING; + bat_percentage = percentage; + bat_lvl_ani_timer_buffer = sync_timer_read32(); + cur_percentage = 0; + time_interval = BAT_LEVEL_GROWING_INTERVAL; +#ifdef RGB_MATRIX_ENABLE + r = g = b = 255; +#endif +} + +void bat_level_animiation_stop(void) { + animation_state = BAT_LVL_ANI_NONE; +} + +bool bat_level_animiation_actived(void) { + return animation_state; +} + +void bat_level_animiation_indicate(void) { +#ifdef LED_MATRIX_ENABLE + uint8_t bat_lvl_led_list[10] = BAT_LEVEL_LED_LIST; + + for (uint8_t i = 0; i <= DRIVER_LED_TOTAL; i++) { + led_matrix_set_value(i, 0); + } + + if (animation_state == BAT_LVL_ANI_GROWING || animation_state == BAT_LVL_ANI_BLINK_ON) + for (uint8_t i = 0; i < cur_percentage / 10; i++) + led_matrix_set_value(bat_lvl_led_list[i], 255); +#endif + +#ifdef RGB_MATRIX_ENABLE + uint8_t bat_lvl_led_list[10] = BAT_LEVEL_LED_LIST; + + for (uint8_t i = 0; i <= DRIVER_LED_TOTAL; i++) { + rgb_matrix_set_color(i, 0, 0, 0); + } + + if (animation_state == BAT_LVL_ANI_GROWING || animation_state == BAT_LVL_ANI_BLINK_ON) { + for (uint8_t i = 0; i < cur_percentage / 10; i++) { + rgb_matrix_set_color(bat_lvl_led_list[i], r, g, b); + } + } +#endif +} + +void bat_level_animiation_update(void) { + switch (animation_state) { + case BAT_LVL_ANI_GROWING: + if (cur_percentage < bat_percentage) + cur_percentage += 10; + else { + if (cur_percentage == 0) cur_percentage = 10; + animation_state = BAT_LVL_ANI_BLINK_OFF; + } + break; + + case BAT_LVL_ANI_BLINK_OFF: +#ifdef RGB_MATRIX_ENABLE + if (bat_percentage < 30) { + r = 255; + b = g = 0; + } else { + r = b = 0; + g = 255; + } +#endif + time_interval = BAT_LEVEL_ON_INTERVAL; + animation_state = BAT_LVL_ANI_BLINK_ON; + break; + + case BAT_LVL_ANI_BLINK_ON: + animation_state = BAT_LVL_ANI_NONE; + if (indicator_config.value == 0 && !indicator_is_backlit_enabled_eeprom()) { + indicator_disable(); + } + break; + + default: + break; + } + + bat_lvl_ani_timer_buffer = sync_timer_read32(); +} + +void bat_level_animiation_task(void) { + if (animation_state && sync_timer_elapsed32(bat_lvl_ani_timer_buffer) > time_interval) { + bat_level_animiation_update(); + } +} diff --git a/keyboards/keychron/bluetooth/bat_level_animation.h b/keyboards/keychron/bluetooth/bat_level_animation.h new file mode 100644 index 0000000000..716e924103 --- /dev/null +++ b/keyboards/keychron/bluetooth/bat_level_animation.h @@ -0,0 +1,23 @@ +/* Copyright 2022 @ lokher (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/>. + */ + +#pragma once + +void bat_level_animiation_start(uint8_t percentage); +void bat_level_animiation_stop(void); +bool bat_level_animiation_actived(void); +void bat_level_animiation_indicate(void); +void bat_level_animiation_task(void); diff --git a/keyboards/keychron/bluetooth/battery.c b/keyboards/keychron/bluetooth/battery.c new file mode 100644 index 0000000000..6dd453357e --- /dev/null +++ b/keyboards/keychron/bluetooth/battery.c @@ -0,0 +1,107 @@ +/* Copyright 2022 @ lokher (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 "quantum.h" +#include "bluetooth.h" +#include "battery.h" +#include "transport.h" +#include "ckbt51.h" +#include "lpm.h" + +#define BATTERY_EMPTY_COUNT 10 +#define CRITICAL_LOW_COUNT 20 + +static uint32_t bat_monitor_timer_buffer = 0; +static uint16_t voltage = FULL_VOLTAGE_VALUE; +static uint8_t bat_empty = 0; +static uint8_t critical_low = 0; +static uint8_t bat_state; + +void battery_init(void) { + bat_monitor_timer_buffer = 0; + bat_state = BAT_NOT_CHARGING; +} +__attribute__((weak)) void battery_measure(void) {} + +/* Calculate the voltage */ +__attribute__((weak)) void battery_calculate_voltage(uint16_t value) {} + +void battery_set_voltage(uint16_t value) { + voltage = value; +} + +uint16_t battery_get_voltage(void) { + return voltage; +} + +uint8_t battery_get_percentage(void) { + if (voltage > FULL_VOLTAGE_VALUE) return 100; + + if (voltage > EMPTY_VOLTAGE_VALUE) { + return ((uint32_t)voltage - EMPTY_VOLTAGE_VALUE) * 80 / (FULL_VOLTAGE_VALUE - EMPTY_VOLTAGE_VALUE) + 20; + } + + if (voltage > SHUTDOWN_VOLTAGE_VALUE) { + return ((uint32_t)voltage - SHUTDOWN_VOLTAGE_VALUE) * 20 / (EMPTY_VOLTAGE_VALUE - SHUTDOWN_VOLTAGE_VALUE); + } else + return 0; +} + +bool battery_is_empty(void) { + return bat_empty > BATTERY_EMPTY_COUNT; +} + +bool battery_is_critical_low(void) { + return critical_low > CRITICAL_LOW_COUNT; +} + +void battery_check_empty(void) { + if (voltage < EMPTY_VOLTAGE_VALUE) { + if (bat_empty <= BATTERY_EMPTY_COUNT) { + if (++bat_empty > BATTERY_EMPTY_COUNT) indicator_battery_low_enable(true); + } + } else if (bat_empty <= BATTERY_EMPTY_COUNT) { + bat_empty = BATTERY_EMPTY_COUNT; + } +} + +void battery_check_critical_low(void) { + if (voltage < SHUTDOWN_VOLTAGE_VALUE) { + if (critical_low <= CRITICAL_LOW_COUNT) { + if (++critical_low > CRITICAL_LOW_COUNT) bluetooth_low_battery_shutdown(); + } + } else if (critical_low <= CRITICAL_LOW_COUNT) { + critical_low = 0; + } +} + +void battery_task(void) { + if (get_transport() == TRANSPORT_BLUETOOTH && bluetooth_get_state() == BLUETOOTH_CONNECTED) { + if (sync_timer_elapsed32(bat_monitor_timer_buffer) > VOLTAGE_MEASURE_INTERVAL) { + battery_check_empty(); + battery_check_critical_low(); + + bat_monitor_timer_buffer = sync_timer_read32(); + battery_measure(); + } + } + + if ((bat_empty || critical_low) && usb_power_connected()) { + bat_empty = false; + critical_low = false; + indicator_battery_low_enable(false); + } +} diff --git a/keyboards/keychron/bluetooth/battery.h b/keyboards/keychron/bluetooth/battery.h new file mode 100644 index 0000000000..5d00a529c6 --- /dev/null +++ b/keyboards/keychron/bluetooth/battery.h @@ -0,0 +1,51 @@ +/* Copyright 2022 @ lokher (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/>. + */ + +#pragma once + +enum { + BAT_NOT_CHARGING = 0, + BAT_CHARGING, + BAT_CHARGING_FINISHED, +}; + +#ifndef FULL_VOLTAGE_VALUE +# define FULL_VOLTAGE_VALUE 4100 +#endif + +#ifndef EMPTY_VOLTAGE_VALUE +# define EMPTY_VOLTAGE_VALUE 3500 +#endif + +#ifndef SHUTDOWN_VOLTAGE_VALUE +# define SHUTDOWN_VOLTAGE_VALUE 3300 +#endif + +#ifndef VOLTAGE_MEASURE_INTERVAL +# define VOLTAGE_MEASURE_INTERVAL 3000 +#endif + +void battery_init(void); +void battery_measure(void); +void battery_calculte_voltage(uint16_t value); +void battery_set_voltage(uint16_t value); +uint16_t battery_get_voltage(void); +uint8_t battery_get_percentage(void); +void indicator_battery_low_enable(bool enable); +bool battery_is_empty(void); +bool battery_is_critical_low(void); + +void battery_task(void); diff --git a/keyboards/keychron/bluetooth/bluetooth.c b/keyboards/keychron/bluetooth/bluetooth.c new file mode 100644 index 0000000000..10c79257a9 --- /dev/null +++ b/keyboards/keychron/bluetooth/bluetooth.c @@ -0,0 +1,441 @@ +/* Copyright 2022 @ lokher (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 "quantum.h" +#include "bluetooth.h" +#include "report_buffer.h" +#include "lpm.h" +#include "battery.h" +#include "indicator.h" +#include "transport.h" + +extern uint8_t pairing_indication; +extern host_driver_t chibios_driver; +extern report_buffer_t kb_rpt; +extern uint32_t retry_time_buffer; +extern uint8_t retry; + +#ifdef NKRO_ENABLE +typedef struct { + bool usb : 1; + bool bluetooth : 1; +} nkro_t; + +extern nkro_t nkro; +#endif + +static uint8_t host_index = 0; +static uint8_t led_state = 0; + +extern bluetooth_transport_t bluetooth_transport; +static bluetooth_state_t bt_state = BLUETOOTH_RESET; +static bool pincodeEntry = false; +uint8_t bluetooth_report_protocol = true; + +/* declarations */ +uint8_t bluetooth_keyboard_leds(void); +void bluetooth_send_keyboard(report_keyboard_t *report); +void bluetooth_send_mouse(report_mouse_t *report); +void bluetooth_send_system(uint16_t data); +void bluetooth_send_consumer(uint16_t data); +/* host struct */ +host_driver_t bluetooth_driver = {bluetooth_keyboard_leds, bluetooth_send_keyboard, bluetooth_send_mouse, bluetooth_send_system, bluetooth_send_consumer}; + +#define BLUETOOTH_EVENT_QUEUE_SIZE 16 +bluetooth_event_t bt_event_queue[BLUETOOTH_EVENT_QUEUE_SIZE]; +uint8_t bt_event_queue_head; +uint8_t bt_event_queue_tail; + +void bluetooth_bt_event_queue_init(void) { + // Initialise the event queue + memset(&bt_event_queue, 0, sizeof(bt_event_queue)); + bt_event_queue_head = 0; + bt_event_queue_tail = 0; +} + +bool bluetooth_event_queue_enqueue(bluetooth_event_t event) { + uint8_t next = (bt_event_queue_head + 1) % BLUETOOTH_EVENT_QUEUE_SIZE; + if (next == bt_event_queue_tail) { + /* Override the first report */ + bt_event_queue_tail = (bt_event_queue_tail + 1) % BLUETOOTH_EVENT_QUEUE_SIZE; + } + bt_event_queue[bt_event_queue_head] = event; + bt_event_queue_head = next; + return true; +} + +static inline bool bluetooth_event_queue_dequeue(bluetooth_event_t *event) { + if (bt_event_queue_head == bt_event_queue_tail) { + return false; + } + *event = bt_event_queue[bt_event_queue_tail]; + bt_event_queue_tail = (bt_event_queue_tail + 1) % BLUETOOTH_EVENT_QUEUE_SIZE; + return true; +} + +/* + * Bluetooth init. + */ +void bluetooth_init(void) { + bt_state = BLUETOOTH_INITIALIZED; + + bluetooth_bt_event_queue_init(); +#ifndef DISABLE_REPORT_BUFFER + report_buffer_init(); +#endif + indicator_init(); +#ifdef BLUETOOTH_INT_INPUT_PIN + setPinInputHigh(BLUETOOTH_INT_INPUT_PIN); +#endif + + lpm_init(); +} + +/* + * Bluetooth trasponrt init. Bluetooth module driver shall use this function to register a callback + * to its implementation. + */ +void bluetooth_set_transport(bluetooth_transport_t *transport) { + if (transport) memcpy(&bluetooth_transport, transport, sizeof(bluetooth_transport_t)); +} + +/* + * Enter pairing with current host index + */ +void bluetooth_pairing(void) { + if (battery_is_critical_low()) return; + + bluetooth_pairing_ex(0, NULL); + bt_state = BLUETOOTH_PARING; +} + +/* + * Enter pairing with specified host index and param + */ +void bluetooth_pairing_ex(uint8_t host_idx, void *param) { + if (battery_is_critical_low()) return; + + if (bluetooth_transport.pairing_ex) bluetooth_transport.pairing_ex(host_idx, param); + bt_state = BLUETOOTH_PARING; + + host_index = host_idx; +} + +/* + * Initiate connection request to paired host + */ +void bluetooth_connect(void) { + /* Work around empty report after wakeup, which leads to reconneect/disconnected loop */ + if (battery_is_critical_low() || sync_timer_read32() == 0) return; + + bluetooth_transport.connect_ex(0, 0); + bt_state = BLUETOOTH_RECONNECTING; +} + +/* + * Initiate connection request to paired host with argument + */ +void bluetooth_connect_ex(uint8_t host_idx, uint16_t timeout) { + if (battery_is_critical_low()) return; + + if (host_idx != 0) { + if (host_index == host_idx && bt_state == BLUETOOTH_CONNECTED) return; + host_index = host_idx; + led_state = 0; + } + bluetooth_transport.connect_ex(host_idx, timeout); + bt_state = BLUETOOTH_RECONNECTING; +} + +/* Initiate a disconnection */ +void bluetooth_disconnect(void) { + if (bluetooth_transport.disconnect) bluetooth_transport.disconnect(); +} + + +/* Called when the BT device is reset. */ +static void bluetooth_enter_reset(uint8_t reason) { + bt_state = BLUETOOTH_RESET; + bluetooth_enter_reset_kb(reason); +} + +/* Enters discoverable state. Upon entering this state we perform the following actions: + * - change state to BLUETOOTH_PARING + * - set pairing indication + */ +static void bluetooth_enter_discoverable(uint8_t host_idx) { + bt_state = BLUETOOTH_PARING; + indicator_set(bt_state, host_idx); + bluetooth_enter_discoverable_kb(host_idx); +} + +/* + * Enters reconnecting state. Upon entering this state we perform the following actions: + * - change state to RECONNECTING + * - set reconnect indication + */ +static void bluetooth_enter_reconnecting(uint8_t host_idx) { + bt_state = BLUETOOTH_RECONNECTING; + indicator_set(bt_state, host_idx); + bluetooth_enter_reconnecting_kb(host_idx); +} + +/* Enters connected state. Upon entering this state we perform the following actions: + * - change state to CONNECTED + * - set connected indication + * - enable bluetooth NKRO is support + */ +static void bluetooth_enter_connected(uint8_t host_idx) { + bt_state = BLUETOOTH_CONNECTED; + indicator_set(bt_state, host_idx); + host_index = host_idx; |