diff --git a/drivers/chibios/spi_master.c b/drivers/chibios/spi_master.c
index 552ac663c1e9..d7e3c4561d69 100644
--- a/drivers/chibios/spi_master.c
+++ b/drivers/chibios/spi_master.c
@@ -32,6 +32,10 @@ __attribute__((weak)) void spi_init(void) {
palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
+#elif defined(HT32_SPI_USE_SPI1) || defined(HT32_SPI_USE_SPI2)
+ palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_HT32_MODE_AF(SPI_SCK_PAL_MODE) | PAL_MODE_OUTPUT_PUSHPULL);
+ palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_HT32_MODE_AF(SPI_MOSI_PAL_MODE) | PAL_MODE_OUTPUT_PUSHPULL);
+ palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_HT32_MODE_AF(SPI_MISO_PAL_MODE) | PAL_MODE_OUTPUT_PUSHPULL);
#else
palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
@@ -53,12 +57,36 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
return false;
}
+#if defined(HT32_SPI_USE_SPI1) || defined(HT32_SPI_USE_SPI2)
+ spiConfig.cr0 = SPI_CR0_SELOEN;
+ spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
+
+ if (lsbFirst) {
+ spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
+ }
+
+ switch (mode) {
+ case 0:
+ spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
+ break;
+ case 1:
+ spiConfig.cr1 |= SPI_CR1_FORMAT_MODE1;
+ break;
+ case 2:
+ spiConfig.cr1 |= SPI_CR1_FORMAT_MODE2;
+ break;
+ case 3:
+ spiConfig.cr1 |= SPI_CR1_FORMAT_MODE3;
+ break;
+ }
+
+ spiConfig.cpr = (roundedDivisor - 1) >> 1;
+#else
spiConfig.cr1 = 0;
if (lsbFirst) {
spiConfig.cr1 |= SPI_CR1_LSBFIRST;
}
-
switch (mode) {
case 0:
break;
@@ -98,6 +126,7 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0;
break;
}
+#endif
currentSlavePin = slavePin;
spiConfig.ssport = PAL_PORT(slavePin);
diff --git a/keyboards/annepro2/annepro2.c b/keyboards/annepro2/annepro2.c
index fd180695916b..a6bcf423bf37 100644
--- a/keyboards/annepro2/annepro2.c
+++ b/keyboards/annepro2/annepro2.c
@@ -2,6 +2,7 @@
#include "hal.h"
#include "annepro2.h"
#include "annepro2_ble.h"
+#include "spi_master.h"
#include "qmk_ap2_led.h"
static const SerialConfig ledUartConfig = {
@@ -26,6 +27,9 @@ uint16_t annepro2LedMatrix[MATRIX_ROWS * MATRIX_COLS] = {
};
void OVERRIDE keyboard_pre_init_kb(void) {
+#if HAL_USE_SPI == TRUE
+ spi_init();
+#endif
}
void OVERRIDE keyboard_post_init_kb(void) {
@@ -33,10 +37,21 @@ void OVERRIDE keyboard_post_init_kb(void) {
sdStart(&SD0, &ledUartConfig);
sdWrite(&SD0, ledMcuWakeup, 11);
+ // wait to receive response from wakeup
+ wait_ms(15);
+
+ // loop to clear out receive buffer from shine wakeup
+ while(!sdGetWouldBlock(&SD0))
+ sdGet(&SD0);
+
// 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(5);
+
keyboard_post_init_user();
}
@@ -77,20 +92,21 @@ bool OVERRIDE process_record_kb(uint16_t keycode, keyrecord_t *record) {
case KC_AP_LED_OFF:
annepro2LedPrevProfile();
annepro2LedDisable();
- return false;
+ break;
case KC_AP_LED_ON:
annepro2LedNextProfile();
annepro2LedEnable();
- return false;
+ break;
case KC_AP_LED_NEXT_PROFILE:
annepro2LedNextProfile();
- return false;
+ break;
case KC_AP_LED_PREV_PROFILE:
annepro2LedPrevProfile();
- return false;
+ break;
+
default:
break;
diff --git a/keyboards/annepro2/c18/config.h b/keyboards/annepro2/c18/config.h
index ad6333889220..96b8c1f3e085 100644
--- a/keyboards/annepro2/c18/config.h
+++ b/keyboards/annepro2/c18/config.h
@@ -60,6 +60,31 @@
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
#define DEBOUNCE 5
+#if defined(ANNEPRO2_EEPROM)
+// SPI Config
+#define SPI_DRIVER SPID1
+#define SPI_SCK_PIN A0
+#define SPI_SCK_PAL_MODE 5
+#define SPI_MOSI_PIN A1
+#define SPI_MOSI_PAL_MODE 5
+#define SPI_MISO_PIN A2
+#define SPI_MISO_PAL_MODE 5
+// EEPROM Config for W25X20CL
+#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN A3
+#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 16
+#define EXTERNAL_EEPROM_BYTE_COUNT 1024 // 262144
+#define EXTERNAL_EEPROM_PAGE_SIZE 256
+#define EXTERNAL_EEPROM_ADDRESS_SIZE 3
+#define EXTERNAL_EEPROM_SPI_LSBFIRST false
+#define EXTERNAL_EEPROM_SPI_MODE 3
+// HAL Config
+#define HAL_USE_SPI TRUE
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
+// MCU Config
+#define HT32_SPI_USE_SPI1 TRUE
+#define HT32_SPI1_IRQ_PRIORITY 9
+#endif
+
/* number of backlight levels */
// #define BACKLIGHT_LEVELS 10
diff --git a/keyboards/annepro2/c18/rules.mk b/keyboards/annepro2/c18/rules.mk
index e042ff844a55..11efab064870 100644
--- a/keyboards/annepro2/c18/rules.mk
+++ b/keyboards/annepro2/c18/rules.mk
@@ -5,6 +5,11 @@ SRC = \
annepro2_ble.c \
qmk_ap2_led.c
+ifeq ($(strip $(ANNEPRO2_EEPROM)), yes)
+ OPT_DEFS += -DANNEPRO2_EEPROM
+ SRC += spi_master.c eeprom_w25x20cl.c
+endif
+
LAYOUTS +=
# MCU
diff --git a/keyboards/annepro2/eeprom_w25x20cl.c b/keyboards/annepro2/eeprom_w25x20cl.c
new file mode 100644
index 000000000000..6f96e650fcbd
--- /dev/null
+++ b/keyboards/annepro2/eeprom_w25x20cl.c
@@ -0,0 +1,203 @@
+/* Copyright 2020 Nick Brassel (tzarc) and tech2077
+ *
+ * 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
+
+/*
+ Note that the implementations of eeprom_XXXX_YYYY on AVR are normally
+ provided by avr-libc. The same functions are reimplemented below and are
+ rerouted to the external SPI equivalent.
+
+ Seemingly, as this is compiled from within QMK, the object file generated
+ during the build overrides the avr-libc implementation during the linking
+ stage.
+
+ On other platforms such as ARM, there are no provided implementations, so
+ there is nothing to override during linkage.
+*/
+
+#include "wait.h"
+#include "spi_master.h"
+#include "eeprom.h"
+#include "eeprom_w25x20cl.h"
+
+#define CMD_WREN 0x06u
+#define CMD_WRDI 0x04u
+#define CMD_RDSR 0x05u
+#define CMD_WRSR 0x01u
+#define CMD_READ 0x03u
+#define CMD_WRITE 0x02u
+#define CMD_SECTOR_ERASE 0x20u
+
+#define SR_WIP 0x01u
+
+// #define DEBUG_EEPROM_OUTPUT
+
+#ifndef EXTERNAL_EEPROM_SPI_TIMEOUT
+# define EXTERNAL_EEPROM_SPI_TIMEOUT 100
+#endif
+
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
+# include "timer.h"
+# include "debug.h"
+#endif // CONSOLE_ENABLE
+
+bool spi_eeprom_start(void) {
+ return spi_start(EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN, EXTERNAL_EEPROM_SPI_LSBFIRST, EXTERNAL_EEPROM_SPI_MODE, EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR);
+}
+
+static spi_status_t spi_eeprom_wait_while_busy(int timeout) {
+ uint32_t deadline = timer_read32() + timeout;
+ spi_status_t response;
+ spi_write(CMD_RDSR);
+ do {
+ response = spi_read();
+ if (timer_read32() >= deadline) {
+ return SPI_STATUS_TIMEOUT;
+ }
+ } while ((uint16_t)response & SR_WIP);
+ return SPI_STATUS_SUCCESS;
+}
+//----------------------------------------------------------------------------------------------------------------------
+
+void eeprom_erase(uint32_t addr) {
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
+ uint32_t start = timer_read32();
+#endif
+
+ spi_eeprom_start();
+ spi_write(CMD_WREN);
+ spi_stop();
+
+ spi_eeprom_start();
+ spi_write(CMD_SECTOR_ERASE);
+ spi_write((uint8_t)((addr & 0xFF0000u) >> 16u));
+ spi_write((uint8_t)((addr & 0x00FF00u) >> 8u));
+ spi_write((uint8_t)((addr & 0x0000FFu)));
+ spi_stop();
+
+ spi_eeprom_start();
+ spi_status_t response = spi_eeprom_wait_while_busy(10000);
+ spi_stop();
+ if (response == SPI_STATUS_TIMEOUT) {
+ dprint("SPI timeout for WIP check\n");
+ return;
+ }
+
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
+ dprintf("EEPROM erase took %ldms to complete\n", ((long)(timer_read32() - start)));
+#endif
+}
+
+void eeprom_read(void *buf, uint32_t addr, size_t len) {
+ //-------------------------------------------------
+ // Wait for the write-in-progress bit to be cleared
+ bool res = spi_eeprom_start();
+ if (!res) {
+ dprint("failed to start SPI for WIP check\n");
+ spi_stop();
+ return;
+ }
+
+ spi_status_t response = spi_eeprom_wait_while_busy(EXTERNAL_EEPROM_SPI_TIMEOUT);
+ spi_stop();
+ if (response == SPI_STATUS_TIMEOUT) {
+ dprint("SPI timeout for WIP check\n");
+ spi_stop();
+ return;
+ }
+
+ //-------------------------------------------------
+ // Perform read
+ res = spi_eeprom_start();
+ if (!res) {
+ dprint("failed to start SPI for read\n");
+ spi_stop();
+ return;
+ }
+
+ spi_write(CMD_READ);
+ spi_write((uint8_t)((addr & 0xFF0000u) >> 16u));
+ spi_write((uint8_t)((addr & 0x00FF00u) >> 8u));
+ spi_write((uint8_t)((addr & 0x0000FFu)));
+ spi_receive(buf, len);
+ spi_stop();
+
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
+ dprintf("[EEPROM R] 0x%08lX: ", (addr));
+ for (size_t i = 0; i < len; ++i) {
+ dprintf(" %02X", (int)(((uint8_t *)buf)[i]));
+ }
+ dprintf("\n");
+#endif // DEBUG_EEPROM_OUTPUT
+
+}
+
+void eeprom_write(const void *buf, uint32_t addr, size_t len) {
+ eeprom_erase(addr);
+
+ //-------------------------------------------------
+ // Enable writes
+ bool res = spi_eeprom_start();
+ if (!res) {
+ dprint("failed to start SPI for write-enable\n");
+ spi_stop();
+ return;
+ }
+
+ spi_write(CMD_WREN);
+ spi_stop();
+
+ wait_us(1);
+
+ //-------------------------------------------------
+ // Perform the write
+ res = spi_eeprom_start();
+ if (!res) {
+ dprint("failed to start SPI for write\n");
+ spi_stop();
+ return;
+ }
+
+#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
+ dprintf("[EEPROM W] 0x%08lX: ", ((uint32_t)(uintptr_t)addr));
+ for (size_t i = 0; i < len; i++) {
+ dprintf(" %02X", (int)(uint8_t)(buf[i]));
+ }
+ dprintf("\n");
+#endif // DEBUG_EEPROM_OUTPUT
+
+ spi_write(CMD_WRITE);
+ spi_write((uint8_t)((addr & 0xFF0000u) >> 16u));
+ spi_write((uint8_t)((addr & 0x00FF00u) >> 8u));
+ spi_write((uint8_t)((addr & 0x0000FFu)));
+ spi_transmit(buf, len);
+ spi_stop();
+
+ res = spi_eeprom_start();
+ if (!res) {
+ dprint("failed to start SPI for status\n");
+ spi_stop();
+ return;
+ }
+ spi_status_t response = spi_eeprom_wait_while_busy(EXTERNAL_EEPROM_SPI_TIMEOUT);
+ spi_stop();
+ if (response == SPI_STATUS_TIMEOUT) {
+ dprint("SPI timeout for WIP check\n");
+ return;
+ }
+}
diff --git a/keyboards/annepro2/eeprom_w25x20cl.h b/keyboards/annepro2/eeprom_w25x20cl.h
new file mode 100644
index 000000000000..17021daded64
--- /dev/null
+++ b/keyboards/annepro2/eeprom_w25x20cl.h
@@ -0,0 +1,84 @@
+/* Copyright 2020 Nick Brassel (tzarc) and tech2077
+ *
+ * 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
+
+void eeprom_erase(uint32_t addr);
+void eeprom_read(void *buf, uint32_t addr, size_t len);
+void eeprom_write(const void *buf, uint32_t addr, size_t len);
+
+/*
+ The slave select pin of the EEPROM.
+ This needs to be a normal GPIO pin_t value, such as A7.
+*/
+#ifndef EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN
+# error "No chip select pin defined -- missing EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN"
+#endif
+
+/*
+ The clock divisor for SPI to ensure that the MCU is within the
+ specifications of the EEPROM chip. Generally this will be PCLK divided by
+ the intended divisor -- check your clock settings and the datasheet of
+ your EEPROM.
+*/
+#ifndef EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR
+# ifdef __AVR__
+# define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 8
+# else
+# define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 64
+# endif
+#endif
+
+/*
+ The SPI mode to communicate with the EEPROM.
+*/
+#ifndef EXTERNAL_EEPROM_SPI_MODE
+# define EXTERNAL_EEPROM_SPI_MODE 0
+#endif
+
+/*
+ Whether or not the SPI communication between the MCU and EEPROM should be
+ LSB-first.
+*/
+#ifndef EXTERNAL_EEPROM_SPI_LSBFIRST
+# define EXTERNAL_EEPROM_SPI_LSBFIRST false
+#endif
+
+/*
+ The total size of the EEPROM, in bytes. The EEPROM datasheet will usually
+ specify this value in kbits, and will require conversion to bytes.
+*/
+#ifndef EXTERNAL_EEPROM_BYTE_COUNT
+# define EXTERNAL_EEPROM_BYTE_COUNT 8192
+#endif
+
+/*
+ The page size in bytes of the EEPROM, as specified in the datasheet.
+*/
+#ifndef EXTERNAL_EEPROM_PAGE_SIZE
+# define EXTERNAL_EEPROM_PAGE_SIZE 32
+#endif
+
+/*
+ The address size in bytes of the EEPROM. For EEPROMs with <=256 bytes, this
+ will likely be 1. For EEPROMs >256 and <=65536, this will be 2. For EEPROMs
+ >65536, this will likely need to be 4.
+
+ As expected, consult the datasheet for specifics of your EEPROM.
+*/
+#ifndef EXTERNAL_EEPROM_ADDRESS_SIZE
+# define EXTERNAL_EEPROM_ADDRESS_SIZE 2
+#endif
\ No newline at end of file
diff --git a/keyboards/annepro2/keymaps/tech2077/keymap.c b/keyboards/annepro2/keymaps/tech2077/keymap.c
new file mode 100644
index 000000000000..a3f238dbd01f
--- /dev/null
+++ b/keyboards/annepro2/keymaps/tech2077/keymap.c
@@ -0,0 +1,206 @@
+#include "annepro2.h"
+#include
+#include
+#include
+#include "qmk_ap2_led.h"
+#include "eeprom_w25x20cl.h"
+
+// layout using eeprom and bidir-comms to keep user led settings persistent
+
+// eeprom memory layout
+typedef union {
+ uint32_t raw;
+ struct {
+ uint8_t magic : 8;
+ bool leds_on : 1;
+ uint8_t leds_profile : 8;
+ };
+} user_config_t;
+
+// define out default user_config
+user_config_t user_config = {.magic = 0xDE, .leds_on = 0, .leds_profile = 0};
+
+// keep the number of profiles so we can track along with the shine proc
+uint8_t numProfiles = 0;
+
+static uint8_t usb_buf[256];
+static uint8_t buf_fil = 0;
+
+enum anne_pro_layers {
+ _BASE_LAYER,
+ _FN1_LAYER,
+ _FN2_LAYER,
+};
+
+/*
+* 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 | GUI | Alt | space | GUI | ALT | FN1 | Ctrl |
+* \-----------------------------------------------------------------------------------------/
+* Layer TAP in _BASE_LAYER
+* ,-----------------------------------------------------------------------------------------.
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | | |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | | | | | | | UP |
+* |-----------------------------------------------------------------------------------------+
+* | | | | | | LEFT | DOWN | RIGHT |
+* \-----------------------------------------------------------------------------------------/
+*/
+const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_BASE_LAYER] = KEYMAP(/* 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,
+ 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_LALT, KC_LGUI, KC_SPC, KC_RGUI, LT(KC_RALT, KC_LEFT), LT(_FN1_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 | FN2 | FN1 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN1_LAYER] = KEYMAP(/* 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,
+ MO(_FN2_LAYER), 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, MO(_FN2_LAYER), KC_TRNS, 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 | FN2 | FN1 | Ctrl |
+ * \-----------------------------------------------------------------------------------------/
+ *
+ */
+ [_FN2_LAYER] = KEYMAP(/* 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_PROFILE, KC_TRNS, 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(_FN2_LAYER), MO(_FN1_LAYER), KC_TRNS),
+};
+const uint16_t keymaps_size = sizeof(keymaps);
+
+void matrix_init_user(void)
+{
+}
+
+void matrix_scan_user(void)
+{
+}
+
+layer_state_t layer_state_set_user(layer_state_t layer)
+{
+ return layer;
+}
+
+void raw_hid_receive(uint8_t *data, uint8_t length) {
+ uprintf("raw_hid len: %u\n", length);
+ if (length == 1)
+ annepro2LedSetProfile(data[0]);
+ else {
+ for (uint8_t i = 0; i < length; i++){
+ usb_buf[buf_fil + i] = data[i];
+ }
+ buf_fil += length;
+ if (buf_fil >= 211) {
+ sdWrite(&SD0, usb_buf, 211);
+ buf_fil = 0;
+ }
+// for (int i = 0; i < length; i++) {
+// sdPut(&SD0, data[i]);
+// sdGet(&SD0);
+// }
+ }
+}
+
+/*!
+ * @returns false processing for this keycode has been completed.
+ */
+bool process_record_user(uint16_t keycode, keyrecord_t* record)
+{
+ switch (keycode) {
+ case KC_AP_LED_OFF:
+ if (record->event.pressed) {
+ user_config.leds_on = false;
+ eeprom_write((void*)&user_config, 0, sizeof(user_config_t));
+ }
+ return false;
+ case KC_AP_LED_ON:
+ if (record->event.pressed) {
+ user_config.leds_on = true;
+ eeprom_write((void*)&user_config, 0, sizeof(user_config_t));
+ }
+ return false;
+ case KC_AP_LED_NEXT_PROFILE:
+ if (record->event.pressed) {
+ user_config.leds_profile = (user_config.leds_profile + 1) % numProfiles;
+ annepro2LedSetProfile(user_config.leds_profile);
+ eeprom_write((void*)&user_config, 0, sizeof(user_config_t));
+ }
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+void keyboard_post_init_user(void)
+{
+ // Customize these values to desired behavior
+ debug_enable = true;
+ //debug_matrix = true;
+ //debug_keyboard=true;
+ //debug_mouse=true;
+
+ // Read the user config from EEPROM
+ eeprom_read((void*)&user_config, 0, sizeof(user_config_t));
+
+ // initialize a new eeprom
+ if (user_config.magic != 0xDE)
+ {
+ user_config.magic = 0xDE;
+ user_config.leds_on = false;
+ user_config.leds_profile = 0;
+ eeprom_write((void*)&user_config, 0, sizeof(user_config_t));
+ }
+
+ numProfiles = annepro2LedGetNumProfiles();
+
+ if (user_config.leds_on) {
+ // send profile before so that we don't get a flicker on startup
+ annepro2LedSetProfile(user_config.leds_profile);
+ annepro2LedEnable();
+ } else {
+ annepro2LedDisable();
+ }
+}
\ No newline at end of file
diff --git a/keyboards/annepro2/keymaps/tech2077/rules.mk b/keyboards/annepro2/keymaps/tech2077/rules.mk
new file mode 100644
index 000000000000..59a7f53b85cf
--- /dev/null
+++ b/keyboards/annepro2/keymaps/tech2077/rules.mk
@@ -0,0 +1,47 @@
+# Anne Pro 2
+SRC = \
+ matrix.c \
+ hardfault_handler.c \
+ annepro2_ble.c \
+ qmk_ap2_led.c
+
+LAYOUTS +=
+
+# MCU
+MCU = cortex-m0plus
+ARMV = 6
+USE_FPU = no
+MCU_FAMILY = HT32
+MCU_SERIES = HT32F523x2
+MCU_LDSCRIPT = HT32F52342_ANNEPRO2
+MCU_STARTUP = ht32f523x2
+
+BOARD = ANNEPRO2_C18
+
+OPT_DEFS = -Wno-unused-function -fdump-rtl-dfinish -fstack-usage
+#EXTRALDFLAGS = -Wl,--print-memory-usage
+
+# Options
+
+# Keys
+CUSTOM_MATRIX = yes
+NKRO_ENABLE = no
+MOUSEKEY_ENABLE = no
+EXTRAKEY_ENABLE = yes
+KEY_LOCK_ENABLE = no
+
+# Other featues
+BOOTMAGIC_ENABLE = no
+CONSOLE_ENABLE = yes
+COMMAND_ENABLE = yes
+DEBUG_EEPROM = yes
+RAW_ENABLE = no
+MIDI_ENABLE = no
+VIRTSER_ENABLE = no
+COMBO_ENABLE = no
+ANNEPRO2_EEPROM = yes
+
+ifeq ($(strip $(ANNEPRO2_EEPROM)), yes)
+ OPT_DEFS += -DANNEPRO2_EEPROM
+ SRC += spi_master.c eeprom_w25x20cl.c
+endif
\ No newline at end of file