diff --git a/keyboards/redragon/k715_pro/bluetooth/bluetooth.mk b/keyboards/redragon/k715_pro/bluetooth/bluetooth.mk
new file mode 100644
index 00000000000..ebda4b804e2
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/bluetooth.mk
@@ -0,0 +1,9 @@
+
+BLUETOOTH_DIR = bluetooth
+SRC += \
+ $(BLUETOOTH_DIR)/bluetooth_main.c \
+ $(BLUETOOTH_DIR)/btfunc.c \
+ $(BLUETOOTH_DIR)/btspi.c \
+ $(BLUETOOTH_DIR)/btsys.c
+
+VPATH += $(TOP_DIR)/keyboards/redragon/k715_pro/$(BLUETOOTH_DIR)
diff --git a/keyboards/redragon/k715_pro/bluetooth/bluetooth_main.c b/keyboards/redragon/k715_pro/bluetooth/bluetooth_main.c
new file mode 100644
index 00000000000..6486ca3e954
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/bluetooth_main.c
@@ -0,0 +1,31 @@
+/* Copyright 2024 temp4gh
+ *
+ * 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"
+
+__attribute__((weak)) void bluetooth_pre_task(void) {}
+__attribute__((weak)) void bluetooth_task(void) {}
+__attribute__((weak)) void bluetooth_post_task(void) {}
+
+void bluetooth_tasks(void) {
+ bluetooth_pre_task();
+ bluetooth_task();
+ bluetooth_post_task();
+}
+
+void housekeeping_task_kb(void) {
+ bluetooth_tasks();
+}
diff --git a/keyboards/redragon/k715_pro/bluetooth/btfunc.c b/keyboards/redragon/k715_pro/bluetooth/btfunc.c
new file mode 100644
index 00000000000..8a38de228c4
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/btfunc.c
@@ -0,0 +1,78 @@
+/* Copyright 2023 temp4gh
+ *
+ * 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
+#include "quantum.h"
+#include "btfunc.h"
+#include "btspi.h"
+#include "k715_pro.h"
+
+extern user_settings_config g_config;
+extern tDevInfo dev_info;
+
+void k715bt_send_ble_req_bt_info(void)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_GET_INFO, NULL, 0);
+}
+
+void k715bt_send_ble_req_bt_name(void)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_BT_GETNAME, NULL, 0);
+}
+
+void k715bt_send_mcu_req_ble_fwver(void)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_MCU_REQ_BT_FWVER, NULL, 0);
+}
+
+void k715bt_send_ble_switch_device_mode(uint8_t mode)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_MODE_SET, &mode, 1);
+}
+
+void k715bt_send_ble_pair(uint8_t pair_timeout, uint8_t *adv_data, uint8_t adv_data_len)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_BT_PAIR, NULL, 0);
+}
+
+void k715bt_send_ble_reconnect_bt(uint8_t reconn_timeout)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_BT_BACK, &reconn_timeout, 1);
+}
+
+void k715bt_send_ble_disconnect_bt(void)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_BT_DISCONNECT, NULL, 0);
+}
+
+void k715bt_send_ble_set_device_name(uint8_t *dev_name, uint8_t dev_name_len)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_BT_SETNAME, dev_name, dev_name_len);
+}
+
+void k715bt_send_ble_set_bt_channel(uint8_t bt_channel)
+{
+ k715bt_send_spi_extend_single_packet(KBD_CMD_BT_SETCHN, &bt_channel, 1);
+}
+
+void k715bt_switch_channel(uint8_t bt_channel)
+{
+ if(g_config.bt_ch != bt_channel)
+ {
+ k715bt_send_ble_set_bt_channel(bt_channel);
+ g_config.bt_ch = bt_channel;
+ }
+}
diff --git a/keyboards/redragon/k715_pro/bluetooth/btfunc.h b/keyboards/redragon/k715_pro/bluetooth/btfunc.h
new file mode 100644
index 00000000000..0cf8dfa99d9
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/btfunc.h
@@ -0,0 +1,30 @@
+/* Copyright 2023 temp4gh
+ *
+ * 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 "stdint.h"
+
+void k715bt_send_ble_req_bt_info(void);
+void k715bt_send_ble_req_bt_name(void);
+void k715bt_send_mcu_req_ble_fwver(void);
+void k715bt_send_ble_set_device_name(uint8_t *dev_name, uint8_t dev_name_len);
+void k715bt_send_ble_switch_device_mode(uint8_t mode);
+void k715bt_send_ble_set_bt_channel(uint8_t bt_channel);
+void k715bt_send_ble_pair(uint8_t pair_timeout, uint8_t *adv_data, uint8_t adv_data_len);
+void k715bt_send_ble_reconnect_bt(uint8_t reconn_timeout);
+void k715bt_send_ble_disconnect_bt(void);
+void k715bt_switch_channel(uint8_t bt_channel);
diff --git a/keyboards/redragon/k715_pro/bluetooth/btspi.c b/keyboards/redragon/k715_pro/bluetooth/btspi.c
new file mode 100644
index 00000000000..4875f360421
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/btspi.c
@@ -0,0 +1,1231 @@
+/* Copyright 2024 temp4gh
+ *
+ * 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
+#include "spi_master.h"
+#include "host_driver.h"
+#include "k715_pro.h"
+#include "btspi.h"
+#include "btfunc.h"
+
+#define SPI_SLAVE_NOTIFY_CMD_RETURN_VALUE (0xAAAABBBB)
+
+#define print_log(fmt,...) do{}while(0)
+
+static uint8_t spi_inited = 0;
+static uint8_t last_device_mode = INVALID_DIP_DEVICE_MODE;
+static uint8_t now_mode = KBD_BT_MODE;
+static uint8_t kbd_dev_mode;
+static uint8_t dev_mode_detect;
+static uint8_t mode_bt_state = 0;
+tDevInfo dev_info;
+
+static spi_read_data_t spi_salve_data;
+user_settings_config g_config;
+
+#define now_ms timer_read32()
+#define get_time_ms() timer_read32()
+
+static void spi_slave_start(void)
+{
+ spi_start(SPI_SLAVE_CS, false, SPI_MODE, SPI_DIVISOR);
+ wait_us(200);
+}
+
+static void spi_slave_stop(void)
+{
+ spi_stop();
+}
+
+static bool check_dip_switch_usb_mode_enabled(void)
+{
+ palSetLineMode(EXT_READ_DIP_PIN_USB_MODE, PAL_MODE_INPUT_PULLUP);
+ if(palReadLine(EXT_READ_DIP_PIN_USB_MODE) == PAL_LOW)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+static bool check_dip_switch_bt_mode_enabled(void)
+{
+ palSetLineMode(EXT_READ_DIP_PIN_BT_MODE, PAL_MODE_INPUT_PULLUP);
+ if(palReadLine(EXT_READ_DIP_PIN_BT_MODE) == PAL_LOW)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+static uint8_t check_dip_device_mode(uint8_t debug_flag)
+{
+ uint8_t ret, reboot;
+
+ reboot = 0;
+
+ if(check_dip_switch_bt_mode_enabled())
+ {
+ ret = KBD_BT_MODE;
+ }
+ else if(check_dip_switch_usb_mode_enabled())
+ {
+ ret = KBD_USB_MODE;
+ }
+ else
+ {
+ ret = KBD_POWEROFF_MODE;
+ }
+
+ if(last_device_mode == INVALID_DIP_DEVICE_MODE)
+ {
+ last_device_mode = ret;
+ }
+ else
+ {
+ if(last_device_mode != ret)
+ {
+ last_device_mode = ret;
+ reboot = 1;
+ }
+ }
+
+ if(reboot)
+ {
+ wait_ms(100);
+ mcu_reset();
+ }
+
+ return ret;
+}
+
+static uint8_t get_dev_mode_detected(void)
+{
+ return(dev_mode_detect);
+}
+
+static void init_ext_read_spi_slave_gpio(void)
+{
+ palSetLineMode(EXT_READ_SPI_SLAVE_INT_PIN, EXT_READ_SPI_SLAVE_GPIO_INIT);
+}
+
+static void set_IS31FL3733_normal_mode(void)
+{
+ palSetLineMode(EXT_IS31FL3733_SUSPEND_PIN, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetLine(EXT_IS31FL3733_SUSPEND_PIN);
+}
+
+static void init_dev_info(void)
+{
+ memset(&dev_info, 0, sizeof(dev_info));
+}
+
+static uint8_t ble_spi_notify_cmd_buf[MAX_BLE_SPI_NOTIFY_CMD_BUF_SIZE + 4];
+static uint8_t get_ble_spi_notify_cmd(void)
+{
+ return(ble_spi_notify_cmd_buf[2]);
+}
+
+static uint8_t *get_ble_spi_notify_cmd_data(void)
+{
+ return(&(ble_spi_notify_cmd_buf[3]));
+}
+
+static void set_ble_spi_notify_cmd_data_header(uint8_t cmd, uint8_t len)
+{
+ ble_spi_notify_cmd_buf[0] = SPI_BLE_PACKET_HEADER;
+ ble_spi_notify_cmd_buf[1] = len + 1;
+ ble_spi_notify_cmd_buf[2] = cmd;
+}
+
+uint8_t get_ble_spi_notify_cmd_data_length(void)
+{
+ return(ble_spi_notify_cmd_buf[1]);
+}
+
+uint8_t *get_ble_spi_notify_data(void)
+{
+ return(ble_spi_notify_cmd_buf);
+}
+
+uint8_t buffer_get_sum(uint8_t *buf, int len)
+{
+ int i;
+ uint8_t chksum = 0;
+
+ for(i = 1; i < len; i++)
+ {
+ chksum += buf[i];
+ }
+
+ return chksum;
+}
+
+int ble_spi_req_recv(uint8_t cmd, uint8_t *buf, uint8_t len, uint8_t send_req_flag)
+{
+ uint8_t data[MAX_BLE_SPI_RX_FRAME_MAX_SIZE];
+ int ret;
+ int i = 0;
+ uint8_t next_sn, rx_len;
+ int sum_err = 0;
+ uint8_t length;
+
+ spi_use_begin();
+ if(buf)
+ {
+ memset(buf, 0, len);
+ }
+
+ if(cmd == KBD_CMD_GET_INFO)
+ {
+ k715bt_send_ble_req_bt_info();
+ wait_ms(10);
+ }
+ else if(cmd == KBD_CMD_BT_GETNAME)
+ {
+ k715bt_send_ble_req_bt_name();
+ wait_ms(10);
+ }
+ else if(cmd == KBD_CMD_MCU_REQ_BT_FWVER)
+ {
+ k715bt_send_mcu_req_ble_fwver();
+ wait_ms(10);
+ }
+ else
+ {
+ k715bt_send_ble_req_bt_info();
+ wait_ms(10);
+ }
+
+ spi_slave_start();
+
+ length = MAX_BLE_SPI_RX_FRAME_MAX_SIZE;
+ next_sn = 1;
+ rx_len = 0;
+
+__SPI_RECEIVE:
+ memset(data, 0, sizeof(data));
+ ret = -1;
+
+ ret = spi_receive(data, length);
+ if(ret == SPI_STATUS_SUCCESS)
+ {
+ i = length;
+ if(data[0] == SPI_BLE_PACKET_HEADER)
+ {
+ if((data[1] == 0) || (data[1] > MAX_SPI_BLE_SINGLE_PACKET_LOAD_LENGTH))
+ {
+ sum_err = 0xF0;
+ }
+ else
+ {
+ if(data[length - 1] == buffer_get_sum(&data[0], length - 1))
+ {
+ if((cmd == KBD_CMD_UNKNOW) || ((data[2] & 0x7f) == cmd))
+ {
+ if((data[2] & 0x80) == 0x80)
+ {
+ if((data[3] & 0x7F) == next_sn)
+ {
+ next_sn += 1;
+
+ i = data[1] - 2;
+ if((rx_len + i) >= len)
+ {
+ sum_err = 0;
+ goto __EXIT;
+ }
+
+ if((i > 0) && (i < MAX_BLE_SPI_RX_FRAME_MAX_SIZE))
+ {
+ memcpy(&buf[rx_len], &data[4], i);
+ }
+
+ rx_len += i;
+
+ if((data[3] & 0x80) == 0x80)
+ {
+ cmd = data[2] & 0x7F;
+ }
+ else
+ {
+ goto __SPI_RECEIVE;
+ }
+ }
+ else
+ {
+ sum_err = 0xF2;
+ goto __EXIT;
+ }
+ }
+ else
+ {
+ len = MIN(len, (data[1] - 1));
+ if(len)
+ {
+
+ memcpy(buf, &data[3], len);
+ rx_len += len;
+ }
+
+ if(cmd == KBD_CMD_UNKNOW)
+ {
+ cmd = data[2];
+ }
+
+ }
+
+ sum_err = 0;
+ }
+ else
+ {
+ sum_err = 0xF1;
+ }
+ }
+ else
+ {
+ sum_err = 2;
+ }
+ }
+ }
+ else
+ {
+ sum_err = 0xFF;
+ }
+ }
+ else
+ {
+ sum_err = 3;
+ }
+
+__EXIT:
+ spi_slave_stop();
+ spi_use_end();
+
+ if(sum_err)
+ {
+ return 0;
+ }
+ else
+ {
+ set_ble_spi_notify_cmd_data_header((data[2] & 0x7f), rx_len);
+ return(data[2] & 0x7f);
+ }
+}
+
+static volatile uint8_t ble_spi_rx_reading = 0;
+bool is_ble_spi_rx_reading(void)
+{
+ return(ble_spi_rx_reading);
+}
+
+void set_ble_spi_rx_reading(uint8_t val)
+{
+ ble_spi_rx_reading = val;
+}
+
+uint8_t ble_spi_read_dev_info(uint8_t cmd, uint8_t send_req_flag)
+{
+ uint8_t len = MAX_SPI_BLE_SINGLE_PACKET_LENGTH;
+ uint8_t cnt = 0;
+ spi_slave_dev_info_t dinf;
+ int ret = 0;
+
+ set_ble_spi_rx_reading(1);
+
+ memset(&dinf, 0, sizeof(dinf));
+ if(cmd == KBD_CMD_GET_INFO)
+ {
+ ret = 0;
+ len = MAX_SPI_BLE_SINGLE_PACKET_LENGTH;
+ while(ret != cmd)
+ {
+ ret = ble_spi_req_recv(cmd, (uint8_t *)&dinf, len, send_req_flag);
+ if(ret == cmd)
+ {
+ break;
+ }
+
+ if(++cnt < 20)
+ {
+ wait_ms(20);
+ }
+ else
+ {
+ cmd = KBD_CMD_INVALID;
+ goto __BLE_RX_EXIT;
+ }
+ }
+
+ if(cmd == KBD_CMD_GET_INFO)
+ {
+ goto __SPI_RX_DEV_INFO;
+ }
+ else
+ {
+ goto __BLE_RX_EXIT;
+ }
+ }
+ else
+ {
+ uint8_t *rx_ptr;
+
+ ret = 0;
+ memset(ble_spi_notify_cmd_buf, 0, sizeof(ble_spi_notify_cmd_buf));
+ rx_ptr = (uint8_t *) & (ble_spi_notify_cmd_buf[3]);
+ len = MAX_BLE_SPI_NOTIFY_CMD_BUF_SIZE - 3;
+ while(ret == 0)
+ {
+ ret = ble_spi_req_recv(cmd, rx_ptr, len, send_req_flag);
+ if(ret)
+ {
+ break;
+ }
+
+ if(++cnt < 20)
+ {
+ wait_ms(20);
+ }
+ else
+ {
+ cmd = KBD_CMD_INVALID;
+ goto __BLE_RX_EXIT;
+ }
+ }
+
+ if(get_ble_spi_notify_cmd() == KBD_CMD_GET_INFO)
+ {
+ memcpy((uint8_t *)&dinf, rx_ptr, MAX_SPI_BLE_SINGLE_PACKET_LENGTH);
+ goto __SPI_RX_DEV_INFO;
+ }
+
+ cmd = get_ble_spi_notify_cmd();
+ goto __BLE_RX_EXIT;
+ }
+
+__SPI_RX_DEV_INFO:
+ spi_salve_data.spi_read_length = sizeof(dinf);
+ memcpy(spi_salve_data.spi_read_buf, (uint8_t *)&dinf, sizeof(dinf));
+
+ if(is_bt_mode_enabled())
+ {
+ dev_info.CapsLock = dinf.CapsLock;
+ dev_info.NumLock = dinf.NumLock;
+ dev_info.ScrollLock = dinf.ScrollLock;
+
+ update_caps_led();
+ }
+
+ dev_info.usbstate = dinf.state_usb;
+ if(dinf.mode != 0xff)
+ {
+ dev_info.btstate = dinf.state_bt;
+ dev_info.devmode = dinf.mode;
+ }
+
+ if(dinf.state_bt == BTSTATECONNECTED)
+ {
+ dev_info.btconnected = 1;
+ }
+ else
+ {
+ dev_info.btconnected = 0;
+ }
+
+ if(dinf.ch != 0xff)
+ {
+ if(g_config.bt_ch != dinf.ch)
+ {
+ g_config.bt_ch = dinf.ch;
+ }
+ }
+
+ cmd = KBD_CMD_GET_INFO;
+
+__BLE_RX_EXIT:
+ set_ble_spi_rx_reading(0);
+ return(cmd);
+}
+
+static int get_caps_state(void)
+{
+ int onoff;
+
+ onoff = -1;
+ if(now_mode == KBD_POWEROFF_MODE)
+ {
+ return 0;
+ }
+
+ if(is_bt_mode_enabled())
+ {
+ onoff = dev_info.CapsLock;
+ }
+ else
+ {
+ if(is_usb_mode_enabled())
+ {
+ if(host_keyboard_led_state().caps_lock)
+ {
+ onoff = 1;
+ }
+ else
+ {
+ onoff = 0;
+ }
+ }
+ }
+
+ return(onoff);
+}
+
+void update_caps_led(void)
+{
+ int onoff;
+
+ if(now_mode == KBD_POWEROFF_MODE)
+ {
+ return;
+ }
+
+ onoff = get_caps_state();
+ if(onoff == 1)
+ {
+ set_caps_lock_on();
+ }
+ else if(onoff == 0)
+ {
+ set_caps_lock_off();
+ }
+}
+
+int ble_spi_read_and_update_dev_mode(void)
+{
+ int ret;
+ unsigned short cnt;
+
+ cnt = 0;
+ while(1)
+ {
+ ret = ble_spi_read_dev_info(KBD_CMD_GET_INFO, 1);
+ if(ret == KBD_CMD_INVALID)
+ {
+ wait_ms(100);
+ }
+ else
+ {
+ uint8_t mode;
+
+ mode = get_dev_mode_detected();
+ if(dev_info.devmode != mode)
+ {
+ k715bt_send_ble_switch_device_mode(mode);
+ wait_ms(200);
+ cnt &= 0xff00;
+ cnt += 0x100;
+ if(cnt > 0xa00)
+ {
+ ret = -1;
+ break;
+ }
+ }
+ else
+ {
+ ret = 0;
+ break;
+ }
+ }
+
+ if(((++cnt) & 0xff) >= 10)
+ {
+
+ ret = -2;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+bool is_poweroff_mode_enabled(void)
+{
+ if(now_mode == KBD_POWEROFF_MODE)
+ {
+ return(true);
+ }
+
+ return false;
+}
+
+static int ble_spi_send(uint8_t cmd, uint8_t *buf, uint8_t len)
+{
+ int mul = 0;
+ uint8_t data[MAX_BLE_SPI_TX_FRAME_MAX_SIZE], s = len;
+
+ memset(data, 0, sizeof(data));
+ while(len || (buf == NULL && len == 0))
+ {
+ int i = 0;
+
+ data[i++] = SPI_BLE_PACKET_HEADER;
+ if(len > MAX_SPI_BLE_SINGLE_PACKET_LENGTH || mul)
+ {
+ mul++;
+ if(len > MAX_SPI_BLE_MUL_PACKET_LENGTH)
+ {
+ data[i++] = MAX_SPI_BLE_MUL_PACKET_LENGTH + 2;
+ data[i++] = cmd | 0x80;
+ data[i++] = mul;
+ s = MAX_SPI_BLE_MUL_PACKET_LENGTH;
+ }
+ else
+ {
+ data[i++] = len + 2;
+ data[i++] = cmd | 0x80;
+ data[i++] = mul | 0x80;
+ s = len;
+ }
+ }
+ else
+ {
+ data[i++] = len + 1;
+ data[i++] = cmd;
+ s = len;
+ }
+
+ if(buf && s)
+ {
+ memcpy(&data[i], buf, s);
+ }
+
+ data[s + i] = buffer_get_sum(data, s + i);
+
+ spi_slave_start();
+ spi_transmit(data, s + i + 1);
+ spi_slave_stop();
+
+ if(len >= s)
+ {
+ len -= s;
+ if(len)
+ {
+ wait_us(200);
+ }
+ }
+
+ if(len == 0)
+ {
+ break;
+ }
+
+ if(buf)
+ {
+ buf += s;
+ }
+ }
+
+ return 0;
+}
+
+void k715bt_send_spi_extend_single_packet(uint8_t param_type, uint8_t *param_data, uint8_t param_len)
+{
+ if(is_poweroff_mode_enabled())
+ {
+ return;
+ }
+
+ if(is_ble_spi_rx_reading())
+ {
+ uint8_t loop_count = 0;
+ while(1)
+ {
+ wait_ms(2);
+ if(!is_ble_spi_rx_reading() || (++loop_count >= 20))
+ {
+ break;
+ }
+ }
+ }
+
+ if(spi_inited)
+ {
+ ble_spi_send(param_type, param_data, param_len);
+ }
+}
+
+static void init_user_settings(void)
+{
+ memset(&g_config, 0, sizeof(g_config));
+
+ g_config.magic_num = KB_MAGIC_NUMBER;
+ g_config.kbd_dev_mode = 0xFF;
+ g_config.bt_ch = BT_CHANNEL_1;
+ g_config.bt_last_connected = BT_CHANNEL_INVALID;
+}
+
+static int req_ble_exchange(uint8_t req_cmd, uint8_t ack_cmd, uint8_t *data, uint8_t len)
+{
+ int ret = 0;
+ uint8_t read_count = 0;
+
+__LOOP_READ_CMD:
+ memset(data, 0, len);
+ ret = ble_spi_req_recv(req_cmd, data, len, 1);
+ if(ret != ack_cmd)
+ {
+ read_count++;
+ if(read_count < 20)
+ {
+ wait_ms(20);
+ goto __LOOP_READ_CMD;
+ }
+ else
+ {
+ memset(data, 0, len);
+ }
+ }
+ else
+ {
+ ret = 1;
+ }
+
+ return ret;
+}
+
+#define BT_FW_VERINFO_LEN 19
+static uint8_t bt_mac_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+static uint8_t bt_fw_verinfo[BT_FW_VERINFO_LEN + 1] = {0};
+
+uint8_t *get_bt_mac_addr(void)
+{
+ return(bt_mac_addr);
+}
+
+uint8_t *get_bt_fw_verinfo(uint8_t *len)
+{
+ *len = BT_FW_VERINFO_LEN;
+ return(bt_fw_verinfo);
+}
+
+int init_req_bt_ver(void)
+{
+ int ret;
+ uint8_t data[48];
+
+ ret = req_ble_exchange(KBD_CMD_MCU_REQ_BT_FWVER, KBD_CMD_MCU_REQ_BT_FWVER, data, sizeof(data));
+ if(ret)
+ {
+ memset(bt_fw_verinfo, 0, sizeof(bt_fw_verinfo));
+ memcpy(bt_fw_verinfo, data, BT_FW_VERINFO_LEN);
+ memcpy(bt_mac_addr, &(data[BT_FW_VERINFO_LEN]), 6);
+
+ print_log("BT fw version:%s\r\n", bt_fw_verinfo);
+ print_log("BT addr:%02X:%02X:%02X:%02X:%02X:%02X\r\n", bt_mac_addr[0], bt_mac_addr[1], \
+ bt_mac_addr[2], bt_mac_addr[3], \
+ bt_mac_addr[4], bt_mac_addr[5]);
+ }
+
+ return 0;
+}
+
+uint8_t get_active_bt_chn(void)
+{
+ return(g_config.bt_ch);
+}
+
+#define DEFAULT_BT_NAME "BLE Keyboard"
+void send_bt_name_with_chn(uint8_t chn)
+{
+ k715bt_send_ble_set_device_name((uint8_t *)DEFAULT_BT_NAME, strlen(DEFAULT_BT_NAME));
+}
+
+void ble_mark_bt_disconnected(void)
+{
+ dev_info.btconnected = 0;
+}
+
+void set_dev_info_bt_timeout(uint32_t timeout, int flag)
+{
+ if(timeout == 0)
+ {
+ if(flag)
+ {
+ dev_info.bt_timeout = timeout;
+ }
+ else
+ {
+ dev_info.bt_timeout = BT_BP_TIMEOUT - RF_TIMEOUT_OFFSET + get_time_ms();
+ }
+ }
+ else
+ {
+ dev_info.bt_timeout = timeout;
+ }
+}
+
+void set_dev_info_bt_pair_timeout(void)
+{
+ set_dev_info_bt_timeout(0, 0);
+}
+
+void set_dev_info_bt_reconn_timeout(void)
+{
+ set_dev_info_bt_timeout(BT_BACK_TIMEOUT - RF_TIMEOUT_OFFSET + get_time_ms(), 1);
+}
+
+int sys_tk_diff(uint32_t now, uint32_t start_time, int flag)
+{
+ int ret;
+
+ if(now > start_time)
+ {
+ ret = 10;
+ }
+ else
+ {
+ ret = timer_elapsed32(start_time);
+ }
+
+ if(ret >= 10)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+bool is_bt_mode_enabled(void)
+{
+ if(mode_bt_state)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool is_usb_mode_enabled(void)
+{
+ if(now_mode == KBD_USB_MODE)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+static uint8_t last_spi_notify_line_level = 0xFF;
+void invlaid_read_spi_slave_line(void)
+{
+ last_spi_notify_line_level = EXT_READ_SPI_SLAVE_READY;
+}
+
+int check_read_spi_slave_line(void)
+{
+ uint8_t line_level;
+ int ret = 0;
+
+ line_level = palReadLine(EXT_READ_SPI_SLAVE_INT_PIN);
+ if(line_level != last_spi_notify_line_level)
+ {
+ if(last_spi_notify_line_level != 0xFF)
+ {
+ last_spi_notify_line_level = line_level;
+ if(line_level == EXT_READ_SPI_SLAVE_READY)
+ {
+ ret = 1;
+ }
+ }
+ else
+ {
+ last_spi_notify_line_level = line_level;
+ if(line_level == EXT_READ_SPI_SLAVE_READY)
+ {
+ ret = 1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void send_mcu_fwver_to_ble(void)
+{
+ uint8_t buf[14];
+
+ memset(buf, 0, sizeof(buf));
+
+ sprintf((char *)buf, "%d.%d.%d", (DEVICE_VER >> 8) & 0x000F, (DEVICE_VER >> 4) & 0x000F, DEVICE_VER & 0x000F);
+ k715bt_send_spi_extend_single_packet(KBD_CMD_SEND_BT_MCU_FWVER, buf, strlen((char *)buf));
+}
+
+void ble_spi_slave_cmd_notify(void)
+{
+ uint8_t rx_cmd;
+ uint8_t *rx_data;
+
+ rx_cmd = get_ble_spi_notify_cmd();
+ rx_data = get_ble_spi_notify_cmd_data();
+
+ switch(rx_cmd)
+ {
+ case KBD_CMD_MCU_RECV_BT_FWVER:
+ {
+ uint8_t offset = BT_FW_VERINFO_LEN;
+
+ memset(bt_fw_verinfo, 0, sizeof(bt_fw_verinfo));
+ memcpy(bt_fw_verinfo, rx_data, sizeof(bt_fw_verinfo) - 1);
+ memcpy(bt_mac_addr, &(rx_data[offset]), 6);
+
+ print_log("BT fw version:%s\r\n", bt_fw_verinfo);
+ print_log("BT addr:%02X:%02X:%02X:%02X:%02X:%02X\r\n", bt_mac_addr[0], bt_mac_addr[1], \
+ bt_mac_addr[2], bt_mac_addr[3], \
+ bt_mac_addr[4], bt_mac_addr[5]);
+
+ break;
+ }
+
+ case KBD_CMD_BT_REQ_MCU_FWVER:
+ {
+ send_mcu_fwver_to_ble();
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+uint32_t ble_spi_slave_data_decode(uint32_t mode_set_timeout)
+{
+ uint8_t state_before_sleep;
+ uint32_t last_key_ms;
+
+ if(now_ms > mode_set_timeout)
+ {
+ uint8_t cmd;
+
+ cmd = ble_spi_read_dev_info(KBD_CMD_UNKNOW, 0);
+
+ if(cmd == KBD_CMD_INVALID)
+ {
+ return 0xFFFFFFFF;
+ }
+
+
+ if(cmd != KBD_CMD_GET_INFO)
+ {
+ return SPI_SLAVE_NOTIFY_CMD_RETURN_VALUE;
+ }
+
+ mode_set_timeout = 0xffffffff;
+ {
+ if(dev_info.devmode == KBD_BT_MODE)
+ {
+ char b = dev_info.btback;
+ char p = dev_info.btpair;
+
+ if(g_config.bt_ch == 0)
+ {
+ g_config.bt_ch = BT_CHANNEL_1;
+ }
+
+ if(dev_info.btstate == BTSTATEDISCONN)
+ {
+ ble_mark_bt_disconnected();
+ if(dev_info.bt_timeout && sys_tk_diff(now_ms, dev_info.bt_timeout, 0) && (p || b))
+ {
+ dev_info.bt_timeout = 0;
+ if(dev_info.btback)
+ {
+ dev_info.btback = 0;
+ }
+
+ if(dev_info.btpair)
+ {
+ dev_info.btpair = 0;
+ if(g_config.bt_last_connected == g_config.bt_ch)
+ {
+ if(g_config.bt_used & (1 << (g_config.bt_ch - 1)))
+ {
+ dev_info.btback = 1;
+ k715bt_send_ble_reconnect_bt(BT_BACK_TIMEOUT / 1000);
+ set_dev_info_bt_reconn_timeout();
+ }
+ }
+ }
+ }
+ else if(p && dev_info.bt_timeout)
+ {
+ dev_info.btpair = 1;
+ k715bt_send_ble_pair(BT_BP_TIMEOUT / 1000, NULL, 0);
+ }
+ else if(b && dev_info.bt_timeout)
+ {
+ dev_info.btback = 1;
+ k715bt_send_ble_reconnect_bt(BT_BACK_TIMEOUT / 1000);
+ }
+ else
+ {
+ if(g_config.bt_used & (1 << (g_config.bt_ch - 1)))
+ {
+ dev_info.btback = 1;
+ dev_info.btpair = 0;
+ k715bt_send_ble_reconnect_bt(BT_BACK_TIMEOUT / 1000);
+ set_dev_info_bt_reconn_timeout();
+ }
+ else
+ {
+ dev_info.btpair = 1;
+ dev_info.btback = 0;
+ k715bt_send_ble_pair(BT_BP_TIMEOUT / 1000, NULL, 0);
+ set_dev_info_bt_pair_timeout();
+ }
+ last_key_ms = now_ms;
+ }
+
+ if((dev_info.btpair || dev_info.btback) != (b || p))
+ {
+ mode_set_timeout = now_ms + 2000;
+ }
+ }
+ else if(dev_info.btstate == BTSTATEDISCOVER)
+ {
+ state_before_sleep = dev_info.btstate;
+ ble_mark_bt_disconnected();
+
+ if(dev_info.btpair == 0)
+ {
+ dev_info.btpair = 1;
+ if(dev_info.bt_timeout == 0)
+ {
+ set_dev_info_bt_pair_timeout();
+ last_key_ms = now_ms;
+ }
+ }
+
+ dev_info.btback = 0;
+ }
+ else if(dev_info.btstate == BTSTATECONNECTED)
+ {
+ last_key_ms = now_ms;
+ state_before_sleep = dev_info.btstate;
+ if((g_config.bt_used & (1 << (g_config.bt_ch - 1))) == 0
+ && dev_info.btback == 0
+ && dev_info.btpair == 0)
+ {
+ ble_mark_bt_disconnected();
+
+ dev_info.btpair = 1;
+ k715bt_send_ble_pair(BT_BP_TIMEOUT / 1000, NULL, 0);
+ set_dev_info_bt_pair_timeout();
+ }
+ else
+ {
+ b = g_config.bt_used;
+ last_key_ms = get_time_ms();
+
+ dev_info.btback = 0;
+ dev_info.btpair = 0;
+ dev_info.bt_timeout = 0;
+ dev_info.btconnected = 1;
+ g_config.bt_last_connected = g_config.bt_ch;
+ g_config.bt_used |= (1 << (g_config.bt_ch - 1));
+ }
+ }
+ else if(dev_info.btstate == BTSTATERECONN)
+ {
+ state_before_sleep = dev_info.btstate;
+ ble_mark_bt_disconnected();
+
+ if(dev_info.btback == 0)
+ {
+ if((g_config.bt_used & (1 << (g_config.bt_ch - 1))) == 0)
+ {
+ dev_info.btpair = 1;
+ k715bt_send_ble_pair(BT_BP_TIMEOUT / 1000, NULL, 0);
+ set_dev_info_bt_pair_timeout();
+ }
+ else
+ {
+ dev_info.btback = 1;
+ if(dev_info.bt_timeout == 0)
+ {
+ set_dev_info_bt_reconn_timeout();
+ }
+
+ dev_info.btpair = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ (void)state_before_sleep;
+ (void)last_key_ms;
+
+ return 0;
+}
+
+void check_read_spi_data(void)
+{
+ if(!is_bt_mode_enabled())
+ {
+ return;
+ }
+
+ if(check_read_spi_slave_line())
+ {
+ uint32_t ret = 0;
+
+ ret = ble_spi_slave_data_decode(0);
+ if(ret == SPI_SLAVE_NOTIFY_CMD_RETURN_VALUE)
+ {
+ ble_spi_slave_cmd_notify();
+ invlaid_read_spi_slave_line();
+ }
+ else if(ret != 0xFFFFFFFF)
+ {
+ invlaid_read_spi_slave_line();
+ }
+ }
+}
+
+void k715_bt_start_pair(uint8_t chn)
+{
+ ble_mark_bt_disconnected();
+
+ k715bt_switch_channel(chn);
+
+ dev_info.btpair = 1;
+ dev_info.btback = 0;
+ set_dev_info_bt_pair_timeout();
+ k715bt_send_ble_pair(BT_BP_TIMEOUT_MS, NULL, 0);
+}
+
+void k715_ble_spi_init(void)
+{
+ spi_init();
+ spi_inited = 1;
+
+ wait_ms(500);
+
+ dev_mode_detect = check_dip_device_mode(1);
+ now_mode = dev_mode_detect;
+
+ init_ext_read_spi_slave_gpio();
+
+ init_user_settings();
+ kbd_dev_mode = g_config.kbd_dev_mode;
+
+ if(now_mode == KBD_BT_MODE)
+ {
+ mode_bt_state = 1;
+ }
+ else
+ {
+ mode_bt_state = 0;
+ }
+
+ init_dev_info();
+ wait_ms(500);
+ set_IS31FL3733_normal_mode();
+
+ if(now_mode != KBD_POWEROFF_MODE)
+ {
+ ble_spi_read_and_update_dev_mode();
+ }
+
+ init_req_bt_ver();
+
+ if(now_mode == KBD_BT_MODE)
+ {
+ send_bt_name_with_chn(get_active_bt_chn());
+ wait_ms(20);
+ }
+
+ if(now_mode != KBD_POWEROFF_MODE)
+ {
+ k715bt_send_ble_switch_device_mode(now_mode);
+ if(now_mode != kbd_dev_mode)
+ {
+ if(now_mode == KBD_BT_MODE)
+ {
+ wait_ms(500);
+ }
+ }
+ }
+
+ if(now_mode != kbd_dev_mode)
+ {
+ kbd_dev_mode = now_mode;
+ g_config.kbd_dev_mode = kbd_dev_mode;
+ }
+
+ if(now_mode != KBD_USB_MODE)
+ {
+ if(now_mode == KBD_BT_MODE)
+ {
+ if(g_config.bt_used & (1 << (g_config.bt_ch - 1)))
+ {
+ if(!dev_info.btconnected)
+ {
+ ble_mark_bt_disconnected();
+
+ k715bt_send_ble_set_bt_channel(g_config.bt_ch);
+ wait_ms(20);
+
+ dev_info.btback = 1;
+ dev_info.btpair = 0;
+ k715bt_send_ble_reconnect_bt(BT_BACK_TIMEOUT / 1000);
+ set_dev_info_bt_reconn_timeout();
+ }
+ else
+ {
+ uint8_t b;
+
+ b = g_config.bt_used;
+ dev_info.btback = 0;
+ dev_info.btpair = 0;
+ dev_info.bt_timeout = 0;
+ dev_info.btconnected = 1;
+ g_config.bt_last_connected = g_config.bt_ch;
+ g_config.bt_used |= (1 << (g_config.bt_ch - 1));
+
+ if(b != g_config.bt_used)
+ {
+ }
+ }
+ }
+ else
+ {
+ ble_mark_bt_disconnected();
+
+ k715bt_send_ble_set_bt_channel(g_config.bt_ch);
+ wait_ms(20);
+
+ dev_info.btpair = 1;
+ dev_info.btback = 0;
+ k715bt_send_ble_pair(BT_BP_TIMEOUT / 1000, NULL, 0);
+ set_dev_info_bt_pair_timeout();
+ }
+ }
+ }
+}
diff --git a/keyboards/redragon/k715_pro/bluetooth/btspi.h b/keyboards/redragon/k715_pro/bluetooth/btspi.h
new file mode 100644
index 00000000000..a9b9181f6db
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/btspi.h
@@ -0,0 +1,204 @@
+/* Copyright 2023 temp4gh
+ *
+ * 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 "quantum.h"
+
+#define ENABLE_SPI_BLE_MODULE
+
+#define SPI_MODE 3
+#define SPI_DIVISOR 32
+
+#define IS31FL3733_POWERON_PIN B2
+#define EXT_IS31FL3733_SUSPEND_PIN (IS31FL3733_POWERON_PIN)
+
+#define EXT_READ_DIP_PIN_USB_MODE C13
+#define EXT_READ_DIP_PIN_BT_MODE C14
+
+#define CAPS_LOCK_DRV_PIN B8
+#define set_caps_lock_on() palClearLine(CAPS_LOCK_DRV_PIN)
+#define set_caps_lock_off() palSetLine(CAPS_LOCK_DRV_PIN)
+
+#define EXT_READ_SPI_SLAVE_INT_PIN B9
+#define EXT_READ_SPI_SLAVE_GPIO_INIT (PAL_MODE_INPUT_PULLUP)
+#define EXT_READ_SPI_SLAVE_READY (PAL_LOW)
+#define EXT_READ_SPI_SLAVE_NOT_READY (PAL_HIGH)
+
+#define KBD_BT_MODE 0
+#define KBD_USB_MODE 2
+#define KBD_POWEROFF_MODE 8
+#define INVALID_DIP_DEVICE_MODE 0xFF
+
+#define DEVICE_MODE_BT KBD_BT_MODE
+#define DEVICE_MODE_2D4G KBD_24G_MODE
+#define DEVICE_MODE_USB KBD_USB_MODE
+
+#define BTSTATEDISCONN 0
+#define BTSTATEDISCOVER 1
+#define BTSTATECONNECTED 2
+#define BTSTATERECONN 3
+
+#define BT_CHANNEL_1 1
+#define BT_CHANNEL_INVALID 0xFF
+
+#define BT_BACK_TIMEOUT 60000
+#define BT_BACK_TIMEOUT_MS ((BT_BACK_TIMEOUT) / 1000)
+
+#define BT_BP_TIMEOUT 60000
+#define BT_BP_TIMEOUT_MS ((BT_BP_TIMEOUT) / 1000)
+
+//means use default value
+#define DEFAULT_BT_BP_TIMEOUT 0
+
+//based on ms
+#define RF_TIMEOUT_OFFSET 1000
+
+#define MAX_SPI_BLE_SINGLE_PACKET_LENGTH 12
+#define MAX_SPI_BLE_MUL_PACKET_LENGTH 11
+#define MAX_SPI_BLE_SINGLE_PACKET_LOAD_LENGTH 13
+#define MAX_BLE_SPI_RX_FRAME_MAX_SIZE 16
+#define MAX_BLE_SPI_TX_FRAME_MAX_SIZE (MAX_BLE_SPI_RX_FRAME_MAX_SIZE)
+#define MAX_BLE_SPI_NOTIFY_CMD_BUF_SIZE (32)
+
+#define SPI_BLE_PACKET_HEADER 0x5A
+
+#define SEND_BT_NAME_DELAY_MS 10
+
+#define KBD_CMD_UNKNOW 0x0
+#define KBD_CMD_MODE_SET 0x11
+#define KBD_CMD_BT_PAIR 0x21
+#define KBD_CMD_BT_BACK 0x22
+#define KBD_CMD_BT_DISCONNECT 0x23
+#define KBD_CMD_BT_SETNAME 0x25
+#define KBD_CMD_BT_GETNAME 0x26
+#define KBD_CMD_BT_SETCHN 0x27
+#define KBD_CMD_GET_INFO 0x51
+#define KBD_CMD_INVALID 0x0
+
+#define KBD_CMD_BT_QUERY_KEY_STATE 0x66
+#define KBD_CMD_MCU_RESP_KEY_STATE 0x67
+#define KBD_CMD_QUERY_LOST_KEY_STATE 0x68
+
+#define KBD_CMD_SEND_BT_TEST_RF 0x71
+#define KBD_CMD_MCU_REQ_BT_FWVER 0x72
+#define KBD_CMD_MCU_RECV_BT_FWVER 0x72
+#define KBD_CMD_BT_REQ_MCU_FWVER 0x73
+#define KBD_CMD_SEND_BT_MCU_FWVER 0x73
+#define KBD_CMD_BT_REQ_DEV_STATUS 0x74
+#define KBD_CMD_SEND_BT_DEV_STATUS 0x74
+#define KBD_CMD_BT_REQ_LIGHT_CONTROL 0x75
+#define KBD_CMD_BT_REQ_DEEP_SLEEP 0x76
+#define KBD_CMD_BT_SET_TEST_MODE 0x77
+
+typedef struct
+{
+ uint32_t NumLock: 1;
+ uint32_t CapsLock: 1;
+ uint32_t ScrollLock: 1;
+ uint32_t red: 1;
+ uint32_t green: 1;
+ uint32_t blue: 1;
+ uint32_t win_lock: 1;
+ uint32_t kbd_lock: 1;
+
+ uint32_t btstate: 2;
+ uint32_t wifistate: 3;
+ uint32_t btpair: 1;
+ uint32_t btback: 1;
+ uint32_t lowVoltage: 1;
+
+ uint32_t devmode: 7;
+ uint32_t btconnected: 1;
+
+ uint32_t usbstate: 3;
+ uint32_t fn_down: 1;
+ uint32_t pair: 1;
+ uint32_t res_bt_isr: 1;
+ uint32_t usb_connected: 2;
+
+ uint32_t last_key_ms;
+ uint32_t bt_timeout;
+} tDevInfo;
+
+#define BLE_SPI_RX_BUF_MAX_SIZE 20
+typedef struct
+{
+ uint8_t spi_read_buf[BLE_SPI_RX_BUF_MAX_SIZE];
+ uint8_t spi_read_length;
+} spi_read_data_t;
+
+typedef struct __attribute__((__packed__))
+{
+ uint32_t NumLock: 1;
+ uint32_t CapsLock: 1;
+ uint32_t ScrollLock: 1;
+ uint32_t res: 1;
+ uint32_t remote_btn_down: 1;
+ uint32_t remote_btn_dec: 1;
+ uint32_t remote_btn_add: 1;
+ uint32_t remote_chg: 1;
+ uint32_t state_bt: 8;
+ uint32_t state_24g: 8;
+ uint32_t state_usb: 8;
+ uint8_t mode;
+ uint8_t eff_mode;
+ uint8_t eff_bright;
+ uint8_t eff_speed;
+ uint8_t eff_r;
+ uint8_t eff_g;
+ uint8_t eff_b;
+ uint8_t ch;
+}
+spi_slave_dev_info_t;
+
+#define KB_MAGIC_NUMBER 0xBE
+typedef struct
+{
+ uint8_t magic_num;
+
+ uint8_t caps_lock: 1;
+ uint8_t num_lock: 1;
+ uint8_t scroll_lock: 1;
+ uint8_t winlock_state: 1;
+
+ uint8_t kbd_lock: 1;
+ uint8_t reset_factory: 1;
+ uint8_t reserved_bit: 2;
+
+ uint8_t kbd_dev_mode;
+ uint8_t bt_ch;
+ uint8_t bt_used;
+ uint8_t bt_last_connected;
+
+ uint8_t reset_reason;
+ uint8_t unused;
+} user_settings_config;
+
+#define spi_use_begin() do{}while(0)
+#define spi_use_end() do{}while(0)
+
+#define kbd_spi_send_byte(_t_) spi_write(_t_)
+#define kbd_spi_rec_byte(_t_) spi_read()
+
+void set_dev_info_bt_pair_timeout(void);
+void set_dev_info_bt_reconn_timeout(void);
+void check_read_spi_data(void);
+void update_caps_led(void);
+void k715_bt_start_pair(uint8_t chn);
+bool is_usb_mode_enabled(void);
+bool is_bt_mode_enabled(void);
+void k715_ble_spi_init(void);
+void k715bt_send_spi_extend_single_packet(uint8_t param_type, uint8_t *param_data, uint8_t param_len);
diff --git a/keyboards/redragon/k715_pro/bluetooth/btsys.c b/keyboards/redragon/k715_pro/bluetooth/btsys.c
new file mode 100644
index 00000000000..e2221dbcdab
--- /dev/null
+++ b/keyboards/redragon/k715_pro/bluetooth/btsys.c
@@ -0,0 +1,50 @@
+/* Copyright 2024 temp4gh
+ *
+ * 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 "config.h"
+#include "btspi.h"
+
+void init_set_IS31FL3733_poweron(void)
+{
+ palSetLineMode(IS31FL3733_POWERON_PIN, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetLine(IS31FL3733_POWERON_PIN);
+}
+
+void bootloader_jump(void)
+{
+ NVIC_SystemReset();
+}
+
+void mcu_reset(void)
+{
+ NVIC_SystemReset();
+}
+
+void board_init(void)
+{
+ AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_DISABLE;
+
+ palSetLineMode(CAPS_LOCK_DRV_PIN, PAL_MODE_OUTPUT_PUSHPULL);
+ set_caps_lock_off();
+
+ palSetPadMode(GPIOC, 11, PAL_MODE_INPUT);
+ palSetPadMode(GPIOA, 13, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetPadMode(GPIOA, 14, PAL_MODE_OUTPUT_PUSHPULL);
+ palSetPadMode(GPIOA, 15, PAL_MODE_OUTPUT_PUSHPULL);
+
+ init_set_IS31FL3733_poweron();
+}
diff --git a/keyboards/redragon/k715_pro/config.h b/keyboards/redragon/k715_pro/config.h
new file mode 100644
index 00000000000..45e08cfe5f2
--- /dev/null
+++ b/keyboards/redragon/k715_pro/config.h
@@ -0,0 +1,27 @@
+/* Copyright 2023 temp4gh
+ *
+ * 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 IS31FL3733_I2C_ADDRESS_1 IS31FL3733_I2C_ADDRESS_GND_GND
+#define IS31FL3733_I2C_ADDRESS_2 IS31FL3733_I2C_ADDRESS_GND_VCC
+
+#define SPI_DRIVER SPID2
+#define SPI_SCK_PIN B13
+#define SPI_MOSI_PIN B15
+#define SPI_MISO_PIN B14
+
+#define SPI_SLAVE_CS B12
diff --git a/keyboards/redragon/k715_pro/halconf.h b/keyboards/redragon/k715_pro/halconf.h
new file mode 100644
index 00000000000..42b470bae5a
--- /dev/null
+++ b/keyboards/redragon/k715_pro/halconf.h
@@ -0,0 +1,28 @@
+/* Copyright 2020 QMK
+ *
+ * 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 HAL_USE_I2C
+#define HAL_USE_I2C TRUE
+
+#undef HAL_USE_SPI
+#define HAL_USE_SPI TRUE
+
+#undef SPI_SELECT_MODE
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
diff --git a/keyboards/redragon/k715_pro/k715_pro.c b/keyboards/redragon/k715_pro/k715_pro.c
new file mode 100644
index 00000000000..2b8bb311f72
--- /dev/null
+++ b/keyboards/redragon/k715_pro/k715_pro.c
@@ -0,0 +1,303 @@
+/* Copyright 2023 temp4gh
+ *
+ * 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
+#include "spi_master.h"
+#include "host_driver.h"
+#include "config.h"
+
+#include "k715_pro.h"
+#include "btspi.h"
+
+const is31fl3733_led_t PROGMEM g_is31fl3733_leds[IS31FL3733_LED_COUNT] =
+{
+ {0, SW7_CS1, SW9_CS1, SW8_CS1},
+ {0, SW7_CS3, SW9_CS3, SW8_CS3},
+ {0, SW7_CS4, SW9_CS4, SW8_CS4},
+ {0, SW7_CS5, SW9_CS5, SW8_CS5},
+ {0, SW7_CS6, SW9_CS6, SW8_CS6},
+ {0, SW7_CS7, SW9_CS7, SW8_CS7},
+ {0, SW7_CS8, SW9_CS8, SW8_CS8},
+ {0, SW7_CS9, SW9_CS9, SW8_CS9},
+ {0, SW7_CS10, SW9_CS10, SW8_CS10},
+ {0, SW7_CS11, SW9_CS11, SW8_CS11},
+ {0, SW7_CS12, SW9_CS12, SW8_CS12},
+ {0, SW7_CS13, SW9_CS13, SW8_CS13},
+ {0, SW7_CS14, SW9_CS14, SW8_CS14},
+ {0, SW7_CS15, SW9_CS15, SW8_CS15},
+ {0, SW4_CS1, SW6_CS1, SW5_CS1},
+ {0, SW4_CS2, SW6_CS2, SW5_CS2},
+ {0, SW4_CS3, SW6_CS3, SW5_CS3},
+ {0, SW4_CS4, SW6_CS4, SW5_CS4},
+ {0, SW4_CS5, SW6_CS5, SW5_CS5},
+ {0, SW4_CS6, SW6_CS6, SW5_CS6},
+ {0, SW4_CS7, SW6_CS7, SW5_CS7},
+ {0, SW4_CS8, SW6_CS8, SW5_CS8},
+ {0, SW4_CS9, SW6_CS9, SW5_CS9},
+ {0, SW4_CS10, SW6_CS10, SW5_CS10},
+ {0, SW4_CS11, SW6_CS11, SW5_CS11},
+ {0, SW4_CS12, SW6_CS12, SW5_CS12},
+ {0, SW4_CS13, SW6_CS13, SW5_CS13},
+ {0, SW4_CS14, SW6_CS14, SW5_CS14},
+ {0, SW4_CS15, SW6_CS15, SW5_CS15},
+ {0, SW1_CS1, SW3_CS1, SW2_CS1},
+ {0, SW1_CS2, SW3_CS2, SW2_CS2},
+ {0, SW1_CS3, SW3_CS3, SW2_CS3},
+ {0, SW1_CS4, SW3_CS4, SW2_CS4},
+ {0, SW1_CS5, SW3_CS5, SW2_CS5},
+ {0, SW1_CS6, SW3_CS6, SW2_CS6},
+ {0, SW1_CS7, SW3_CS7, SW2_CS7},
+ {0, SW1_CS8, SW3_CS8, SW2_CS8},
+ {0, SW1_CS9, SW3_CS9, SW2_CS9},
+ {0, SW1_CS10, SW3_CS10, SW2_CS10},
+ {0, SW1_CS11, SW3_CS11, SW2_CS11},
+ {0, SW1_CS12, SW3_CS12, SW2_CS12},
+ {0, SW1_CS13, SW3_CS13, SW2_CS13},
+ {0, SW1_CS14, SW3_CS14, SW2_CS14},
+ {0, SW1_CS15, SW3_CS15, SW2_CS15},
+ {1, SW7_CS1, SW9_CS1, SW8_CS1},
+ {1, SW7_CS2, SW9_CS2, SW8_CS2},
+ {1, SW7_CS3, SW9_CS3, SW8_CS3},
+ {1, SW7_CS4, SW9_CS4, SW8_CS4},
+ {1, SW7_CS5, SW9_CS5, SW8_CS5},
+ {1, SW7_CS6, SW9_CS6, SW8_CS6},
+ {1, SW7_CS7, SW9_CS7, SW8_CS7},
+ {1, SW7_CS8, SW9_CS8, SW8_CS8},
+ {1, SW7_CS9, SW9_CS9, SW8_CS9},
+ {1, SW7_CS10, SW9_CS10, SW8_CS10},
+ {1, SW7_CS11, SW9_CS11, SW8_CS11},
+ {1, SW7_CS12, SW9_CS12, SW8_CS12},
+ {1, SW7_CS13, SW9_CS13, SW8_CS13},
+ {1, SW7_CS14, SW9_CS14, SW8_CS14},
+ {1, SW7_CS15, SW9_CS15, SW8_CS15},
+ {1, SW4_CS1, SW6_CS1, SW5_CS1},
+ {1, SW4_CS2, SW6_CS2, SW5_CS2},
+ {1, SW4_CS3, SW6_CS3, SW5_CS3},
+ {1, SW4_CS4, SW6_CS4, SW5_CS4},
+ {1, SW4_CS5, SW6_CS5, SW5_CS5},
+ {1, SW4_CS6, SW6_CS6, SW5_CS6},
+ {1, SW4_CS7, SW6_CS7, SW5_CS7},
+ {1, SW4_CS8, SW6_CS8, SW5_CS8},
+ {1, SW4_CS9, SW6_CS9, SW5_CS9},
+ {1, SW4_CS10, SW6_CS10, SW5_CS10},
+ {1, SW4_CS11, SW6_CS11, SW5_CS11},
+ {1, SW4_CS12, SW6_CS12, SW5_CS12},
+ {1, SW4_CS13, SW6_CS13, SW5_CS13},
+ {1, SW4_CS14, SW6_CS14, SW5_CS14},
+ {1, SW4_CS15, SW6_CS15, SW5_CS15},
+ {1, SW1_CS1, SW3_CS1, SW2_CS1},
+ {1, SW1_CS2, SW3_CS2, SW2_CS2},
+ {1, SW1_CS3, SW3_CS3, SW2_CS3},
+ {1, SW1_CS5, SW3_CS5, SW2_CS5},
+ {1, SW1_CS6, SW3_CS6, SW2_CS6},
+ {1, SW1_CS7, SW3_CS7, SW2_CS7},
+ {1, SW1_CS8, SW3_CS8, SW2_CS8},
+ {1, SW1_CS9, SW3_CS9, SW2_CS9},
+ {1, SW1_CS10, SW3_CS10, SW2_CS10},
+ {1, SW1_CS11, SW3_CS11, SW2_CS11},
+ {1, SW1_CS12, SW3_CS12, SW2_CS12},
+ {1, SW1_CS13, SW3_CS13, SW2_CS13},
+ {1, SW1_CS14, SW3_CS14, SW2_CS14},
+ {1, SW1_CS15, SW3_CS15, SW2_CS15},
+ {0, SW7_CS2, SW9_CS2, SW8_CS2},
+ {1, SW1_CS4, SW3_CS4, SW2_CS4}
+};
+
+static void send_ble_hid_report(uint8_t report_type, uint8_t *hid_report_buf, uint8_t data_len)
+{
+ switch(report_type)
+ {
+ case BLE_HID_REPORT_TYPE_NORMAL_KEY:
+ {
+ k715bt_send_spi_extend_single_packet(report_type, hid_report_buf, data_len);
+ break;
+ }
+
+ case BLE_HID_REPORT_TYPE_EXTRA_KEY:
+ {
+ k715bt_send_spi_extend_single_packet(report_type, hid_report_buf, data_len);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+static uint8_t k715_ble_leds(void)
+{
+ return 0;
+}
+
+static void k715_send_keyboard(report_keyboard_t *report)
+{
+ uint8_t raw_data[KEYBOARD_REPORT_KEYS + 2];
+
+ raw_data[0] = report->mods;
+ raw_data[1] = 0;
+ for(int i = 0; i < KEYBOARD_REPORT_KEYS; i++)
+ {
+ raw_data[2 + i] = report->keys[i];
+ }
+
+ send_ble_hid_report(BLE_HID_REPORT_TYPE_NORMAL_KEY, raw_data, KEYBOARD_REPORT_KEYS + 2);
+}
+
+#ifdef NKRO_ENABLE
+static void k715_send_nkro(report_nkro_t *report)
+{
+ uint8_t raw_data[NKRO_REPORT_BITS + 2];
+
+ raw_data[0] = report->mods;
+ raw_data[1] = 0;
+ for(int i = 0; i < NKRO_REPORT_BITS; i++)
+ {
+ raw_data[2 + i] = report->bits[i];
+ }
+
+ send_ble_hid_report(BLE_HID_REPORT_TYPE_ALL_KEY, raw_data, NKRO_REPORT_BITS + 2);
+}
+#endif
+
+static void k715_send_mouse(report_mouse_t *report)
+{
+}
+
+static void k715_send_extra(report_extra_t *report)
+{
+ if(report->report_id == REPORT_ID_CONSUMER)
+ {
+ uint8_t extra_buf[6];
+
+ memset(extra_buf, 0, sizeof(extra_buf));
+ memcpy(extra_buf, &report->usage, 2);
+ send_ble_hid_report(BLE_HID_REPORT_TYPE_EXTRA_KEY, extra_buf, sizeof(extra_buf));
+ }
+}
+
+static host_driver_t k715_ble_driver =
+{
+#ifdef NKRO_ENABLE
+ k715_ble_leds, k715_send_keyboard, k715_send_nkro, k715_send_mouse, k715_send_extra
+#else
+ k715_ble_leds, k715_send_keyboard, NULL, k715_send_mouse, k715_send_extra
+#endif
+};
+
+static bool _swtich_bt_driver(void)
+{
+ if(host_get_driver() == &k715_ble_driver)
+ {
+ return false;
+ }
+
+ clear_keyboard();
+
+#ifdef NKRO_ENABLE
+ keymap_config.nkro = true;
+#else
+ keymap_config.nkro = false;
+#endif
+
+ host_set_driver(&k715_ble_driver);
+ return true;
+}
+
+void k715bt_bt_swtich_ble_driver(void)
+{
+ if(is_bt_mode_enabled())
+ {
+ _swtich_bt_driver();
+ }
+}
+
+void k715_rgb_matrix_flags_init(void)
+{
+ rgb_matrix_enable();
+ rgb_matrix_set_flags(NORMAL_LED_FLAG_BIT);
+}
+
+void k715_bt_init(void)
+{
+ k715_ble_spi_init();
+ k715_rgb_matrix_flags_init();
+}
+
+bool led_update_kb(led_t led_state)
+{
+ bool res = led_update_user(led_state);
+
+ if(res)
+ {
+ update_caps_led();
+ }
+
+ return res;
+}
+
+bool process_record_kb_bt(uint16_t keycode, keyrecord_t *record)
+{
+ static uint8_t chn = 0;
+
+ switch(keycode)
+ {
+ case BT_CHN1:
+ case BT_CHN2:
+ case BT_CHN3:
+ if(is_bt_mode_enabled())
+ {
+ if(record->event.pressed)
+ {
+ chn = keycode - BT_CHN1 + 1;
+ k715_bt_start_pair(chn);
+ }
+ else
+ {
+ chn = 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool process_record_kb(uint16_t keycode, keyrecord_t *record)
+{
+ if(!process_record_user(keycode, record))
+ {
+ return false;
+ }
+
+ return process_record_kb_bt(keycode, record);
+}
+
+void bluetooth_task(void)
+{
+ k715bt_bt_swtich_ble_driver();
+ check_read_spi_data();
+}
+
+void keyboard_post_init_kb(void)
+{
+ k715_bt_init();
+ keyboard_post_init_user();
+}
diff --git a/keyboards/redragon/k715_pro/k715_pro.h b/keyboards/redragon/k715_pro/k715_pro.h
new file mode 100644
index 00000000000..d147b5d1207
--- /dev/null
+++ b/keyboards/redragon/k715_pro/k715_pro.h
@@ -0,0 +1,35 @@
+/* Copyright 2023 temp4gh
+ *
+ * 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 "quantum.h"
+
+#define BLE_HID_REPORT_TYPE_NORMAL_KEY 0x1
+#define BLE_HID_REPORT_TYPE_MOUSE_KEY 0x2
+#define BLE_HID_REPORT_TYPE_EXTRA_KEY 0x3
+#define BLE_HID_REPORT_TYPE_SYSTEM_KEY 0x4
+#define BLE_HID_REPORT_TYPE_ALL_KEY 0x5
+
+enum {
+ BT_CHN1,
+ BT_CHN2,
+ BT_CHN3,
+ NEW_SAFE_RANGE
+};
+
+#define NORMAL_LED_FLAG_BIT (LED_FLAG_KEYLIGHT | LED_FLAG_MODIFIER)
+
diff --git a/keyboards/redragon/k715_pro/keyboard.json b/keyboards/redragon/k715_pro/keyboard.json
new file mode 100644
index 00000000000..de477447ead
--- /dev/null
+++ b/keyboards/redragon/k715_pro/keyboard.json
@@ -0,0 +1,242 @@
+{
+ "manufacturer": "redragon",
+ "keyboard_name": "k715 pro",
+ "bootloader": "stm32duino",
+ "bootmagic": {
+ "matrix": [1, 0]
+ },
+ "diode_direction": "COL2ROW",
+ "dynamic_keymap": {
+ "layer_count": 2
+ },
+ "encoder": {
+ "rotary": [
+ {"pin_a": "B5", "pin_b": "B4"}
+ ]
+ },
+ "features": {
+ "bootmagic": true,
+ "console": true,
+ "encoder": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": false,
+ "rgb_matrix": true
+ },
+ "indicators": {
+ "caps_lock": "B8",
+ "on_state": 0
+ },
+ "matrix_pins": {
+ "cols": ["A6", "A7", "C4", "C5", "B0", "B1", "C6", "C7", "C8", "C9", "A8", "A9", "A10", "A13", "A14", "A15"],
+ "rows": ["A0", "A1", "A2", "A3", "A4", "A5"]
+ },
+ "processor": "STM32F103",
+ "rgb_matrix": {
+ "animations": {
+ "solid_color": true,
+ "alphas_mods": true,
+ "gradient_up_down": true,
+ "gradient_left_right": true,
+ "breathing": true,
+ "band_sat": true,
+ "band_val": true,
+ "band_spiral_val": true,
+ "cycle_all": true,
+ "cycle_left_right": true,
+ "cycle_up_down": true,
+ "hue_wave": true,
+ "pixel_flow": true
+ },
+ "driver": "is31fl3733",
+ "layout": [
+ {"matrix": [0, 0], "x": 7, "y": 2, "flags": 4},
+ {"matrix": [0, 2], "x": 34, "y": 2, "flags": 4},
+ {"matrix": [0, 3], "x": 48, "y": 2, "flags": 4},
+ {"matrix": [0, 4], "x": 61, "y": 2, "flags": 4},
+ {"matrix": [0, 5], "x": 75, "y": 2, "flags": 4},
+ {"matrix": [0, 6], "x": 95, "y": 2, "flags": 4},
+ {"matrix": [0, 7], "x": 109, "y": 2, "flags": 4},
+ {"matrix": [0, 8], "x": 122, "y": 2, "flags": 4},
+ {"matrix": [0, 9], "x": 136, "y": 2, "flags": 4},
+ {"matrix": [0, 10], "x": 157, "y": 2, "flags": 4},
+ {"matrix": [0, 11], "x": 170, "y": 2, "flags": 4},
+ {"matrix": [0, 12], "x": 184, "y": 2, "flags": 4},
+ {"matrix": [0, 13], "x": 198, "y": 2, "flags": 4},
+ {"matrix": [0, 14], "x": 217, "y": 2, "flags": 4},
+ {"matrix": [1, 0], "x": 7, "y": 14, "flags": 4},
+ {"matrix": [1, 1], "x": 20, "y": 14, "flags": 4},
+ {"matrix": [1, 2], "x": 34, "y": 14, "flags": 4},
+ {"matrix": [1, 3], "x": 48, "y": 14, "flags": 4},
+ {"matrix": [1, 4], "x": 61, "y": 14, "flags": 4},
+ {"matrix": [1, 5], "x": 75, "y": 14, "flags": 4},
+ {"matrix": [1, 6], "x": 89, "y": 14, "flags": 4},
+ {"matrix": [1, 7], "x": 102, "y": 14, "flags": 4},
+ {"matrix": [1, 8], "x": 116, "y": 14, "flags": 4},
+ {"matrix": [1, 9], "x": 129, "y": 14, "flags": 4},
+ {"matrix": [1, 10], "x": 143, "y": 14, "flags": 4},
+ {"matrix": [1, 11], "x": 157, "y": 14, "flags": 4},
+ {"matrix": [1, 12], "x": 170, "y": 14, "flags": 4},
+ {"matrix": [1, 13], "x": 190, "y": 14, "flags": 4},
+ {"matrix": [1, 14], "x": 217, "y": 14, "flags": 4},
+ {"matrix": [2, 0], "x": 10, "y": 24, "flags": 4},
+ {"matrix": [2, 1], "x": 27, "y": 24, "flags": 4},
+ {"matrix": [2, 2], "x": 40, "y": 24, "flags": 4},
+ {"matrix": [2, 3], "x": 54, "y": 24, "flags": 4},
+ {"matrix": [2, 4], "x": 68, "y": 24, "flags": 4},
+ {"matrix": [2, 5], "x": 81, "y": 24, "flags": 4},
+ {"matrix": [2, 6], "x": 95, "y": 24, "flags": 4},
+ {"matrix": [2, 7], "x": 109, "y": 24, "flags": 4},
+ {"matrix": [2, 8], "x": 122, "y": 24, "flags": 4},
+ {"matrix": [2, 9], "x": 136, "y": 24, "flags": 4},
+ {"matrix": [2, 10], "x": 150, "y": 24, "flags": 4},
+ {"matrix": [2, 11], "x": 163, "y": 24, "flags": 4},
+ {"matrix": [2, 12], "x": 177, "y": 24, "flags": 4},
+ {"matrix": [2, 13], "x": 194, "y": 24, "flags": 4},
+ {"matrix": [2, 14], "x": 217, "y": 24, "flags": 4},
+ {"matrix": [3, 0], "x": 12, "y": 34, "flags": 4},
+ {"matrix": [3, 1], "x": 30, "y": 34, "flags": 4},
+ {"matrix": [3, 2], "x": 44, "y": 34, "flags": 4},
+ {"matrix": [3, 3], "x": 58, "y": 34, "flags": 4},
+ {"matrix": [3, 4], "x": 71, "y": 34, "flags": 4},
+ {"matrix": [3, 5], "x": 85, "y": 34, "flags": 4},
+ {"matrix": [3, 6], "x": 99, "y": 34, "flags": 4},
+ {"matrix": [3, 7], "x": 112, "y": 34, "flags": 4},
+ {"matrix": [3, 8], "x": 126, "y": 34, "flags": 4},
+ {"matrix": [3, 9], "x": 140, "y": 34, "flags": 4},
+ {"matrix": [3, 10], "x": 153, "y": 34, "flags": 4},
+ {"matrix": [3, 11], "x": 167, "y": 34, "flags": 4},
+ {"x": 180, "y": 34, "flags": 4},
+ {"matrix": [3, 13], "x": 189, "y": 34, "flags": 4},
+ {"matrix": [3, 14], "x": 217, "y": 34, "flags": 4},
+ {"matrix": [4, 0], "x": 8, "y": 44, "flags": 4},
+ {"x": 24, "y": 44, "flags": 4},
+ {"matrix": [4, 2], "x": 38, "y": 44, "flags": 4},
+ {"matrix": [4, 3], "x": 51, "y": 44, "flags": 4},
+ {"matrix": [4, 4], "x": 65, "y": 44, "flags": 4},
+ {"matrix": [4, 5], "x": 78, "y": 44, "flags": 4},
+ {"matrix": [4, 6], "x": 92, "y": 44, "flags": 4},
+ {"matrix": [4, 7], "x": 106, "y": 44, "flags": 4},
+ {"matrix": [4, 8], "x": 119, "y": 44, "flags": 4},
+ {"matrix": [4, 9], "x": 133, "y": 44, "flags": 4},
+ {"matrix": [4, 10], "x": 147, "y": 44, "flags": 4},
+ {"matrix": [4, 11], "x": 160, "y": 44, "flags": 4},
+ {"matrix": [4, 12], "x": 179, "y": 44, "flags": 4},
+ {"matrix": [4, 13], "x": 201, "y": 46, "flags": 4},
+ {"matrix": [4, 14], "x": 217, "y": 44, "flags": 4},
+ {"matrix": [5, 0], "x": 8, "y": 54, "flags": 4},
+ {"matrix": [5, 1], "x": 25, "y": 54, "flags": 4},
+ {"matrix": [5, 2], "x": 43, "y": 54, "flags": 4},
+ {"x": 67, "y": 57, "flags": 4},
+ {"x": 80, "y": 57, "flags": 4},
+ {"x": 94, "y": 54, "flags": 4},
+ {"matrix": [5, 6], "x": 107, "y": 57, "flags": 4},
+ {"x": 120, "y": 57, "flags": 4},
+ {"matrix": [5, 9], "x": 143, "y": 54, "flags": 4},
+ {"matrix": [5, 10], "x": 157, "y": 54, "flags": 4},
+ {"matrix": [5, 11], "x": 170, "y": 54, "flags": 4},
+ {"matrix": [5, 12], "x": 187, "y": 56, "flags": 4},
+ {"matrix": [5, 13], "x": 201, "y": 56, "flags": 4},
+ {"matrix": [5, 14], "x": 214, "y": 56, "flags": 4},
+ {"x": 207, "y": 23, "flags": 8},
+ {"x": 207, "y": 27, "flags": 8}
+ ]
+ },
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x00D1",
+ "vid": "0x369B",
+ "no_startup_check": true
+ },
+ "layout_aliases": {
+ "LAYOUT_75_ansi": "LAYOUT"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"label": "ESC", "matrix": [0, 0], "x": 0, "y": 0},
+ {"label": "F1", "matrix": [0, 2], "x": 1.5, "y": 0},
+ {"label": "F2", "matrix": [0, 3], "x": 2.5, "y": 0},
+ {"label": "F3", "matrix": [0, 4], "x": 3.5, "y": 0},
+ {"label": "F4", "matrix": [0, 5], "x": 4.5, "y": 0},
+ {"label": "F5", "matrix": [0, 6], "x": 6, "y": 0},
+ {"label": "F6", "matrix": [0, 7], "x": 7, "y": 0},
+ {"label": "F7", "matrix": [0, 8], "x": 8, "y": 0},
+ {"label": "F8", "matrix": [0, 9], "x": 9, "y": 0},
+ {"label": "F9", "matrix": [0, 10], "x": 10.5, "y": 0},
+ {"label": "F10", "matrix": [0, 11], "x": 11.5, "y": 0},
+ {"label": "F11", "matrix": [0, 12], "x": 12.5, "y": 0},
+ {"label": "F12", "matrix": [0, 13], "x": 13.5, "y": 0},
+ {"label": "END", "matrix": [0, 15], "x": 15, "y": 0},
+ {"label": "GRV", "matrix": [1, 0], "x": 0, "y": 1.25},
+ {"label": "1", "matrix": [1, 1], "x": 1, "y": 1.25},
+ {"label": "2", "matrix": [1, 2], "x": 2, "y": 1.25},
+ {"label": "3", "matrix": [1, 3], "x": 3, "y": 1.25},
+ {"label": "4", "matrix": [1, 4], "x": 4, "y": 1.25},
+ {"label": "5", "matrix": [1, 5], "x": 5, "y": 1.25},
+ {"label": "6", "matrix": [1, 6], "x": 6, "y": 1.25},
+ {"label": "7", "matrix": [1, 7], "x": 7, "y": 1.25},
+ {"label": "8", "matrix": [1, 8], "x": 8, "y": 1.25},
+ {"label": "9", "matrix": [1, 9], "x": 9, "y": 1.25},
+ {"label": "0", "matrix": [1, 10], "x": 10, "y": 1.25},
+ {"label": "MINS", "matrix": [1, 11], "x": 11, "y": 1.25},
+ {"label": "EQL", "matrix": [1, 12], "x": 12, "y": 1.25},
+ {"label": "BSPC", "matrix": [1, 13], "x": 13, "y": 1.25, "w": 2},
+ {"label": "INS", "matrix": [1, 14], "x": 15, "y": 1.25},
+ {"label": "TAB", "matrix": [2, 0], "x": 0, "y": 2.25, "w": 1.5},
+ {"label": "Q", "matrix": [2, 1], "x": 1.5, "y": 2.25},
+ {"label": "W", "matrix": [2, 2], "x": 2.5, "y": 2.25},
+ {"label": "E", "matrix": [2, 3], "x": 3.5, "y": 2.25},
+ {"label": "R", "matrix": [2, 4], "x": 4.5, "y": 2.25},
+ {"label": "T", "matrix": [2, 5], "x": 5.5, "y": 2.25},
+ {"label": "Y", "matrix": [2, 6], "x": 6.5, "y": 2.25},
+ {"label": "U", "matrix": [2, 7], "x": 7.5, "y": 2.25},
+ {"label": "I", "matrix": [2, 8], "x": 8.5, "y": 2.25},
+ {"label": "O", "matrix": [2, 9], "x": 9.5, "y": 2.25},
+ {"label": "P", "matrix": [2, 10], "x": 10.5, "y": 2.25},
+ {"label": "LBRC", "matrix": [2, 11], "x": 11.5, "y": 2.25},
+ {"label": "RBRC", "matrix": [2, 12], "x": 12.5, "y": 2.25},
+ {"label": "BSLS", "matrix": [2, 13], "x": 13.5, "y": 2.25, "w": 1.5},
+ {"label": "DEL", "matrix": [2, 14], "x": 15, "y": 2.25},
+ {"label": "CAPS", "matrix": [3, 0], "x": 0, "y": 3.25, "w": 1.75},
+ {"label": "A", "matrix": [3, 1], "x": 1.75, "y": 3.25},
+ {"label": "S", "matrix": [3, 2], "x": 2.75, "y": 3.25},
+ {"label": "D", "matrix": [3, 3], "x": 3.75, "y": 3.25},
+ {"label": "F", "matrix": [3, 4], "x": 4.75, "y": 3.25},
+ {"label": "G", "matrix": [3, 5], "x": 5.75, "y": 3.25},
+ {"label": "H", "matrix": [3, 6], "x": 6.75, "y": 3.25},
+ {"label": "J", "matrix": [3, 7], "x": 7.75, "y": 3.25},
+ {"label": "K", "matrix": [3, 8], "x": 8.75, "y": 3.25},
+ {"label": "L", "matrix": [3, 9], "x": 9.75, "y": 3.25},
+ {"label": "SCLN", "matrix": [3, 10], "x": 10.75, "y": 3.25},
+ {"label": "QUOT", "matrix": [3, 11], "x": 11.75, "y": 3.25},
+ {"label": "ENT", "matrix": [3, 13], "x": 12.75, "y": 3.25, "w": 2.25},
+ {"label": "PGUP", "matrix": [3, 14], "x": 15, "y": 3.25},
+ {"label": "LSFT", "matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25},
+ {"label": "Z", "matrix": [4, 2], "x": 2.25, "y": 4.25},
+ {"label": "X", "matrix": [4, 3], "x": 3.25, "y": 4.25},
+ {"label": "C", "matrix": [4, 4], "x": 4.25, "y": 4.25},
+ {"label": "V", "matrix": [4, 5], "x": 5.25, "y": 4.25},
+ {"label": "B", "matrix": [4, 6], "x": 6.25, "y": 4.25},
+ {"label": "N", "matrix": [4, 7], "x": 7.25, "y": 4.25},
+ {"label": "M", "matrix": [4, 8], "x": 8.25, "y": 4.25},
+ {"label": "COMM", "matrix": [4, 9], "x": 9.25, "y": 4.25},
+ {"label": "DOT", "matrix": [4, 10], "x": 10.25, "y": 4.25},
+ {"label": "SLSH", "matrix": [4, 11], "x": 11.25, "y": 4.25},
+ {"label": "RSFT", "matrix": [4, 12], "x": 12.25, "y": 4.25, "w": 1.75},
+ {"label": "UP", "matrix": [4, 13], "x": 14, "y": 4.25},
+ {"label": "PGDN", "matrix": [4, 14], "x": 15, "y": 4.25},
+ {"label": "LCTL", "matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.25},
+ {"label": "LGUI", "matrix": [5, 1], "x": 1.25, "y": 5.25, "w": 1.25},
+ {"label": "LALT", "matrix": [5, 2], "x": 2.5, "y": 5.25, "w": 1.25},
+ {"label": "SPC", "matrix": [5, 6], "x": 3.75, "y": 5.25, "w": 6.25},
+ {"label": "RALT", "matrix": [5, 9], "x": 10, "y": 5.25},
+ {"label": "MO(1)", "matrix": [5, 10], "x": 11, "y": 5.25},
+ {"label": "RCTL", "matrix": [5, 11], "x": 12, "y": 5.25},
+ {"label": "LEFT", "matrix": [5, 12], "x": 13, "y": 5.25},
+ {"label": "DOWN", "matrix": [5, 13], "x": 14, "y": 5.25},
+ {"label": "RGHT", "matrix": [5, 14], "x": 15, "y": 5.25}
+ ]
+ }
+ }
+}
diff --git a/keyboards/redragon/k715_pro/keymaps/default/keymap.c b/keyboards/redragon/k715_pro/keymaps/default/keymap.c
new file mode 100644
index 00000000000..b25e77be674
--- /dev/null
+++ b/keyboards/redragon/k715_pro/keymaps/default/keymap.c
@@ -0,0 +1,50 @@
+/* Copyright 2024 temp4gh
+ *
+ * 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
+#include "k715_pro.h"
+
+enum layer_names
+{
+ _BASE,
+ _FnLay,
+};
+
+#ifdef ENCODER_MAP_ENABLE
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
+ [_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
+ [_FnLay] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI) },
+};
+#endif
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_BASE] = LAYOUT(
+ 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_MUTE,
+ 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_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(_FnLay), KC_RCTL, KC_LEFT, KC_DOWN, KC_RIGHT
+ ),
+ [_FnLay] = LAYOUT(
+ EE_CLR, KC_BRID, KC_BRIU, A(KC_TAB),G(KC_H),G(KC_D), G(KC_S), KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, XXXXXXX,
+ XXXXXXX, BT_CHN1, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, RGB_MOD,
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_HOME, KC_END, XXXXXXX, XXXXXXX,
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_SCRL, KC_PSCR, XXXXXXX, XXXXXXX,
+ XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_PAUS, XXXXXXX, RGB_VAI, XXXXXXX,
+ XXXXXXX, XXXXXXX, XXXXXXX, RGB_TOG, XXXXXXX, _______, XXXXXXX, RGB_SPD, RGB_VAD, RGB_SPI
+ )
+};
diff --git a/keyboards/redragon/k715_pro/keymaps/default/rules.mk b/keyboards/redragon/k715_pro/keymaps/default/rules.mk
new file mode 100644
index 00000000000..cb9527ac99e
--- /dev/null
+++ b/keyboards/redragon/k715_pro/keymaps/default/rules.mk
@@ -0,0 +1,2 @@
+SPI_DRIVER_REQUIRED = yes
+ENCODER_MAP_ENABLE = yes
diff --git a/keyboards/redragon/k715_pro/mcuconf.h b/keyboards/redragon/k715_pro/mcuconf.h
new file mode 100644
index 00000000000..bb4b34214a4
--- /dev/null
+++ b/keyboards/redragon/k715_pro/mcuconf.h
@@ -0,0 +1,25 @@
+/* Copyright 2020 QMK
+ *
+ * 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 STM32_I2C_USE_I2C1
+#define STM32_I2C_USE_I2C1 TRUE
+
+#undef STM32_SPI_USE_SPI2
+#define STM32_SPI_USE_SPI2 TRUE
diff --git a/keyboards/redragon/k715_pro/post_rules.mk b/keyboards/redragon/k715_pro/post_rules.mk
new file mode 100644
index 00000000000..7e8fbbed86d
--- /dev/null
+++ b/keyboards/redragon/k715_pro/post_rules.mk
@@ -0,0 +1 @@
+include keyboards/redragon/k715_pro/bluetooth/bluetooth.mk
\ No newline at end of file
diff --git a/keyboards/redragon/k715_pro/readme.md b/keyboards/redragon/k715_pro/readme.md
new file mode 100644
index 00000000000..cd8b539f92d
--- /dev/null
+++ b/keyboards/redragon/k715_pro/readme.md
@@ -0,0 +1,21 @@
+# K715 Pro
+
+
+
+A customizable 80% keyboard with wire and bluetooth.
+
+- Keyboard Maintainer: [temp4gh](https://github.com/temp4gh)
+- Hardware Supported:K715 pro PCB
+- Hardware Availability: www.redragonzone.com
+
+Make example for this keyboard (after setting up your build environment):
+
+ make redragon/k715_pro:default
+
+Flashing example for this keyboard:
+
+ make redragon/k715_pro:default:flash
+
+**Reset Key**: Hold down the key located at *K10*, commonly programmed as *Grave* while plugging in the keyboard.
+
+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).
diff --git a/keyboards/redragon/k715_pro/rules.mk b/keyboards/redragon/k715_pro/rules.mk
new file mode 100644
index 00000000000..e69de29bb2d