summaryrefslogtreecommitdiffstats
path: root/keyboards/keychron/bluetooth/factory_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/keychron/bluetooth/factory_test.c')
-rw-r--r--keyboards/keychron/bluetooth/factory_test.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/keyboards/keychron/bluetooth/factory_test.c b/keyboards/keychron/bluetooth/factory_test.c
new file mode 100644
index 0000000000..10fdf24d17
--- /dev/null
+++ b/keyboards/keychron/bluetooth/factory_test.c
@@ -0,0 +1,320 @@
+/* Copyright 2021 @ 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 "quantum.h"
+#include "ckbt51.h"
+#include "raw_hid.h"
+#include "transport.h"
+#include "battery.h"
+#include "via.h"
+#include "indicator.h"
+#include "lpm.h"
+
+extern bool bt_factory_reset;
+
+enum {
+ BACKLIGHT_TEST_OFF = 0,
+ BACKLIGHT_TEST_WHITE,
+ BACKLIGHT_TEST_RED,
+ BACKLIGHT_TEST_GREEN,
+ BACKLIGHT_TEST_BLUE,
+ BACKLIGHT_TEST_MAX,
+};
+
+enum {
+ KEY_PRESS_FN = 0x01 << 0,
+ KEY_PRESS_J = 0x01 << 1,
+ KEY_PRESS_Z = 0x01 << 2,
+ KEY_PRESS_RIGHT = 0x01 << 3,
+ KEY_PRESS_HOME = 0x01 << 4,
+ KEY_PRESS_FACTORY_RESET = KEY_PRESS_FN | KEY_PRESS_J | KEY_PRESS_Z,
+ KEY_PRESS_BACKLIGTH_TEST = KEY_PRESS_FN | KEY_PRESS_RIGHT | KEY_PRESS_HOME,
+};
+
+enum {
+ FACTORY_TEST_CMD_BACKLIGHT = 0x01,
+ FACTORY_TEST_CMD_OS_SWITCH,
+ FACTORY_TEST_CMD_JUMP_TO_BL,
+ FACTORY_TEST_CMD_INT_PIN,
+ FACTORY_TEST_CMD_GET_TRANSPORT,
+ FACTORY_TEST_CMD_CHARGING_ADC,
+};
+
+enum {
+ OS_SWITCH = 0x01,
+};
+
+static uint32_t factory_reset_timer = 0;
+static uint8_t factory_reset_state = 0;
+static uint8_t backlight_test_mode = BACKLIGHT_TEST_OFF;
+
+static uint32_t factory_reset_ind_timer = 0;
+static uint8_t factory_reset_ind_state = 0;
+static bool report_os_sw_state = false;
+
+void factory_timer_start(void) {
+ factory_reset_timer = sync_timer_read32() | 1;
+}
+
+static inline void factory_timer_check(void) {
+ if (sync_timer_elapsed32(factory_reset_timer) > 3000) {
+ factory_reset_timer = 0;
+
+ if (factory_reset_state == KEY_PRESS_FACTORY_RESET) {
+ factory_reset_ind_timer = sync_timer_read32() | 1;
+ factory_reset_ind_state++;
+
+ layer_state_t default_layer_tmp = default_layer_state;
+ eeconfig_init();
+ default_layer_set(default_layer_tmp);
+#ifdef LED_MATRIX_ENABLE
+ if (!led_matrix_is_enabled()) led_matrix_enable();
+ led_matrix_init();
+#endif
+#ifdef RGB_MATRIX_ENABLE
+ if (!rgb_matrix_is_enabled()) rgb_matrix_enable();
+ rgb_matrix_init();
+#endif
+#ifdef BLUETOOTH_ENABLE
+ ckbt51_factory_reset();
+ bt_factory_reset = true;
+#endif
+ } else if (factory_reset_state == KEY_PRESS_BACKLIGTH_TEST) {
+#ifdef LED_MATRIX_ENABLE
+ if (!led_matrix_is_enabled()) led_matrix_enable();
+#endif
+#ifdef RGB_MATRIX_ENABLE
+ if (!rgb_matrix_is_enabled()) rgb_matrix_enable();
+#endif
+ backlight_test_mode = BACKLIGHT_TEST_WHITE;
+ }
+
+ factory_reset_state = 0;
+ }
+}
+
+static inline void factory_reset_ind_timer_check(void) {
+ if (factory_reset_ind_timer && sync_timer_elapsed32(factory_reset_ind_timer) > 250) {
+ if (factory_reset_ind_state++ > 6) {
+ factory_reset_ind_timer = factory_reset_ind_state = 0;
+ } else {
+ factory_reset_ind_timer = sync_timer_read32() | 1;
+ }
+ }
+}
+
+void process_record_factory_reset(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case MO(1): /* fall through */
+ case MO(2):
+ case MO(3):
+ case MO(4):
+ if (record->event.pressed) {
+ factory_reset_state |= KEY_PRESS_FN;
+ } else {
+ factory_reset_state &= ~KEY_PRESS_FN;
+ factory_reset_timer = 0;
+ }
+ break;
+ case KC_J:
+ if (record->event.pressed) {
+ factory_reset_state |= KEY_PRESS_J;
+ if (factory_reset_state == 0x07) factory_timer_start();
+ } else {
+ factory_reset_state &= ~KEY_PRESS_J;
+ factory_reset_timer = 0;
+ }
+ break;
+ case KC_Z:
+ if (record->event.pressed) {
+ factory_reset_state |= KEY_PRESS_Z;
+ if (factory_reset_state == 0x07) factory_timer_start();
+ } else {
+ factory_reset_state &= ~KEY_PRESS_Z;
+ factory_reset_timer = 0;
+ }
+ break;
+ case KC_RIGHT:
+ if (record->event.pressed) {
+ if (backlight_test_mode) {
+ if (++backlight_test_mode >= BACKLIGHT_TEST_MAX) {
+ backlight_test_mode = BACKLIGHT_TEST_WHITE;
+ }
+ } else {
+ factory_reset_state |= KEY_PRESS_RIGHT;
+ if (factory_reset_state == 0x19) factory_timer_start();
+ }
+ } else {
+ factory_reset_state &= ~KEY_PRESS_RIGHT;
+ factory_reset_timer = 0;
+ }
+ break;
+ case KC_HOME:
+ if (record->event.pressed) {
+ if (backlight_test_mode) {
+ backlight_test_mode = BACKLIGHT_TEST_OFF;
+ } else {
+ factory_reset_state |= KEY_PRESS_HOME;
+ if (factory_reset_state == 0x19) factory_timer_start();
+ }
+ } else {
+ factory_reset_state &= ~KEY_PRESS_HOME;
+ factory_reset_timer = 0;
+ }
+ break;
+ }
+}
+
+#ifdef LED_MATRIX_ENABLE
+void led_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+ if (factory_reset_ind_state) {
+ for (uint8_t i = led_min; i <= led_max; i++) {
+ led_matrix_set_value(i, factory_reset_ind_state % 2 ? 0 : 255);
+ }
+ }
+}
+#endif
+
+#ifdef RGB_MATRIX_ENABLE
+void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+ if (factory_reset_ind_state) {
+ for (uint8_t i = led_min; i <= led_max; i++) {
+ rgb_matrix_set_color(i, factory_reset_ind_state % 2 ? 0 : 255, 0, 0);
+ }
+ } else if (backlight_test_mode) {
+ switch (backlight_test_mode) {
+ case BACKLIGHT_TEST_WHITE:
+ for (uint8_t i = led_min; i <= led_max; i++) {
+ rgb_matrix_set_color(i, 255, 255, 255);
+ }
+ break;
+ case BACKLIGHT_TEST_RED:
+ for (uint8_t i = led_min; i <= led_max; i++) {
+ rgb_matrix_set_color(i, 255, 0, 0);
+ }
+ break;
+ case BACKLIGHT_TEST_GREEN:
+ for (uint8_t i = led_min; i <= led_max; i++) {
+ rgb_matrix_set_color(i, 0, 255, 0);
+ }
+ break;
+ case BACKLIGHT_TEST_BLUE:
+ for (uint8_t i = led_min; i <= led_max; i++) {
+ rgb_matrix_set_color(i, 0, 0, 255);
+ }
+ break;
+ }
+ }
+}
+#endif
+
+void factory_reset_task(void) {
+ if (factory_reset_timer) factory_timer_check();
+ if (factory_reset_ind_timer) factory_reset_ind_timer_check();
+}
+
+void factory_test_send(uint8_t *payload, uint8_t length) {
+ uint16_t checksum = 0;
+ uint8_t data[RAW_EPSIZE] = {0};
+
+ uint8_t i = 0;
+ data[i++] = 0xAB;
+
+ memcpy(&data[i], payload, length);
+ i += length;
+
+ for (uint8_t i = 1; i < RAW_EPSIZE - 3; i++) checksum += data[i];
+ data[RAW_EPSIZE - 2] = checksum & 0xFF;
+ data[RAW_EPSIZE - 1] = (checksum >> 8) & 0xFF;
+
+ raw_hid_send(data, RAW_EPSIZE);
+}
+
+void factory_test_rx(uint8_t *data, uint8_t length) {
+ if (data[0] == 0xAB) {
+ uint16_t checksum = 0;
+
+ for (uint8_t i = 1; i < RAW_EPSIZE - 3; i++) {
+ checksum += data[i];
+ }
+ /* Verify checksum */
+ if ((checksum & 0xFF) != data[RAW_EPSIZE - 2] || checksum >> 8 != data[RAW_EPSIZE - 1]) return;
+
+ uint8_t payload[32];
+ uint8_t len = 0;
+
+ switch (data[1]) {
+ case FACTORY_TEST_CMD_BACKLIGHT:
+ backlight_test_mode = data[2];
+ factory_reset_timer = 0;
+ break;
+ case FACTORY_TEST_CMD_OS_SWITCH:
+ report_os_sw_state = data[2];
+ if (report_os_sw_state) {
+ dip_switch_read(true);
+ }
+ break;
+ case FACTORY_TEST_CMD_JUMP_TO_BL:
+ // if (memcmp(&data[2], "JumpToBootloader", strlen("JumpToBootloader")) == 0) bootloader_jump();
+ break;
+ case FACTORY_TEST_CMD_INT_PIN:
+ switch (data[2]) {
+ /* Enalbe/disable test */
+ case 0xA1:
+ ckbt51_int_pin_test(data[3]);
+ break;
+ /* Set INT state */
+ case 0xA2:
+ writePin(CKBT51_INT_INPUT_PIN, data[3]);
+ break;
+ /* Report INT state */
+ case 0xA3:
+ payload[len++] = FACTORY_TEST_CMD_INT_PIN;
+ payload[len++] = 0xA3;
+ payload[len++] = readPin(BLUETOOTH_INT_INPUT_PIN);
+ factory_test_send(payload, len);
+ break;
+ }
+ break;
+ case FACTORY_TEST_CMD_GET_TRANSPORT:
+ payload[len++] = FACTORY_TEST_CMD_GET_TRANSPORT;
+ payload[len++] = get_transport();
+ payload[len++] = readPin(USB_POWER_SENSE_PIN);
+ factory_test_send(payload, len);
+ break;
+#ifdef BATTERY_CHARGE_DONE_DETECT_ADC
+ case FACTORY_TEST_CMD_CHARGING_ADC:
+ case 0xA1:
+ battery_charging_monitor(data[3]);
+ break;
+ case 0xA2:
+ payload[len++] = FACTORY_TEST_CMD_CHARGING_ADC;
+ payload[len++] = battery_adc_read_charging_pin();
+ factory_test_send(payload, len);
+ break;
+#endif
+ }
+ }
+}
+
+bool dip_switch_update_user(uint8_t index, bool active) {
+ if (report_os_sw_state) {
+ uint8_t payload[3] = {FACTORY_TEST_CMD_OS_SWITCH, OS_SWITCH, active};
+ factory_test_send(payload, 3);
+ }
+
+ return true;
+}