diff --git a/keyboards/annepro2/annepro2.c b/keyboards/annepro2/annepro2.c
new file mode 100644
index 0000000000..37489defff
--- /dev/null
+++ b/keyboards/annepro2/annepro2.c
@@ -0,0 +1,202 @@
+/* Copyright 2021 OpenAnnePro community
+ *
+ * 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 "hal.h"
+#include "annepro2.h"
+#include "annepro2_ble.h"
+#include "spi_master.h"
+#include "ap2_led.h"
+#include "protocol.h"
+
+#define RAM_MAGIC_LOCATION 0x20001ffc
+#define IAP_MAGIC_VALUE 0x0000fab2
+
+static const SerialConfig ledUartInitConfig = {
+ .speed = 115200,
+};
+
+#ifndef LED_UART_BAUD_RATE
+# define LED_UART_BAUD_RATE 115200
+#endif // LED_UART_BAUD_RATE
+
+static const SerialConfig ledUartRuntimeConfig = {
+ .speed = LED_UART_BAUD_RATE,
+};
+
+static const SerialConfig bleUartConfig = {
+ .speed = 115200,
+};
+
+static uint8_t ledMcuWakeup[11] = {0x7b, 0x10, 0x43, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x02};
+
+ble_capslock_t BLECapsLock = {._dummy = {0}, .caps_lock = false};
+
+void bootloader_jump(void) {
+ // Send msg to shine to boot into IAP
+ annepro2SetIAP();
+
+ // wait for shine to boot into IAP
+ wait_ms(15);
+
+ // Load ble into IAP
+ annepro2_ble_bootload();
+ wait_ms(15);
+
+ // Magic key to set keyboard to IAP
+ // It’s from reversing original boot loader
+ // If value is that it stays in boot loader aka IAP
+ *((uint32_t *)RAM_MAGIC_LOCATION) = IAP_MAGIC_VALUE;
+
+ // Load the main MCU into IAP
+ __disable_irq();
+ NVIC_SystemReset();
+}
+
+void keyboard_pre_init_kb(void) {
+ // Start LED UART
+ sdStart(&SD0, &ledUartInitConfig);
+ /* Let the LED chip settle a bit before switching the mode.
+ * That helped at least one person. */
+ wait_ms(15);
+ sdWrite(&SD0, ledMcuWakeup, sizeof(ledMcuWakeup));
+
+ // wait to receive response from wakeup
+ wait_ms(15);
+
+ protoInit(&proto, ledCommandCallback);
+
+ // loop to clear out receive buffer from shine wakeup
+ while (!sdGetWouldBlock(&SD0)) sdGet(&SD0);
+
+ sdStart(&SD0, &ledUartRuntimeConfig);
+ keyboard_pre_init_user();
+}
+
+void keyboard_post_init_kb(void) {
+ // Start BLE UART
+ sdStart(&SD1, &bleUartConfig);
+ annepro2_ble_startup();
+
+ // Give the send uart thread some time to
+ // send out the queue before we read back
+ wait_ms(100);
+
+ // loop to clear out receive buffer from ble wakeup
+ while (!sdGetWouldBlock(&SD1)) sdGet(&SD1);
+
+ annepro2LedGetStatus();
+
+ keyboard_post_init_user();
+}
+
+void matrix_scan_kb() {
+ // if there's stuff on the ble serial buffer
+ // read it into the capslock struct
+ while (!sdGetWouldBlock(&SD1)) {
+ sdReadTimeout(&SD1, (uint8_t *)&BLECapsLock, sizeof(ble_capslock_t), 10);
+ }
+
+ /* While there's data from LED keyboard sent - read it. */
+ while (!sdGetWouldBlock(&SD0)) {
+ uint8_t byte = sdGet(&SD0);
+ protoConsume(&proto, byte);
+ }
+
+ matrix_scan_user();
+}
+
+bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
+ if (record->event.pressed) {
+ if (annepro2LedStatus.matrixEnabled && annepro2LedStatus.isReactive) {
+ annepro2LedForwardKeypress(record->event.key.row, record->event.key.col);
+ }
+
+ const annepro2Led_t blue = {
+ .p.blue = 0xff,
+ .p.red = 0x00,
+ .p.green = 0x00,
+ .p.alpha = 0xff,
+ };
+
+ switch (keycode) {
+ case KC_AP2_BT1:
+ annepro2_ble_broadcast(0);
+ /* FIXME: This hardcodes col/row position */
+ annepro2LedBlink(0, 1, blue, 8, 50);
+ return false;
+
+ case KC_AP2_BT2:
+ annepro2_ble_broadcast(1);
+ annepro2LedBlink(0, 2, blue, 8, 50);
+ return false;
+
+ case KC_AP2_BT3:
+ annepro2_ble_broadcast(2);
+ annepro2LedBlink(0, 3, blue, 8, 50);
+ return false;
+
+ case KC_AP2_BT4:
+ annepro2_ble_broadcast(3);
+ annepro2LedBlink(0, 4, blue, 8, 50);
+ return false;
+
+ case KC_AP2_USB:
+ annepro2_ble_disconnect();
+ return false;
+
+ case KC_AP2_BT_UNPAIR:
+ annepro2_ble_unpair();
+ return false;
+
+ case KC_AP_LED_OFF:
+ annepro2LedDisable();
+ break;
+
+ case KC_AP_LED_ON:
+ if (annepro2LedStatus.matrixEnabled) {
+ annepro2LedNextProfile();
+ } else {
+ annepro2LedEnable();
+ }
+ annepro2LedResetForegroundColor();
+ break;
+
+ case KC_AP_LED_NEXT_PROFILE:
+ annepro2LedNextProfile();
+ annepro2LedResetForegroundColor();
+ break;
+
+ case KC_AP_LED_PREV_PROFILE:
+ annepro2LedPrevProfile();
+ annepro2LedResetForegroundColor();
+ break;
+
+ case KC_AP_LED_NEXT_INTENSITY:
+ annepro2LedNextIntensity();
+ annepro2LedResetForegroundColor();
+ return false;
+
+ case KC_AP_LED_SPEED:
+ annepro2LedNextAnimationSpeed();
+ annepro2LedResetForegroundColor();
+ return false;
+
+ default:
+ break;
+ }
+ }
+ return process_record_user(keycode, record);
+}
diff --git a/keyboards/annepro2/annepro2.h b/keyboards/annepro2/annepro2.h
new file mode 100644
index 0000000000..b08f8c5352
--- /dev/null
+++ b/keyboards/annepro2/annepro2.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Yaotian Feng
+ *
+ * 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"
+#include
+#include "ap2_led.h"
+
+typedef struct __attribute__((__packed__)) {
+ uint8_t _dummy[10];
+ bool caps_lock;
+} ble_capslock_t;
+extern ble_capslock_t BLECapsLock;
+
+// Matrix keymap
+// clang-format off
+#define LAYOUT( \
+ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, \
+ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, \
+ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, \
+ K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, \
+ K40, K42, K43, K46, K49, K4A, K4B, K4C \
+) { \
+ /* COL1 COL2 COL3 COL4 COL5 COL6 COL7 COL8 COL9 COL10 COL11 COL12 COL13 COL14*/ \
+ /* ROW1 */ { K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D }, \
+ /* ROW2 */ { K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D }, \
+ /* ROW3 */ { K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, KC_NO}, \
+ /* ROW4 */ { K30, KC_NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, KC_NO}, \
+ /* ROW5 */ { K40, KC_NO, K42, K43, KC_NO, KC_NO, K46, KC_NO, KC_NO, K49, K4A, K4B, K4C, KC_NO}, \
+}
+// clang-format on
+
+enum AP2KeyCodes {
+ KC_AP2_BT1 = SAFE_RANGE,
+ KC_AP2_BT2,
+ KC_AP2_BT3,
+ KC_AP2_BT4,
+ KC_AP2_BT_UNPAIR,
+ KC_AP2_USB,
+ KC_AP_LED_ON,
+ KC_AP_LED_OFF,
+ KC_AP_LED_NEXT_PROFILE,
+ KC_AP_LED_PREV_PROFILE,
+ KC_AP_LED_NEXT_INTENSITY,
+ KC_AP_LED_SPEED,
+ AP2_SAFE_RANGE,
+};
+
+#undef SAFE_RANGE
+#define SAFE_RANGE AP2_SAFE_RANGE
+
diff --git a/keyboards/annepro2/annepro2_ble.c b/keyboards/annepro2/annepro2_ble.c
new file mode 100644
index 0000000000..72cbb68016
--- /dev/null
+++ b/keyboards/annepro2/annepro2_ble.c
@@ -0,0 +1,170 @@
+/*
+ Copyright (C) 2020 Yaotian Feng, Codetector
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "annepro2_ble.h"
+#include "ch.h"
+#include "hal.h"
+#include "host.h"
+#include "host_driver.h"
+#include "report.h"
+
+/* -------------------- Static Function Prototypes -------------------------- */
+static uint8_t ap2_ble_leds(void);
+static void ap2_ble_mouse(report_mouse_t *report);
+static void ap2_ble_system(uint16_t data);
+static void ap2_ble_consumer(uint16_t data);
+static void ap2_ble_keyboard(report_keyboard_t *report);
+
+static void ap2_ble_swtich_ble_driver(void);
+
+/* -------------------- Static Local Variables ------------------------------ */
+static host_driver_t ap2_ble_driver = {
+ ap2_ble_leds, ap2_ble_keyboard, ap2_ble_mouse, ap2_ble_system, ap2_ble_consumer,
+};
+
+static uint8_t bleMcuWakeup[11] = {0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x01, 0x7d, 0x02, 0x01, 0x02};
+
+static uint8_t bleMcuStartBroadcast[11] = {
+ 0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x00, 0x7d, 0x40, 0x01, 0x00 // Broadcast ID[0-3]
+};
+
+static uint8_t bleMcuConnect[11] = {
+ 0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x00, 0x7d, 0x40, 0x04, 0x00 // Connect ID [0-3]
+};
+
+static uint8_t bleMcuSendReport[10] = {
+ 0x7b, 0x12, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x7d, 0x10, 0x04,
+};
+
+static uint8_t bleMcuSendConsumerReport[10] = {
+ 0x7b, 0x12, 0x53, 0x00, 0x06, 0x00, 0x00, 0x7d, 0x10, 0x08,
+};
+
+static uint8_t bleMcuUnpair[10] = {
+ 0x7b, 0x12, 0x53, 0x00, 0x02, 0x00, 0x00, 0x7d, 0x40, 0x05,
+};
+
+static uint8_t bleMcuBootload[11] = {0x7b, 0x10, 0x51, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x01};
+
+static host_driver_t *lastHostDriver = NULL;
+#ifdef NKRO_ENABLE
+static bool lastNkroStatus = false;
+#endif // NKRO_ENABLE
+
+/* -------------------- Public Function Implementation ---------------------- */
+
+void annepro2_ble_bootload(void) { sdWrite(&SD1, bleMcuBootload, sizeof(bleMcuBootload)); }
+
+void annepro2_ble_startup(void) { sdWrite(&SD1, bleMcuWakeup, sizeof(bleMcuWakeup)); }
+
+void annepro2_ble_broadcast(uint8_t port) {
+ if (port > 3) {
+ port = 3;
+ }
+ // sdPut(&SD1, 0x00);
+ sdWrite(&SD1, bleMcuStartBroadcast, sizeof(bleMcuStartBroadcast));
+ sdPut(&SD1, port);
+ static int lastBroadcast = -1;
+ if (lastBroadcast == port) {
+ annepro2_ble_connect(port);
+ }
+ lastBroadcast = port;
+}
+
+void annepro2_ble_connect(uint8_t port) {
+ if (port > 3) {
+ port = 3;
+ }
+ sdWrite(&SD1, bleMcuConnect, sizeof(bleMcuConnect));
+ sdPut(&SD1, port);
+ ap2_ble_swtich_ble_driver();
+}
+
+void annepro2_ble_disconnect(void) {
+ /* Skip if the driver is already enabled */
+ if (host_get_driver() != &ap2_ble_driver) {
+ return;
+ }
+
+ clear_keyboard();
+#ifdef NKRO_ENABLE
+ keymap_config.nkro = lastNkroStatus;
+#endif
+ host_set_driver(lastHostDriver);
+}
+
+void annepro2_ble_unpair(void) {
+ // sdPut(&SD1, 0x0);
+ sdWrite(&SD1, bleMcuUnpair, sizeof(bleMcuUnpair));
+}
+
+/* ------------------- Static Function Implementation ----------------------- */
+static void ap2_ble_swtich_ble_driver(void) {
+ if (host_get_driver() == &ap2_ble_driver) {
+ return;
+ }
+ clear_keyboard();
+ lastHostDriver = host_get_driver();
+#ifdef NKRO_ENABLE
+ lastNkroStatus = keymap_config.nkro;
+#endif
+ keymap_config.nkro = false;
+ host_set_driver(&ap2_ble_driver);
+}
+
+static uint8_t ap2_ble_leds(void) {
+ return 0; // TODO: Figure out how to obtain LED status
+}
+
+static void ap2_ble_mouse(report_mouse_t *report) {}
+
+static void ap2_ble_system(uint16_t data) {}
+
+static inline uint16_t CONSUMER2AP2(uint16_t usage) {
+ switch (usage) {
+ case AUDIO_VOL_DOWN:
+ return 0x04;
+ case AUDIO_VOL_UP:
+ return 0x02;
+ case AUDIO_MUTE:
+ return 0x01;
+ case TRANSPORT_PLAY_PAUSE:
+ return 0x08;
+ case TRANSPORT_NEXT_TRACK:
+ return 0x10;
+ case TRANSPORT_PREV_TRACK:
+ return 0x20;
+ default:
+ return 0x00;
+ }
+}
+
+static void ap2_ble_consumer(uint16_t data) {
+ sdPut(&SD1, 0x0);
+ sdWrite(&SD1, bleMcuSendConsumerReport, sizeof(bleMcuSendConsumerReport));
+ sdPut(&SD1, CONSUMER2AP2(data));
+ static const uint8_t dummy[3] = {0};
+ sdWrite(&SD1, dummy, sizeof(dummy));
+}
+
+/*!
+ * @brief Send keyboard HID report for Bluetooth driver
+ */
+static void ap2_ble_keyboard(report_keyboard_t *report) {
+ sdPut(&SD1, 0x0);
+ sdWrite(&SD1, bleMcuSendReport, sizeof(bleMcuSendReport));
+ sdWrite(&SD1, &report->raw[0], KEYBOARD_REPORT_SIZE);
+}
diff --git a/keyboards/annepro2/annepro2_ble.h b/keyboards/annepro2/annepro2_ble.h
new file mode 100644
index 0000000000..0cfb68e071
--- /dev/null
+++ b/keyboards/annepro2/annepro2_ble.h
@@ -0,0 +1,27 @@
+/*
+ Copyright (C) 2020 Yaotian Feng, Codetector
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#pragma once
+
+#include "annepro2.h"
+#include "quantum.h"
+
+void annepro2_ble_bootload(void);
+void annepro2_ble_startup(void);
+void annepro2_ble_broadcast(uint8_t port);
+void annepro2_ble_connect(uint8_t port);
+void annepro2_ble_disconnect(void);
+void annepro2_ble_unpair(void);
diff --git a/keyboards/annepro2/ap2_led.c b/keyboards/annepro2/ap2_led.c
new file mode 100644
index 0000000000..9969fcd02a
--- /dev/null
+++ b/keyboards/annepro2/ap2_led.c
@@ -0,0 +1,134 @@
+/* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+#include "hal.h"
+#include "annepro2.h"
+#include "ap2_led.h"
+#include "protocol.h"
+
+annepro2Led_t ledMask[KEY_COUNT];
+annepro2LedStatus_t annepro2LedStatus;
+
+void ledCommandCallback(const message_t *msg) {
+ switch (msg->command) {
+ case CMD_LED_STATUS:
+ annepro2LedStatus.amountOfProfiles = msg->payload[0];
+ annepro2LedStatus.currentProfile = msg->payload[1];
+ annepro2LedStatus.matrixEnabled = msg->payload[2];
+ annepro2LedStatus.isReactive = msg->payload[3];
+ annepro2LedStatus.ledIntensity = msg->payload[4];
+ annepro2LedStatus.errors = msg->payload[5];
+ break;
+
+#ifdef CONSOLE_ENABLE
+ case CMD_LED_DEBUG:
+ /* TODO: Don't use printf. */
+ printf("LED:");
+ for (int i = 0; i < msg->payloadSize; i++) {
+ printf("%02x ", msg->payload[i]);
+ }
+ for (int i = 0; i < msg->payloadSize; i++) {
+ printf("%c", msg->payload[i]);
+ }
+ printf("\n");
+ break;
+#endif
+ }
+}
+
+void annepro2SetIAP(void) { protoTx(CMD_LED_IAP, NULL, 0, 3); }
+
+void annepro2LedDisable(void) { protoTx(CMD_LED_OFF, NULL, 0, 3); }
+
+void annepro2LedEnable(void) { protoTx(CMD_LED_ON, NULL, 0, 3); }
+
+void annepro2LedSetProfile(uint8_t prof) { protoTx(CMD_LED_SET_PROFILE, &prof, sizeof(prof), 3); }
+
+void annepro2LedGetStatus() { protoTx(CMD_LED_GET_STATUS, NULL, 0, 3); }
+
+void annepro2LedNextProfile() { protoTx(CMD_LED_NEXT_PROFILE, NULL, 0, 3); }
+
+void annepro2LedNextIntensity() { protoTx(CMD_LED_NEXT_INTENSITY, NULL, 0, 3); }
+
+void annepro2LedNextAnimationSpeed() { protoTx(CMD_LED_NEXT_ANIMATION_SPEED, NULL, 0, 3); }
+
+void annepro2LedPrevProfile() { protoTx(CMD_LED_PREV_PROFILE, NULL, 0, 3); }
+
+void annepro2LedMaskSetKey(uint8_t row, uint8_t col, annepro2Led_t color) {
+ uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
+ protoTx(CMD_LED_MASK_SET_KEY, payload, sizeof(payload), 1);
+}
+
+/* Push a whole local row to the shine */
+void annepro2LedMaskSetRow(uint8_t row) {
+ uint8_t payload[NUM_COLUMN * sizeof(annepro2Led_t) + 1];
+ payload[0] = row;
+ memcpy(payload + 1, &ledMask[ROWCOL2IDX(row, 0)], sizeof(*ledMask) * NUM_COLUMN);
+ protoTx(CMD_LED_MASK_SET_ROW, payload, sizeof(payload), 1);
+}
+
+/* Synchronize all rows */
+void annepro2LedMaskSetAll(void) {
+ for (int row = 0; row < 5; row++) annepro2LedMaskSetRow(row);
+}
+
+/* Set all keys to a given color */
+void annepro2LedMaskSetMono(const annepro2Led_t color) { protoTx(CMD_LED_MASK_SET_MONO, (uint8_t *)&color, sizeof(color), 1); }
+
+void annepro2LedBlink(uint8_t row, uint8_t col, annepro2Led_t color, uint8_t count, uint8_t hundredths) {
+ uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha, count, hundredths};
+ protoTx(CMD_LED_KEY_BLINK, payload, sizeof(payload), 1);
+}
+
+void annepro2LedSetForegroundColor(uint8_t red, uint8_t green, uint8_t blue) {
+ annepro2Led_t color = {.p.red = red, .p.green = green, .p.blue = blue, .p.alpha = 0xff};
+ annepro2LedMaskSetMono(color);
+}
+
+void annepro2LedResetForegroundColor() {
+ annepro2Led_t color = {
+ .p.red = 0,
+ .p.green = 0,
+ .p.blue = 0,
+ .p.alpha = 0,
+ };
+ annepro2LedMaskSetMono(color);
+}
+
+/*
+ * Currently keypresses are unified with other messages, still with single 1
+ * byte payload. Transfer is normally fast enough for that to not be a problem -
+ * especially with asynchronous message reading.
+ *
+ *
+ * Previous description:
+ * If enabled, this data is sent to LED MCU on every keypress.
+ * In order to improve performance, both row and column values
+ * are packed into a single byte.
+ * Row range is [0, 4] and requires only 3 bits.
+ * Column range is [0, 13] and requires 4 bits.
+ *
+ * In order to differentiate this command from regular commands,
+ * the leftmost bit is set to 1 (0b10000000).
+ * Following it are 3 bits of row and 4 bits of col.
+ * 1 + 3 + 4 = 8 bits - only a single byte is sent for every keypress.
+ */
+void annepro2LedForwardKeypress(uint8_t row, uint8_t col) {
+ const uint8_t payload = row << 4 | col;
+ protoTx(CMD_LED_KEY_DOWN, &payload, 1, 1);
+}
diff --git a/keyboards/annepro2/ap2_led.h b/keyboards/annepro2/ap2_led.h
new file mode 100644
index 0000000000..23712a2555
--- /dev/null
+++ b/keyboards/annepro2/ap2_led.h
@@ -0,0 +1,84 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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 "protocol.h"
+
+// Struct defining an LED and its RGB color components
+// Compatible with Shine firmware.
+typedef union {
+ struct {
+ /* Little endian ordering to match uint32_t */
+ uint8_t blue, green, red;
+ /* Used in mask; nonzero means - use color from mask. */
+ uint8_t alpha;
+ } p; /* parts */
+ /* Parts vector access: 0 - blue, 1 - green, 2 - red */
+ uint8_t pv[4];
+ /* 0xrgb in mem is b g r a */
+ uint32_t rgb;
+} annepro2Led_t;
+
+#define ROWCOL2IDX(row, col) (NUM_COLUMN * (row) + (col))
+#define NUM_COLUMN 14
+#define NUM_ROW 5
+#define KEY_COUNT 70
+
+/* Local copy of ledMask, used to override colors on the board */
+extern annepro2Led_t ledMask[KEY_COUNT];
+
+/* Handle incoming messages */
+extern void ledCommandCallback(const message_t *msg);
+
+void annepro2SetIAP(void);
+void annepro2LedDisable(void);
+void annepro2LedEnable(void);
+void annepro2LedSetProfile(uint8_t prof);
+void annepro2LedGetStatus(void);
+void annepro2LedNextProfile(void);
+void annepro2LedPrevProfile(void);
+void annepro2LedNextIntensity(void);
+void annepro2LedNextAnimationSpeed(void);
+void annepro2LedForwardKeypress(uint8_t row, uint8_t col);
+
+/* Set single key to a given color; alpha controls which is displayed */
+void annepro2LedMaskSetKey(uint8_t row, uint8_t col, annepro2Led_t color);
+/* Push a whole local row to the shine */
+void annepro2LedMaskSetRow(uint8_t row);
+/* Synchronize all rows */
+void annepro2LedMaskSetAll(void);
+
+/* Set all keys to a given color */
+void annepro2LedMaskSetMono(annepro2Led_t color);
+
+/* Blink given key `count` times by masking it with a `color`. Blink takes `hundredths` of a second */
+void annepro2LedBlink(uint8_t row, uint8_t col, annepro2Led_t color, uint8_t count, uint8_t hundredths);
+
+/* Kept for compatibility, but implemented using masks */
+void annepro2LedSetForegroundColor(uint8_t red, uint8_t green, uint8_t blue);
+void annepro2LedResetForegroundColor(void);
+
+typedef struct {
+ uint8_t amountOfProfiles;
+ uint8_t currentProfile;
+ uint8_t matrixEnabled;
+ uint8_t isReactive;
+ uint8_t ledIntensity;
+ uint8_t errors;
+} annepro2LedStatus_t;
+
+extern annepro2LedStatus_t annepro2LedStatus;
diff --git a/keyboards/annepro2/boards/ANNEPRO2_C15/board.c b/keyboards/annepro2/boards/ANNEPRO2_C15/board.c
new file mode 100644
index 0000000000..60c1826155
--- /dev/null
+++ b/keyboards/annepro2/boards/ANNEPRO2_C15/board.c
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2020 Yaotian Feng, Codetector
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "hal.h"
+
+/* ============ Private Defines ===================== */
+
+/* ============ Function Prototypes ================== */
+
+#define PBIT(PORT, LINE) ((PAL_PORT(LINE) == PORT) ? (1 << PAL_PAD(LINE)) : 0)
+#define PAFIO_L(PORT, LINE, AF) (((PAL_PORT(LINE) == PORT) && (PAL_PAD(LINE) < 8)) ? (AF << (PAL_PAD(LINE) << 2)) : 0)
+#define PAFIO_H(PORT, LINE, AF) (((PAL_PORT(LINE) == PORT) && (PAL_PAD(LINE) >= 8)) ? (AF << ((PAL_PAD(LINE) - 8) << 2)) : 0)
+#define PAFIO(PORT, N, LINE, AF) ((N) ? PAFIO_H(PORT, LINE, AF) : PAFIO_L(PORT, LINE, AF))
+
+#define OUT_BITS(PORT) (PBIT(PORT, C2) | PBIT(PORT, C1) | PBIT(PORT, B5) | PBIT(PORT, B4) | PBIT(PORT, C3) | 0)
+
+#define IN_BITS(PORT) (PBIT(PORT, C4) | PBIT(PORT, C5) | PBIT(PORT, B10) | PBIT(PORT, B11) | PBIT(PORT, C0) | PBIT(PORT, A15) | PBIT(PORT, A8) | PBIT(PORT, A10) | PBIT(PORT, A11) | PBIT(PORT, A12) | PBIT(PORT, A13) | PBIT(PORT, A14) | PBIT(PORT, B2) | PBIT(PORT, B3) | 0)
+
+// Alternate Functions
+#define AF_BITS(PORT, N) (PAFIO(PORT, N, LINE_UART_RX, AFIO_USART) | PAFIO(PORT, N, LINE_UART_TX, AFIO_USART) | PAFIO(PORT, N, LINE_BT_UART_TX, AFIO_USART) | PAFIO(PORT, N, LINE_BT_UART_RX, AFIO_USART) | PAFIO(PORT, N, C2, AFIO_GPIO) | PAFIO(PORT, N, C1, AFIO_GPIO) | PAFIO(PORT, N, B5, AFIO_GPIO) | PAFIO(PORT, N, B4, AFIO_GPIO) | PAFIO(PORT, N, C3, AFIO_GPIO) | PAFIO(PORT, N, C4, AFIO_GPIO) | PAFIO(PORT, N, C5, AFIO_GPIO) | PAFIO(PORT, N, B10, AFIO_GPIO) | PAFIO(PORT, N, B11, AFIO_GPIO) | PAFIO(PORT, N, C0, AFIO_GPIO) | PAFIO(PORT, N, A15, AFIO_GPIO) | PAFIO(PORT, N, A8, AFIO_GPIO) | PAFIO(PORT, N, A10, AFIO_GPIO) | PAFIO(PORT, N, A11, AFIO_GPIO) | PAFIO(PORT, N, A12, AFIO_GPIO) | PAFIO(PORT, N, A13, AFIO_GPIO) | PAFIO(PORT, N, A14, AFIO_GPIO) | PAFIO(PORT, N, B2, AFIO_GPIO) | PAFIO(PORT, N, B3, AFIO_GPIO) | 0)
+
+/**
+ * @brief PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ * This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+ // GPIO A
+ .setup[0] =
+ {
+ .DIR = OUT_BITS(IOPORTA),
+ .INE = IN_BITS(IOPORTA),
+ .PU = IN_BITS(IOPORTA),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTA, 0),
+ .CFG[1] = AF_BITS(IOPORTA, 1),
+ },
+ // GPIO B
+ .setup[1] =
+ {
+ .DIR = OUT_BITS(IOPORTB),
+ .INE = IN_BITS(IOPORTB),
+ .PU = IN_BITS(IOPORTB),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTB, 0),
+ .CFG[1] = AF_BITS(IOPORTB, 1),
+ },
+ // GPIO C
+ .setup[2] =
+ {
+ .DIR = OUT_BITS(IOPORTC),
+ .INE = IN_BITS(IOPORTC),
+ .PU = IN_BITS(IOPORTC),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTC, 0),
+ .CFG[1] = AF_BITS(IOPORTC, 1),
+ },
+ // GPIO D
+ .setup[3] =
+ {
+ .DIR = OUT_BITS(IOPORTD),
+ .INE = IN_BITS(IOPORTD),
+ .PU = IN_BITS(IOPORTD),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTD, 0),
+ .CFG[1] = AF_BITS(IOPORTD, 1),
+ },
+ .ESSR[0] = 0x00000000,
+ .ESSR[1] = 0x00000000,
+};
+
+void __early_init(void) { ht32_clock_init(); }
+
+void boardInit(void) {}
diff --git a/keyboards/annepro2/boards/ANNEPRO2_C15/board.h b/keyboards/annepro2/boards/ANNEPRO2_C15/board.h
new file mode 100644
index 0000000000..0a044ea181
--- /dev/null
+++ b/keyboards/annepro2/boards/ANNEPRO2_C15/board.h
@@ -0,0 +1,39 @@
+/*
+ ChibiOS - Copyright (C) 2020 Codetector
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#pragma once
+/*
+ * Setup for Anne Pro 2 board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_NAME "Anne Pro 2"
+
+#define HT32F52342
+
+#define FLASH_SIZE (0x10000 - 0x4000) // 64kB - 16kB
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
\ No newline at end of file
diff --git a/keyboards/annepro2/boards/ANNEPRO2_C15/board.mk b/keyboards/annepro2/boards/ANNEPRO2_C15/board.mk
new file mode 100644
index 0000000000..f308892e7c
--- /dev/null
+++ b/keyboards/annepro2/boards/ANNEPRO2_C15/board.mk
@@ -0,0 +1,5 @@
+# List of all the board related files.
+BOARDSRC = $(BOARD_PATH)/boards/ANNEPRO2_C15/board.c
+
+# Required include directories
+BOARDINC = $(BOARD_PATH)/boards/ANNEPRO2_C15
diff --git a/keyboards/annepro2/boards/ANNEPRO2_C18/board.c b/keyboards/annepro2/boards/ANNEPRO2_C18/board.c
new file mode 100644
index 0000000000..42c03d3d00
--- /dev/null
+++ b/keyboards/annepro2/boards/ANNEPRO2_C18/board.c
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2020 Yaotian Feng, Codetector
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "hal.h"
+
+/* ============ Private Defines ===================== */
+
+/* ============ Function Prototypes ================== */
+
+#define PBIT(PORT, LINE) ((PAL_PORT(LINE) == PORT) ? (1 << PAL_PAD(LINE)) : 0)
+#define PAFIO_L(PORT, LINE, AF) (((PAL_PORT(LINE) == PORT) && (PAL_PAD(LINE) < 8)) ? (AF << (PAL_PAD(LINE) << 2)) : 0)
+#define PAFIO_H(PORT, LINE, AF) (((PAL_PORT(LINE) == PORT) && (PAL_PAD(LINE) >= 8)) ? (AF << ((PAL_PAD(LINE) - 8) << 2)) : 0)
+#define PAFIO(PORT, N, LINE, AF) ((N) ? PAFIO_H(PORT, LINE, AF) : PAFIO_L(PORT, LINE, AF))
+
+#define OUT_BITS(PORT) (PBIT(PORT, B5) | PBIT(PORT, B4) | PBIT(PORT, B3) | PBIT(PORT, B2) | PBIT(PORT, D1) | 0)
+
+#define IN_BITS(PORT) (PBIT(PORT, C4) | PBIT(PORT, C5) | PBIT(PORT, D0) | PBIT(PORT, B15) | PBIT(PORT, C11) | PBIT(PORT, A15) | PBIT(PORT, C12) | PBIT(PORT, C13) | PBIT(PORT, A8) | PBIT(PORT, A10) | PBIT(PORT, A11) | PBIT(PORT, A14) | PBIT(PORT, D2) | PBIT(PORT, D3) | 0)
+
+// Alternate Functions
+#define AF_BITS(PORT, N) (PAFIO(PORT, N, LINE_UART_RX, AFIO_USART) | PAFIO(PORT, N, LINE_UART_TX, AFIO_USART) | PAFIO(PORT, N, LINE_BT_UART_TX, AFIO_USART) | PAFIO(PORT, N, LINE_BT_UART_RX, AFIO_USART) | PAFIO(PORT, N, B5, AFIO_GPIO) | PAFIO(PORT, N, B4, AFIO_GPIO) | PAFIO(PORT, N, B3, AFIO_GPIO) | PAFIO(PORT, N, B2, AFIO_GPIO) | PAFIO(PORT, N, D1, AFIO_GPIO) | PAFIO(PORT, N, C4, AFIO_GPIO) | PAFIO(PORT, N, C5, AFIO_GPIO) | PAFIO(PORT, N, D0, AFIO_GPIO) | PAFIO(PORT, N, B15, AFIO_GPIO) | PAFIO(PORT, N, C11, AFIO_GPIO) | PAFIO(PORT, N, A15, AFIO_GPIO) | PAFIO(PORT, N, C12, AFIO_GPIO) | PAFIO(PORT, N, C13, AFIO_GPIO) | PAFIO(PORT, N, A8, AFIO_GPIO) | PAFIO(PORT, N, A10, AFIO_GPIO) | PAFIO(PORT, N, A11, AFIO_GPIO) | PAFIO(PORT, N, A14, AFIO_GPIO) | PAFIO(PORT, N, D2, AFIO_GPIO) | PAFIO(PORT, N, D3, AFIO_GPIO) | 0)
+
+/**
+ * @brief PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ * This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+ // GPIO A
+ .setup[0] =
+ {
+ .DIR = OUT_BITS(IOPORTA),
+ .INE = IN_BITS(IOPORTA),
+ .PU = IN_BITS(IOPORTA),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTA, 0),
+ .CFG[1] = AF_BITS(IOPORTA, 1),
+ },
+ // GPIO B
+ .setup[1] =
+ {
+ .DIR = OUT_BITS(IOPORTB),
+ .INE = IN_BITS(IOPORTB),
+ .PU = IN_BITS(IOPORTB),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTB, 0),
+ .CFG[1] = AF_BITS(IOPORTB, 1),
+ },
+ // GPIO C
+ .setup[2] =
+ {
+ .DIR = OUT_BITS(IOPORTC),
+ .INE = IN_BITS(IOPORTC),
+ .PU = IN_BITS(IOPORTC),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTC, 0),
+ .CFG[1] = AF_BITS(IOPORTC, 1),
+ },
+ // GPIO D
+ .setup[3] =
+ {
+ .DIR = OUT_BITS(IOPORTD),
+ .INE = IN_BITS(IOPORTD),
+ .PU = IN_BITS(IOPORTD),
+ .PD = 0x0000,
+ .OD = 0x0000,
+ .DRV = 0x0000,
+ .LOCK = 0x0000,
+ .OUT = 0x0000,
+ .CFG[0] = AF_BITS(IOPORTD, 0),
+ .CFG[1] = AF_BITS(IOPORTD, 1),
+ },
+ .ESSR[0] = 0x00000000,
+ .ESSR[1] = 0x00000000,
+};
+
+void __early_init(void) { ht32_clock_init(); }
+
+void boardInit(void) {}
diff --git a/keyboards/annepro2/boards/ANNEPRO2_C18/board.h b/keyboards/annepro2/boards/ANNEPRO2_C18/board.h
new file mode 100644
index 0000000000..7345b24231
--- /dev/null
+++ b/keyboards/annepro2/boards/ANNEPRO2_C18/board.h
@@ -0,0 +1,39 @@
+/*
+ ChibiOS - Copyright (C) 2020 Codetector
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#pragma once
+/*
+ * Setup for Anne Pro 2 board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_NAME "Anne Pro 2"
+
+#define HT32F52342
+
+#define FLASH_SIZE (0x10000 - 0x4000) // 64kB - 16kB
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
diff --git a/keyboards/annepro2/boards/ANNEPRO2_C18/board.mk b/keyboards/annepro2/boards/ANNEPRO2_C18/board.mk
new file mode 100644
index 0000000000..1b41dede85
--- /dev/null
+++ b/keyboards/annepro2/boards/ANNEPRO2_C18/board.mk
@@ -0,0 +1,5 @@
+# List of all the board related files.
+BOARDSRC = $(BOARD_PATH)/boards/ANNEPRO2_C18/board.c
+
+# Required include directories
+BOARDINC = $(BOARD_PATH)/boards/ANNEPRO2_C18
diff --git a/keyboards/annepro2/c15/config.h b/keyboards/annepro2/c15/config.h
new file mode 100644
index 0000000000..f28a6a1b53
--- /dev/null
+++ b/keyboards/annepro2/c15/config.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 Charlie Waters
+ *
+ * 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 "pin_defs.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xfeed
+#define PRODUCT_ID 0xac15
+#define DEVICE_VER 0x1337
+#define MANUFACTURER Obins
+#define PRODUCT Anne Pro 2 QMK
+// key matrix size
+#define MATRIX_ROWS 5
+#define MATRIX_COLS 14
+// layer size: MATRIX_ROWS * MATRIX_COLS * sizeof(uint16_t) = 140 bytes
+
+#define LINE_UART_TX B0 // Master TX, LED RX
+#define LINE_UART_RX B1 // Master RX, LED TX
+
+#define LINE_BT_UART_TX A4 // Master TX, BLE RX
+#define LINE_BT_UART_RX A5 // Master RX, BLE TX
+
+// outputs (rows are pulled low)
+#define MATRIX_ROW_PINS \
+ { C2, C1, B5, B4, C3 }
+
+// inputs (columns are sampled)
+// PORTA 12,13 conflict with SWD
+
+#define MATRIX_COL_PINS \
+ { C4, C5, B10, B11, C0, A15, A8, A10, A11, A12, A13, A14, B2, B3 }
diff --git a/keyboards/annepro2/c15/readme.md b/keyboards/annepro2/c15/readme.md
new file mode 100644
index 0000000000..5fadb73909
--- /dev/null
+++ b/keyboards/annepro2/c15/readme.md
@@ -0,0 +1 @@
+AnnePro2, ANSI C15 version.
diff --git a/keyboards/annepro2/c15/rules.mk b/keyboards/annepro2/c15/rules.mk
new file mode 100644
index 0000000000..554ddc28ce
--- /dev/null
+++ b/keyboards/annepro2/c15/rules.mk
@@ -0,0 +1,37 @@
+# Anne Pro 2
+SRC = \
+ matrix.c \
+ annepro2_ble.c \
+ ap2_led.c \
+ protocol.c
+
+# MCU
+MCU = cortex-m0plus
+ARMV = 6
+USE_FPU = no
+MCU_FAMILY = HT32
+MCU_SERIES = HT32F523xx
+MCU_LDSCRIPT = HT32F52342_ANNEPRO2
+MCU_STARTUP = ht32f523xx
+
+BOARD = ANNEPRO2_C15
+
+# Options
+
+# Keys
+CUSTOM_MATRIX = lite
+NKRO_ENABLE = no
+MOUSEKEY_ENABLE = no
+EXTRAKEY_ENABLE = yes
+KEY_LOCK_ENABLE = no
+
+# Other featues
+BOOTMAGIC_ENABLE = no
+CONSOLE_ENABLE = no
+COMMAND_ENABLE = no
+RAW_ENABLE = no
+MIDI_ENABLE = no
+VIRTSER_ENABLE = no
+COMBO_ENABLE = no
+BOOTLOADER = custom
+PROGRAM_CMD = annepro2_tools --boot $(BUILD_DIR)/$(TARGET).bin
diff --git a/keyboards/annepro2/c18/config.h b/keyboards/annepro2/c18/config.h
new file mode 100644
index 0000000000..f610ef76e4
--- /dev/null
+++ b/keyboards/annepro2/c18/config.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Charlie Waters
+ *
+ * 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 "pin_defs.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xfeed
+#define PRODUCT_ID 0xac18
+#define DEVICE_VER 0x1337
+#define MANUFACTURER Obins
+#define PRODUCT Anne Pro 2(c18)QMK
+// key matrix size
+#define MATRIX_ROWS 5
+#define MATRIX_COLS 14
+// layer size: MATRIX_ROWS * MATRIX_COLS * sizeof(uint16_t) = 140 bytes
+
+#define LINE_UART_TX B0
+#define LINE_UART_RX B1
+
+#define LINE_BT_UART_TX A4 // Master TX, BLE RX
+#define LINE_BT_UART_RX A5 // Master RX, BLE TX
+
+// outputs (rows are pulled low)
+#define MATRIX_ROW_PINS \
+ { B5, B4, B3, B2, D1 }
+
+// inputs (columns are sampled)
+#define MATRIX_COL_PINS \
+ { C4, C5, D0, B15, C11, A15, C12, C13, A8, A10, A11, A14, D2, D3 }
diff --git a/keyboards/annepro2/c18/readme.md b/keyboards/annepro2/c18/readme.md
new file mode 100644
index 0000000000..f2e2fc45b8
--- /dev/null
+++ b/keyboards/annepro2/c18/readme.md
@@ -0,0 +1 @@
+AnnePro2, ANSI C18 version.
diff --git a/keyboards/annepro2/c18/rules.mk b/keyboards/annepro2/c18/rules.mk
new file mode 100644
index 0000000000..b2e16cc35f
--- /dev/null
+++ b/keyboards/annepro2/c18/rules.mk
@@ -0,0 +1,37 @@
+# Anne Pro 2
+SRC = \
+ matrix.c \
+ annepro2_ble.c \
+ ap2_led.c \
+ protocol.c
+
+# MCU
+MCU = cortex-m0plus
+ARMV = 6
+USE_FPU = no
+MCU_FAMILY = HT32
+MCU_SERIES = HT32F523xx
+MCU_LDSCRIPT = HT32F52342_ANNEPRO2
+MCU_STARTUP = ht32f523xx
+
+BOARD = ANNEPRO2_C18
+
+# Options
+
+# Keys
+CUSTOM_MATRIX = lite
+NKRO_ENABLE = no
+MOUSEKEY_ENABLE = no
+EXTRAKEY_ENABLE = yes
+KEY_LOCK_ENABLE = no
+
+# Other featues
+BOOTMAGIC_ENABLE = yes
+CONSOLE_ENABLE = no
+COMMAND_ENABLE = no
+RAW_ENABLE = no
+MIDI_ENABLE = no
+VIRTSER_ENABLE = no
+COMBO_ENABLE = no
+BOOTLOADER = custom
+PROGRAM_CMD = annepro2_tools --boot $(BUILD_DIR)/$(TARGET).bin
diff --git a/keyboards/annepro2/chconf.h b/keyboards/annepro2/chconf.h
new file mode 100644
index 0000000000..51fe38cf27
--- /dev/null
+++ b/keyboards/annepro2/chconf.h
@@ -0,0 +1,31 @@
+/* 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 .
+ */
+
+/*
+ * This file was auto-generated by:
+ * `qmk chibios-confmigrate -i keyboards/annepro2/chconf.h -r platforms/chibios/common/configs/chconf.h`
+ */
+
+#pragma once
+
+#define CH_CFG_ST_FREQUENCY 1000
+
+#define CH_CFG_ST_TIMEDELTA 0
+
+#define CH_CFG_TIME_QUANTUM 20
+
+
+#include_next
\ No newline at end of file
diff --git a/keyboards/annepro2/halconf.h b/keyboards/annepro2/halconf.h
new file mode 100644
index 0000000000..686b91a7fb
--- /dev/null
+++ b/keyboards/annepro2/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 .
+ */
+
+/*
+ * This file was auto-generated by:
+ * `qmk chibios-confmigrate -i keyboards/annepro2/halconf.h -r platforms/chibios/common/configs/halconf.h`
+ */
+
+#pragma once
+
+#define HAL_USE_SERIAL TRUE
+
+#define SERIAL_USB_BUFFERS_SIZE 256
+
+#include_next
diff --git a/keyboards/annepro2/info.json b/keyboards/annepro2/info.json
new file mode 100644
index 0000000000..8fd515bd10
--- /dev/null
+++ b/keyboards/annepro2/info.json
@@ -0,0 +1,330 @@
+{
+ "keyboard_name": "Anne Pro 2",
+ "url": "https://openannepro.github.io/",
+ "maintainer": "community",
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {
+ "label": "~",
+ "x": 0,
+ "y": 0
+ },
+ {
+ "label": "!",
+ "x": 1,
+ "y": 0
+ },
+ {
+ "label": "@",
+ "x": 2,
+ "y": 0
+ },
+ {
+ "label": "#",
+ "x": 3,
+ "y": 0
+ },
+ {
+ "label": "$",
+ "x": 4,
+ "y": 0
+ },
+ {
+ "label": "%",
+ "x": 5,
+ "y": 0
+ },
+ {
+ "label": "^",
+ "x": 6,
+ "y": 0
+ },
+ {
+ "label": "&",
+ "x": 7,
+ "y": 0
+ },
+ {
+ "label": "*",
+ "x": 8,
+ "y": 0
+ },
+ {
+ "label": "(",
+ "x": 9,
+ "y": 0
+ },
+ {
+ "label": ")",
+ "x": 10,
+ "y": 0
+ },
+ {
+ "label": "_",
+ "x": 11,
+ "y": 0
+ },
+ {
+ "label": "+",
+ "x": 12,
+ "y": 0
+ },
+ {
+ "label": "Backspace",
+ "x": 13,
+ "y": 0,
+ "w": 2
+ },
+ {
+ "label": "Tab",
+ "x": 0,
+ "y": 1,
+ "w": 1.5
+ },
+ {
+ "label": "Q",
+ "x": 1.5,
+ "y": 1
+ },
+ {
+ "label": "W",
+ "x": 2.5,
+ "y": 1
+ },
+ {
+ "label": "E",
+ "x": 3.5,
+ "y": 1
+ },
+ {
+ "label": "R",
+ "x": 4.5,
+ "y": 1
+ },
+ {
+ "label": "T",
+ "x": 5.5,
+ "y": 1
+ },
+ {
+ "label": "Y",
+ "x": 6.5,
+ "y": 1
+ },
+ {
+ "label": "U",
+ "x": 7.5,
+ "y": 1
+ },
+ {
+ "label": "I",
+ "x": 8.5,
+ "y": 1
+ },
+ {
+ "label": "O",
+ "x": 9.5,
+ "y": 1
+ },
+ {
+ "label": "P",
+ "x": 10.5,
+ "y": 1
+ },
+ {
+ "label": "{",
+ "x": 11.5,
+ "y": 1
+ },
+ {
+ "label": "}",
+ "x": 12.5,
+ "y": 1
+ },
+ {
+ "label": "|",
+ "x": 13.5,
+ "y": 1,
+ "w": 1.5
+ },
+ {
+ "label": "Caps Lock",
+ "x": 0,
+ "y": 2,
+ "w": 1.75
+ },
+ {
+ "label": "A",
+ "x": 1.75,
+ "y": 2
+ },
+ {
+ "label": "S",
+ "x": 2.75,
+ "y": 2
+ },
+ {
+ "label": "D",
+ "x": 3.75,
+ "y": 2
+ },
+ {
+ "label": "F",
+ "x": 4.75,
+ "y": 2
+ },
+ {
+ "label": "G",
+ "x": 5.75,
+ "y": 2
+ },
+ {
+ "label": "H",
+ "x": 6.75,
+ "y": 2
+ },
+ {
+ "label": "J",
+ "x": 7.75,
+ "y": 2
+ },
+ {
+ "label": "K",
+ "x": 8.75,
+ "y": 2
+ },
+ {
+ "label": "L",
+ "x": 9.75,
+ "y": 2
+ },
+ {
+ "label": ":",
+ "x": 10.75,
+ "y": 2
+ },
+ {
+ "label": "\"",
+ "x": 11.75,
+ "y": 2
+ },
+ {
+ "label": "Enter",
+ "x": 12.75,
+ "y": 2,
+ "w": 2.25
+ },
+ {
+ "label": "Shift",
+ "x": 0,
+ "y": 3,
+ "w": 2.25
+ },
+ {
+ "label": "Z",
+ "x": 2.25,
+ "y": 3
+ },
+ {
+ "label": "X",
+ "x": 3.25,
+ "y": 3
+ },
+ {
+ "label": "C",
+ "x": 4.25,
+ "y": 3
+ },
+ {
+ "label": "V",
+ "x": 5.25,
+ "y": 3
+ },
+ {
+ "label": "B",
+ "x": 6.25,
+ "y": 3
+ },
+ {
+ "label": "N",
+ "x": 7.25,
+ "y": 3
+ },
+ {
+ "label": "M",
+ "x": 8.25,
+ "y": 3
+ },
+ {
+ "label": "<",
+ "x": 9.25,
+ "y": 3
+ },
+ {
+ "label": ">",
+ "x": 10.25,
+ "y": 3
+ },
+ {
+ "label": "?",
+ "x": 11.25,
+ "y": 3
+ },
+ {
+ "label": "Shift",
+ "x": 12.25,
+ "y": 3,
+ "w": 2.75
+ },
+ {
+ "label": "Ctrl",
+ "x": 0,
+ "y": 4,
+ "w": 1.25
+ },
+ {
+ "label": "Win",
+ "x": 1.25,
+ "y": 4,
+ "w": 1.25
+ },
+ {
+ "label": "Alt",
+ "x": 2.5,
+ "y": 4,
+ "w": 1.25
+ },
+ {
+ "x": 3.75,
+ "y": 4,
+ "w": 6.25
+ },
+ {
+ "label": "Alt",
+ "x": 10,
+ "y": 4,
+ "w": 1.25
+ },
+ {
+ "label": "Win",
+ "x": 11.25,
+ "y": 4,
+ "w": 1.25
+ },
+ {
+ "label": "Menu",
+ "x": 12.5,
+ "y": 4,
+ "w": 1.25
+ },
+ {
+ "label": "Ctrl",
+ "x": 13.75,
+ "y": 4,
+ "w": 1.25
+ }
+ ]
+ }
+ }
+}
diff --git a/keyboards/annepro2/keymaps/default-full-caps/config.h b/keyboards/annepro2/keymaps/default-full-caps/config.h
new file mode 100644
index 0000000000..413c5d8dc5
--- /dev/null
+++ b/keyboards/annepro2/keymaps/default-full-caps/config.h
@@ -0,0 +1,20 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+
+// Obins stock firmware has something similar to this already enabled, but disabled by default in QMK
+#define PERMISSIVE_HOLD
diff --git a/keyboards/annepro2/keymaps/default-full-caps/keymap.c b/keyboards/annepro2/keymaps/default-full-caps/keymap.c
new file mode 100644
index 0000000000..8ac9211ac4
--- /dev/null
+++ b/keyboards/annepro2/keymaps/default-full-caps/keymap.c
@@ -0,0 +1,120 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+
+enum anne_pro_layers {
+ _BASE_LAYER,
+ _FN1_LAYER,
+ _FN2_LAYER,
+};
+
+// clang-format off
+
+// Key symbols are based on QMK. Use them to remap your keyboard
+/*
+* Layer _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bksp |
+* |-----------------------------------------------------------------------------------------+
+* | Tab | q | w | e | r | t | y | u | i | o | p | [ | ] | \ |
+* |-----------------------------------------------------------------------------------------+
+* | Caps | a | s | d | f | g | h | j | k | l | ; | ' | Enter |
+* |-----------------------------------------------------------------------------------------+
+* | Shift | z | x | c | v | b | n | m | , | . | / | Shift |
+* |-----------------------------------------------------------------------------------------+
+* | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+* \-----------------------------------------------------------------------------------------/
+* Layer TAP in _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | UP |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | LEFT | DOWN | RIGHT |
+* \-----------------------------------------------------------------------------------------/
+*/
+ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_BASE_LAYER] = LAYOUT( /* Base */
+ KC_ESC, 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_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,
+ LT(_FN1_LAYER,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_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, RSFT_T(KC_UP),
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, LT(_FN1_LAYER,KC_LEFT), LT(_FN2_LAYER,KC_DOWN), RCTL_T(KC_RGHT)
+),
+ /*
+ * Layer _FN1_LAYER
+ * ,-----------------------------------------------------------------------------------------.
+ * | ` | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DELETE |
+ * |-----------------------------------------------------------------------------------------+
+ * | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
+ * |-----------------------------------------------------------------------------------------+
+ * | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
+ * |-----------------------------------------------------------------------------------------+
+ * | Shift |V-UP |V-DWN|MUTE | v | b | n | m | , |INSRT| DEL | Shift |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN1_LAYER] = LAYOUT( /* Base */
+ KC_GRV, 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_DEL,
+ KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
+ KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
+ KC_TRNS, KC_VOLU, KC_VOLD, KC_MUTE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN2_LAYER), KC_TRNS
+),
+ /*
+ * Layer _FN2_LAYER
+ * ,-----------------------------------------------------------------------------------------.
+ * | ~ | BT1 | BT2 | BT3 | BT4 | F5 | F6 | F7 |LEDOF|LEDON| F10 | F11 | F12 | Bksp |
+ * |-----------------------------------------------------------------------------------------+
+ * | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
+ * |-----------------------------------------------------------------------------------------+
+ * | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
+ * |-----------------------------------------------------------------------------------------+
+ * | Shift | z | x | c | v | b | n | m | , |INSRT| DEL | Shift |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN2_LAYER] = LAYOUT( /* Base */
+ KC_TRNS, KC_AP2_BT1, KC_AP2_BT2, KC_AP2_BT3, KC_AP2_BT4, KC_TRNS, KC_TRNS, KC_TRNS, KC_AP_LED_OFF, KC_AP_LED_ON, KC_AP_LED_NEXT_INTENSITY, KC_AP_LED_SPEED, KC_TRNS, KC_TRNS,
+ MO(_FN2_LAYER), KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
+ KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN1_LAYER), MO(_FN2_LAYER), KC_TRNS
+ ),
+};
+
+// clang-format on
+
+// The function to handle the caps lock logic
+bool led_update_user(led_t leds) {
+ if (leds.caps_lock) {
+ // Set the leds to red
+ annepro2LedSetForegroundColor(0xFF, 0x00, 0x00);
+ } else {
+ annepro2LedResetForegroundColor();
+ }
+
+ return true;
+}
diff --git a/keyboards/annepro2/keymaps/default-layer-indicators/config.h b/keyboards/annepro2/keymaps/default-layer-indicators/config.h
new file mode 100644
index 0000000000..413c5d8dc5
--- /dev/null
+++ b/keyboards/annepro2/keymaps/default-layer-indicators/config.h
@@ -0,0 +1,20 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+
+// Obins stock firmware has something similar to this already enabled, but disabled by default in QMK
+#define PERMISSIVE_HOLD
diff --git a/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c b/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c
new file mode 100644
index 0000000000..ac2b421d06
--- /dev/null
+++ b/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c
@@ -0,0 +1,147 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+
+enum anne_pro_layers {
+ _BASE_LAYER,
+ _FN1_LAYER,
+ _FN2_LAYER,
+};
+
+// clang-format off
+
+// Key symbols are based on QMK. Use them to remap your keyboard
+/*
+* Layer _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bksp |
+* |-----------------------------------------------------------------------------------------+
+* | Tab | q | w | e | r | t | y | u | i | o | p | [ | ] | \ |
+* |-----------------------------------------------------------------------------------------+
+* | Caps | a | s | d | f | g | h | j | k | l | ; | ' | Enter |
+* |-----------------------------------------------------------------------------------------+
+* | Shift | z | x | c | v | b | n | m | , | . | / | Shift |
+* |-----------------------------------------------------------------------------------------+
+* | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+* \-----------------------------------------------------------------------------------------/
+* Layer TAP in _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | UP |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | LEFT | DOWN | RIGHT |
+* \-----------------------------------------------------------------------------------------/
+*/
+ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_BASE_LAYER] = LAYOUT( /* Base */
+ KC_ESC, 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_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,
+ LT(_FN1_LAYER,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_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, RSFT_T(KC_UP),
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, LT(_FN1_LAYER,KC_LEFT), LT(_FN2_LAYER,KC_DOWN), RCTL_T(KC_RGHT)
+),
+ /*
+ * Layer _FN1_LAYER
+ * ,-----------------------------------------------------------------------------------------.
+ * | ` | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DELETE |
+ * |-----------------------------------------------------------------------------------------+
+ * | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
+ * |-----------------------------------------------------------------------------------------+
+ * | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
+ * |-----------------------------------------------------------------------------------------+
+ * | Shift |V-UP |V-DWN|MUTE | v | b | n | m | , |INSRT| DEL | Shift |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN1_LAYER] = LAYOUT( /* Base */
+ KC_GRV, 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_DEL,
+ KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
+ KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
+ KC_TRNS, KC_VOLU, KC_VOLD, KC_MUTE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN2_LAYER), KC_TRNS
+),
+ /*
+ * Layer _FN2_LAYER
+ * ,-----------------------------------------------------------------------------------------.
+ * | ~ | BT1 | BT2 | BT3 | BT4 | F5 | F6 | F7 |LEDOF|LEDON| F10 | F11 | F12 | Bksp |
+ * |-----------------------------------------------------------------------------------------+
+ * | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
+ * |-----------------------------------------------------------------------------------------+
+ * | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
+ * |-----------------------------------------------------------------------------------------+
+ * | Shift | z | x | c | v | b | n | m | , |INSRT| DEL | Shift |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN2_LAYER] = LAYOUT( /* Base */
+ KC_TRNS, KC_AP2_BT1, KC_AP2_BT2, KC_AP2_BT3, KC_AP2_BT4, KC_TRNS, KC_TRNS, KC_TRNS, KC_AP_LED_OFF, KC_AP_LED_ON, KC_AP_LED_NEXT_INTENSITY, KC_AP_LED_SPEED, KC_TRNS, KC_TRNS,
+ MO(_FN2_LAYER), KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
+ KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN1_LAYER), MO(_FN2_LAYER), KC_TRNS
+ ),
+};
+
+// clang-format on
+
+layer_state_t layer_state_set_user(layer_state_t state) {
+ switch (get_highest_layer(state)) {
+ case _FN1_LAYER:
+ // Set the leds to green
+ annepro2LedSetForegroundColor(0x00, 0xFF, 0x00);
+ break;
+ case _FN2_LAYER:
+ // Set the leds to blue
+ annepro2LedSetForegroundColor(0x00, 0x00, 0xFF);
+ break;
+ default:
+ // Reset back to the current profile
+ annepro2LedResetForegroundColor();
+ break;
+ }
+ return state;
+}
+
+// The function to handle the caps lock logic
+// It's called after the capslock changes state or after entering layers 1 and 2.
+bool led_update_user(led_t leds) {
+ if (leds.caps_lock) {
+ // Set the caps-lock to red
+ const annepro2Led_t color = {.p.red = 0xff, .p.green = 0x00, .p.blue = 0x00, .p.alpha = 0xff};
+
+ annepro2LedMaskSetKey(2, 0, color);
+ /* NOTE: Instead of colouring the capslock only, you can change the whole
+ keyboard with annepro2LedSetForegroundColor */
+ } else {
+ // Reset the capslock if there is no layer active
+ if (!layer_state_is(_FN1_LAYER) && !layer_state_is(_FN2_LAYER)) {
+ const annepro2Led_t color = {.p.red = 0xff, .p.green = 0x00, .p.blue = 0x00, .p.alpha = 0x00};
+ annepro2LedMaskSetKey(2, 0, color);
+ }
+ }
+
+ return true;
+}
diff --git a/keyboards/annepro2/keymaps/default/config.h b/keyboards/annepro2/keymaps/default/config.h
new file mode 100644
index 0000000000..413c5d8dc5
--- /dev/null
+++ b/keyboards/annepro2/keymaps/default/config.h
@@ -0,0 +1,20 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+
+// Obins stock firmware has something similar to this already enabled, but disabled by default in QMK
+#define PERMISSIVE_HOLD
diff --git a/keyboards/annepro2/keymaps/default/keymap.c b/keyboards/annepro2/keymaps/default/keymap.c
new file mode 100644
index 0000000000..a984b05830
--- /dev/null
+++ b/keyboards/annepro2/keymaps/default/keymap.c
@@ -0,0 +1,106 @@
+ /* Copyright 2021 OpenAnnePro community
+ *
+ * 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
+
+enum anne_pro_layers {
+ _BASE_LAYER,
+ _FN1_LAYER,
+ _FN2_LAYER,
+};
+
+// clang-format off
+// Key symbols are based on QMK. Use them to remap your keyboard
+/*
+* Layer _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bksp |
+* |-----------------------------------------------------------------------------------------+
+* | Tab | q | w | e | r | t | y | u | i | o | p | [ | ] | \ |
+* |-----------------------------------------------------------------------------------------+
+* | Caps | a | s | d | f | g | h | j | k | l | ; | ' | Enter |
+* |-----------------------------------------------------------------------------------------+
+* | Shift | z | x | c | v | b | n | m | , | . | / | Shift |
+* |-----------------------------------------------------------------------------------------+
+* | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+* \-----------------------------------------------------------------------------------------/
+* Layer TAP in _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | UP |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | LEFT | DOWN | RIGHT |
+* \-----------------------------------------------------------------------------------------/
+*/
+ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_BASE_LAYER] = LAYOUT( /* Base */
+ KC_ESC, 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_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,
+ LT(_FN1_LAYER,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_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, RSFT_T(KC_UP),
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, LT(_FN1_LAYER,KC_LEFT), LT(_FN2_LAYER,KC_DOWN), RCTL_T(KC_RGHT)
+),
+ /*
+ * Layer _FN1_LAYER
+ * ,-----------------------------------------------------------------------------------------.
+ * | ` | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DELETE |
+ * |-----------------------------------------------------------------------------------------+
+ * | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
+ * |-----------------------------------------------------------------------------------------+
+ * | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
+ * |-----------------------------------------------------------------------------------------+
+ * | Shift |V-UP |V-DWN|MUTE | v | b | n | m | , |INSRT| DEL | Shift |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN1_LAYER] = LAYOUT( /* Base */
+ KC_GRV, 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_DEL,
+ KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
+ KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
+ KC_TRNS, KC_VOLU, KC_VOLD, KC_MUTE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN2_LAYER), KC_TRNS
+),
+ /*
+ * Layer _FN2_LAYER
+ * ,-----------------------------------------------------------------------------------------.
+ * | ~ | BT1 | BT2 | BT3 | BT4 | F5 | F6 | F7 |LEDOF|LEDON| F10 | F11 | F12 | Bksp |
+ * |-----------------------------------------------------------------------------------------+
+ * | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
+ * |-----------------------------------------------------------------------------------------+
+ * | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
+ * |-----------------------------------------------------------------------------------------+
+ * | Shift | z | x | c | v | b | n | m | , |INSRT| DEL | Shift |
+ * |-----------------------------------------------------------------------------------------+
+ * | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN2_LAYER] = LAYOUT( /* Base */
+ KC_TRNS, KC_AP2_BT1, KC_AP2_BT2, KC_AP2_BT3, KC_AP2_BT4, KC_TRNS, KC_TRNS, KC_TRNS, KC_AP_LED_OFF, KC_AP_LED_ON, KC_AP_LED_NEXT_INTENSITY, KC_AP_LED_SPEED, KC_TRNS, KC_TRNS,
+ MO(_FN2_LAYER), KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
+ KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN1_LAYER), MO(_FN2_LAYER), KC_TRNS
+ ),
+};
+// clang-format on
diff --git a/keyboards/annepro2/ld/HT32F52342_ANNEPRO2.ld b/keyboards/annepro2/ld/HT32F52342_ANNEPRO2.ld
new file mode 100644
index 0000000000..544400b948
--- /dev/null
+++ b/keyboards/annepro2/ld/HT32F52342_ANNEPRO2.ld
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013-2016 Fabio UJonathan A. Kollaschtzig, http://fabioutzig.com
+ * (c) 2020 Yaotian Feng (Codetector)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * HT32F52342 w/ Anne Pro 2 bootloader memory setup.
+ */
+MEMORY {
+ flash0 : org = 0x00004000, len = 64k - 16k /* firmware */
+ flash1 : org = 0x00000000, len = 0
+ flash2 : org = 0x00000000, len = 0
+ flash3 : org = 0x00000000, len = 0
+ flash4 : org = 0x00000000, len = 0
+ flash5 : org = 0x00000000, len = 0
+ flash6 : org = 0x00000000, len = 0
+ flash7 : org = 0x00000000, len = 0
+ ram0 : org = 0x20000000, len = 8k - 4 /* RAM */
+ ram1 : org = 0x00000000, len = 0
+ ram2 : org = 0x00000000, len = 0
+ ram3 : org = 0x00000000, len = 0
+ ram4 : org = 0x00000000, len = 0
+ ram5 : org = 0x00000000, len = 0
+ ram6 : org = 0x00000000, len = 0
+ ram7 : org = 0x00000000, len = 0
+}
+
+/* For each data/text section two region are defined, a virtual region
+ and a load region (_LMA suffix).*/
+
+/* Flash region to be used for exception vectors.*/
+REGION_ALIAS("VECTORS_FLASH", flash0);
+REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for constructors and destructors.*/
+REGION_ALIAS("XTORS_FLASH", flash0);
+REGION_ALIAS("XTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for code text.*/
+REGION_ALIAS("TEXT_FLASH", flash0);
+REGION_ALIAS("TEXT_FLASH_LMA", flash0);
+
+/* Flash region to be used for read only data.*/
+REGION_ALIAS("RODATA_FLASH", flash0);
+REGION_ALIAS("RODATA_FLASH_LMA", flash0);
+
+/* Flash region to be used for various.*/
+REGION_ALIAS("VARIOUS_FLASH", flash0);
+REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
+
+/* Flash region to be used for RAM(n) initialization data.*/
+REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
+
+/* RAM region to be used for Main stack. This stack accommodates the processing
+ of all exceptions and interrupts.*/
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
+
+/* RAM region to be used for the process stack. This is the stack used by
+ the main() function.*/
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
+
+/* RAM region to be used for data segment.*/
+REGION_ALIAS("DATA_RAM", ram0);
+REGION_ALIAS("DATA_RAM_LMA", flash0);
+
+/* RAM region to be used for BSS segment.*/
+REGION_ALIAS("BSS_RAM", ram0);
+
+/* RAM region to be used for the default heap.*/
+REGION_ALIAS("HEAP_RAM", ram0);
+
+/* Generic rules inclusion.*/
+INCLUDE rules.ld
diff --git a/keyboards/annepro2/matrix.c b/keyboards/annepro2/matrix.c
new file mode 100644
index 0000000000..a1585e4ddf
--- /dev/null
+++ b/keyboards/annepro2/matrix.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Charlie Waters
+ *
+ * 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
+#include
+#include
+#include "timer.h"
+#include "wait.h"
+#include "print.h"
+#include "matrix.h"
+#include "annepro2.h"
+
+pin_t row_list[MATRIX_ROWS] = MATRIX_ROW_PINS;
+pin_t col_list[MATRIX_COLS] = MATRIX_COL_PINS;
+
+bool matrix_scan_custom(matrix_row_t current_matrix[]) {
+ bool matrix_has_changed = false;
+ // cache of input ports for columns
+ static uint16_t port_cache[4];
+ // scan each row
+ for (int row = 0; row < MATRIX_ROWS; row++) {
+ palClearLine(row_list[row]);
+ __NOP();
+ __NOP();
+ __NOP();
+ __NOP();
+ // read i/o ports
+ port_cache[0] = palReadPort(IOPORTA);
+ port_cache[1] = palReadPort(IOPORTB);
+ port_cache[2] = palReadPort(IOPORTC);
+ port_cache[3] = palReadPort(IOPORTD);
+ palSetLine(row_list[row]);
+
+ // get columns from ports
+ matrix_row_t data = 0;
+ for (int col = 0; col < MATRIX_COLS; ++col) {
+ pin_t line = col_list[col];
+ uint16_t port = port_cache[HT32_PAL_IDX(PAL_PORT(line))];
+ data |= (((port & (1 << PAL_PAD(line))) ? 0 : 1) << col);
+ }
+
+ if (current_matrix[row] != data) {
+ current_matrix[row] = data;
+ matrix_has_changed = true;
+ }
+ }
+ return matrix_has_changed;
+}
\ No newline at end of file
diff --git a/keyboards/annepro2/mcuconf.h b/keyboards/annepro2/mcuconf.h
new file mode 100644
index 0000000000..8265fe6eb9
--- /dev/null
+++ b/keyboards/annepro2/mcuconf.h
@@ -0,0 +1,62 @@
+/*
+ ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#pragma once
+
+#include "nvic.h"
+
+#define HT32F52342_MCUCONF
+
+/*
+ * HAL driver system settings.
+ */
+
+/*
+ * Clock configuration.
+ */
+
+// This configuration:
+// 8 MHz HSE crystal
+// PLL multiplies HSE to 48 MHz core and peripheral clock
+// 48 MHz to UART
+// 48 MHz to USB
+
+#define HT32_CK_HSE_FREQUENCY 8000000UL // 8 MHz
+#define HT32_CKCU_SW CKCU_GCCR_SW_PLL
+#define HT32_PLL_USE_HSE TRUE
+#define HT32_PLL_FBDIV 6 // 8 MHz -> 48 MHz
+#define HT32_PLL_OTDIV 0
+#define HT32_AHB_PRESCALER 1 // 48 MHz -> 48 MHz
+#define HT32_USART_PRESCALER 1 // 48 MHz
+#define HT32_USB_PRESCALER 1 // 48 MHz -> 48 MHz
+// SysTick uses processor clock at 48MHz
+#define HT32_ST_USE_HCLK TRUE
+
+/*
+ * Peripheral driver settings
+ */
+
+#define HT32_SERIAL_USE_USART0 TRUE
+#define HT32_USART0_IRQ_PRIORITY 6
+
+#define HT32_SERIAL_USE_USART1 TRUE
+#define HT32_USART1_IRQ_PRIORITY 7
+
+/*
+ * USB driver settings
+ */
+
+#define HT32_USB_USE_USB0 TRUE
+#define HT32_USB_USB0_IRQ_PRIORITY 5
diff --git a/keyboards/annepro2/protocol.c b/keyboards/annepro2/protocol.c
new file mode 100644
index 0000000000..171ac5c239
--- /dev/null
+++ b/keyboards/annepro2/protocol.c
@@ -0,0 +1,116 @@
+/*
+ * (c) 2021 by Tomasz bla Fortuna
+ * License: GPLv2
+ *
+ * This file is shared with the Shine firmware. Keep it in sync (and in the
+ * shine's clang formatting).
+ *
+ * Implementation of a robust serial protocol which can handle single dropped
+ * characters during transit without locking.
+ *
+ * At 115200, transmitting the shortest message takes 0.043ms, at 9600 - 0.52ms.
+ *
+ */
+
+#include "protocol.h"
+#include "board.h"
+#include "ch.h"
+#include "hal.h"
+
+/* UART communication protocol state */
+protocol_t proto;
+
+void protoInit(protocol_t *proto, void (*callback)(const message_t *)) {
+ proto->previousId = 0;
+ proto->callback = callback;
+ proto->state = STATE_SYNC_1;
+ proto->errors = 0;
+}
+
+static uint8_t msgId = 0;
+void protoTx(uint8_t cmd, const unsigned char *buf, int payloadSize, int retries) {
+ chDbgCheck(payloadSize <= MAX_PAYLOAD_SIZE);
+
+ const uint8_t header[5] = {
+ 0x7A, 0x1D, cmd, ++msgId, payloadSize,
+ };
+
+ /* We don't implement ACKs, yet some messages should not be lost. */
+ for (int i = 0; i < retries; i++) {
+ sdWrite(&PROTOCOL_SD, header, sizeof(header));
+ if (payloadSize) sdWrite(&PROTOCOL_SD, buf, payloadSize);
+ }
+}
+
+static inline void messageReceived(protocol_t *proto) {
+ if (proto->buffer.msgId != proto->previousId) {
+ /* It's not a resend / duplicate */
+ proto->callback(&proto->buffer);
+ proto->previousId = proto->buffer.msgId;
+ }
+ proto->state = STATE_SYNC_1;
+}
+
+void protoConsume(protocol_t *proto, uint8_t byte) {
+ switch (proto->state) {
+ case STATE_SYNC_1:
+ if (byte == 0x7A) {
+ proto->state = STATE_SYNC_2;
+ } else {
+ proto->errors++;
+ }
+ return;
+
+ case STATE_SYNC_2:
+ if (byte == 0x1D) {
+ proto->state = STATE_CMD;
+ } else {
+ proto->state = STATE_SYNC_1;
+ proto->errors++;
+ }
+ return;
+
+ case STATE_CMD:
+ proto->buffer.command = byte;
+ proto->state = STATE_ID;
+ return;
+
+ case STATE_ID:
+ proto->buffer.msgId = byte;
+ proto->state = STATE_PAYLOAD_SIZE;
+ return;
+
+ case STATE_PAYLOAD_SIZE:
+ proto->buffer.payloadSize = byte;
+ if (proto->buffer.payloadSize > MAX_PAYLOAD_SIZE) {
+ proto->buffer.payloadSize = MAX_PAYLOAD_SIZE;
+ proto->errors++;
+ }
+ proto->payloadPosition = 0;
+ if (proto->buffer.payloadSize == 0) {
+ /* No payload - whole message received */
+ messageReceived(proto);
+ } else {
+ proto->state = STATE_PAYLOAD;
+ }
+ return;
+
+ case STATE_PAYLOAD:
+ /* NOTE: This could be read with sdReadTimeout probably, but that breaks
+ * abstraction */
+ proto->buffer.payload[proto->payloadPosition] = byte;
+ proto->payloadPosition++;
+ if (proto->payloadPosition == proto->buffer.payloadSize) {
+ /* Payload read - message received */
+ messageReceived(proto);
+ }
+ return;
+ }
+}
+
+void protoSilence(protocol_t *proto) {
+ if (proto->state != STATE_SYNC_1) {
+ proto->state = STATE_SYNC_1;
+ proto->errors++;
+ }
+}
diff --git a/keyboards/annepro2/protocol.h b/keyboards/annepro2/protocol.h
new file mode 100644
index 0000000000..d1a05683c8
--- /dev/null
+++ b/keyboards/annepro2/protocol.h
@@ -0,0 +1,111 @@
+/*
+ * (c) 2021 by Tomasz bla Fortuna
+ * License: GPLv2
+ *
+ * This file is shared with the Shine firmware. Keep it in sync (and in the
+ * shine's clang formatting).
+ */
+
+#pragma once
+#include
+
+#define PROTOCOL_SD SD0
+
+enum {
+ /*
+ * Main -> LED
+ */
+ /* Basic config */
+ CMD_LED_ON = 0x01,
+ CMD_LED_OFF = 0x02,
+
+ CMD_LED_SET_PROFILE = 0x03,
+ CMD_LED_NEXT_PROFILE = 0x04,
+ CMD_LED_PREV_PROFILE = 0x05,
+
+ CMD_LED_NEXT_INTENSITY = 0x06,
+ CMD_LED_NEXT_ANIMATION_SPEED = 0x07,
+
+ /* Masks */
+ /* Override a key color, eg. capslock */
+ CMD_LED_MASK_SET_KEY = 0x10,
+ /* Override all keys in a row with configurable colors */
+ CMD_LED_MASK_SET_ROW = 0x11,
+
+ /* Override all keys with single color (eg. foreground color) */
+ CMD_LED_MASK_SET_MONO = 0x12,
+
+ /* Reactive / status */
+ CMD_LED_GET_STATUS = 0x20,
+ CMD_LED_KEY_BLINK = 0x21,
+ CMD_LED_KEY_DOWN = 0x22,
+ CMD_LED_KEY_UP = 0x23, /* TODO */
+ CMD_LED_IAP = 0x24,
+
+ /* LED -> Main */
+ /* Payload with data to send over HID */
+ CMD_LED_DEBUG = 0x40,
+
+ /* Number of profiles, current profile, on/off state,
+ reactive flag, brightness, errors */
+ CMD_LED_STATUS = 0x41,
+};
+
+/* 1 ROW * 14 COLS * 4B (RGBX) = 56 + header prefix. */
+#define MAX_PAYLOAD_SIZE 64
+
+/** Enum of the states used for the serial protocol finite-state automaton */
+enum protoState {
+ /* 2-byte initial start-of-message sync */
+ STATE_SYNC_1,
+ STATE_SYNC_2,
+ /* Waiting for command byte */
+ STATE_CMD,
+ /* Waiting for ID byte */
+ STATE_ID,
+ /* Waiting for payload size */
+ STATE_PAYLOAD_SIZE,
+ /* Reading payload until payloadPosition == payloadSize */
+ STATE_PAYLOAD,
+};
+
+/* Buffer holding a single message */
+typedef struct {
+ uint8_t command;
+ uint8_t msgId;
+ uint8_t payloadSize;
+ uint8_t payload[MAX_PAYLOAD_SIZE];
+} message_t;
+
+/* Internal protocol state */
+typedef struct {
+ /* Callback to call upon receiving a valid message */
+ void (*callback)(const message_t *);
+
+ /* Number of read payload bytes */
+ uint8_t payloadPosition;
+
+ /* Current finite-state-automata state */
+ enum protoState state;
+
+ uint8_t previousId;
+ uint8_t errors;
+
+ /* Currently received message */
+ message_t buffer;
+} protocol_t;
+
+/* NOTE: This didn't work when defined on stack */
+extern protocol_t proto;
+
+/* Init state */
+extern void protoInit(protocol_t *proto, void (*callback)(const message_t *));
+
+/* Consume one byte and push state forward - might call the callback */
+extern void protoConsume(protocol_t *proto, uint8_t byte);
+
+/* Prolonged silence - reset state */
+extern void protoSilence(protocol_t *proto);
+
+/* Transmit message */
+extern void protoTx(uint8_t cmd, const unsigned char *buf, int payloadSize, int retries);
diff --git a/keyboards/annepro2/readme.md b/keyboards/annepro2/readme.md
new file mode 100644
index 0000000000..e3e0b95be4
--- /dev/null
+++ b/keyboards/annepro2/readme.md
@@ -0,0 +1,50 @@
+# Anne Pro 2 rev. C15 and C18 QMK firmware
+
+## Introduction
+
+This is the QMK firmware repository for the Anne Pro 2 rev. C15 and C18 keyboard.
+
+## Layouts
+
+Keyboard has 60% ANSI standard layout.
+
+## How to compile
+
+After setting up your build environment, you can compile the Anne Pro 2 C18 default keymap by using:
+
+ make annepro2/c18:default
+
+If you want to compile the Anne Pro 2 C15 default keymap use:
+
+ make annepro2/c15:default
+
+## Installing
+
+### Get AnnePro2 Tools
+
+If you want the executable instead of compiling it yourself, [download it here](https://ci.codetector.org/job/OpenAnnePro/job/AnnePro2-Tools/job/master/).
+Windows and Linux versions are available. Otherwise, follow the steps below:
+
+0. Install the latest stable `rust` toolchain using [rustup](https://rustup.rs/)
+0. Also install [Visual Studio Community edition](https://visualstudio.microsoft.com/downloads/)
+including the C/C++ module to prevent errors while compiling
+0. Download or Clone the [AnnePro2-Tools](https://github.com/OpenAnnePro/AnnePro2-Tools) project.
+0. Compile the tool using
+```bash
+cargo build --release
+```
+0. The compiled tool should be in `./target/release/annepro2_tools` (In later I will refer to this as `annepro2_tools`)
+
+### Flashing the firmware
+0. Put the keyboard into DFU/IAP mode by unplugging the keyboard, then holding ESC while plugging it back in.
+0. Run annepro2_tools with the firmware you just built.
+
+**Please substitute with the correct paths and correct bin file if you chose another keymap profile**
+```bash
+annepro2_tools annepro2_c15_default.bin
+```
+
+If the tool can't find the keyboard please double check you have the keyboard in IAP mode.
+
+
+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).
\ No newline at end of file