diff options
Diffstat (limited to 'tmk_core/common')
29 files changed, 1786 insertions, 100 deletions
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index f7c039f45..b99c2acaa 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -120,7 +120,7 @@ void process_hand_swap(keyevent_t *event) { } #endif -#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) bool disable_action_cache = false; void process_record_nocache(keyrecord_t *record) @@ -773,6 +773,13 @@ void register_code(uint8_t code) else if IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); } + + #ifdef MOUSEKEY_ENABLE + else if IS_MOUSEKEY(code) { + mousekey_on(code); + mousekey_send(); + } + #endif } /** \brief Utilities for actions. (FIXME: Needs better description) @@ -832,6 +839,24 @@ void unregister_code(uint8_t code) else if IS_CONSUMER(code) { host_consumer_send(0); } + #ifdef MOUSEKEY_ENABLE + else if IS_MOUSEKEY(code) { + mousekey_off(code); + mousekey_send(); + } + #endif +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void tap_code(uint8_t code) { + register_code(code); + #if TAP_CODE_DELAY > 0 + wait_ms(TAP_CODE_DELAY); + #endif + unregister_code(code); } /** \brief Utilities for actions. (FIXME: Needs better description) @@ -874,9 +899,18 @@ void clear_keyboard(void) */ void clear_keyboard_but_mods(void) { + clear_keys(); + clear_keyboard_but_mods_and_keys(); +} + +/** \brief Utilities for actions. (FIXME: Needs better description) + * + * FIXME: Needs documentation. + */ +void clear_keyboard_but_mods_and_keys() +{ clear_weak_mods(); clear_macro_mods(); - clear_keys(); send_keyboard_report(); #ifdef MOUSEKEY_ENABLE mousekey_clear(); diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h index acc55c7d3..8e47e5339 100644 --- a/tmk_core/common/action.h +++ b/tmk_core/common/action.h @@ -62,7 +62,7 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); bool process_record_quantum(keyrecord_t *record); /* Utilities for actions. */ -#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) extern bool disable_action_cache; #endif @@ -88,11 +88,13 @@ void process_record(keyrecord_t *record); void process_action(keyrecord_t *record, action_t action); void register_code(uint8_t code); void unregister_code(uint8_t code); +void tap_code(uint8_t code); void register_mods(uint8_t mods); void unregister_mods(uint8_t mods); //void set_mods(uint8_t mods); void clear_keyboard(void); void clear_keyboard_but_mods(void); +void clear_keyboard_but_mods_and_keys(void); void layer_switch(uint8_t new_layer); bool is_tap_key(keypos_t key); diff --git a/tmk_core/common/action_layer.c b/tmk_core/common/action_layer.c index f3cd381ab..120ce3f51 100644 --- a/tmk_core/common/action_layer.c +++ b/tmk_core/common/action_layer.c @@ -15,13 +15,22 @@ */ uint32_t default_layer_state = 0; +/** \brief Default Layer State Set At user Level + * + * FIXME: Needs docs + */ +__attribute__((weak)) +uint32_t default_layer_state_set_user(uint32_t state) { + return state; +} + /** \brief Default Layer State Set At Keyboard Level * * FIXME: Needs docs */ __attribute__((weak)) uint32_t default_layer_state_set_kb(uint32_t state) { - return state; + return default_layer_state_set_user(state); } /** \brief Default Layer State Set @@ -35,7 +44,11 @@ static void default_layer_state_set(uint32_t state) default_layer_debug(); debug(" to "); default_layer_state = state; default_layer_debug(); debug("\n"); +#ifdef STRICT_LAYER_RELEASE clear_keyboard_but_mods(); // To avoid stuck keys +#else + clear_keyboard_but_mods_and_keys(); // Don't reset held keys +#endif } /** \brief Default Layer Print @@ -118,7 +131,11 @@ void layer_state_set(uint32_t state) layer_debug(); dprint(" to "); layer_state = state; layer_debug(); dprintln(); +#ifdef STRICT_LAYER_RELEASE clear_keyboard_but_mods(); // To avoid stuck keys +#else + clear_keyboard_but_mods_and_keys(); // Don't reset held keys +#endif } /** \brief Layer clear @@ -219,7 +236,7 @@ void layer_debug(void) } #endif -#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}}; void update_source_layers_cache(keypos_t key, uint8_t layer) @@ -263,7 +280,7 @@ uint8_t read_source_layers_cache(keypos_t key) */ action_t store_or_get_action(bool pressed, keypos_t key) { -#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) if (disable_action_cache) { return layer_switch_get_action(key); } diff --git a/tmk_core/common/action_layer.h b/tmk_core/common/action_layer.h index 72a6bd8f6..f1551d251 100644 --- a/tmk_core/common/action_layer.h +++ b/tmk_core/common/action_layer.h @@ -31,6 +31,8 @@ void default_layer_set(uint32_t state); __attribute__((weak)) uint32_t default_layer_state_set_kb(uint32_t state); +__attribute__((weak)) +uint32_t default_layer_state_set_user(uint32_t state); #ifndef NO_ACTION_LAYER /* bitwise operation */ @@ -80,15 +82,13 @@ void layer_xor(uint32_t state); #define layer_or(state) #define layer_and(state) #define layer_xor(state) +#endif -__attribute__((weak)) uint32_t layer_state_set_user(uint32_t state); -__attribute__((weak)) uint32_t layer_state_set_kb(uint32_t state); -#endif /* pressed actions cache */ -#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE) /* The number of bits needed to represent the layer number: log2(32). */ #define MAX_LAYER_BITS 5 void update_source_layers_cache(keypos_t key, uint8_t layer); diff --git a/tmk_core/common/arm_atsam/bootloader.c b/tmk_core/common/arm_atsam/bootloader.c new file mode 100644 index 000000000..ba71bfeb0 --- /dev/null +++ b/tmk_core/common/arm_atsam/bootloader.c @@ -0,0 +1,51 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "bootloader.h" +#include "samd51j18a.h" +#include "md_bootloader.h" + +//Set watchdog timer to reset. Directs the bootloader to stay in programming mode. +void bootloader_jump(void) { +#ifdef KEYBOARD_massdrop_ctrl + //CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method. + uint8_t ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; //The version to match (NULL terminated by compiler) + uint8_t *ver_check = ver_ram_method; //Pointer to version match string for traversal + uint8_t *ver_rom = (uint8_t *)0x21A0; //Pointer to address in ROM where this specific bootloader version would exist + + while (*ver_check && *ver_rom == *ver_check) { //While there are check version characters to match and bootloader's version matches check's version + ver_check++; //Move check version pointer to next character + ver_rom++; //Move ROM version pointer to next character + } + + if (!*ver_check) { //If check version pointer is NULL, all characters have matched + *MAGIC_ADDR = BOOTLOADER_MAGIC; //Set magic number into RAM + NVIC_SystemReset(); //Perform system reset + while (1) {} //Won't get here + } +#endif + + WDT->CTRLA.bit.ENABLE = 0; + while (WDT->SYNCBUSY.bit.ENABLE) {} + while (WDT->CTRLA.bit.ENABLE) {} + WDT->CONFIG.bit.WINDOW = 0; + WDT->CONFIG.bit.PER = 0; + WDT->EWCTRL.bit.EWOFFSET = 0; + WDT->CTRLA.bit.ENABLE = 1; + while (WDT->SYNCBUSY.bit.ENABLE) {} + while (!WDT->CTRLA.bit.ENABLE) {} + while (1) {} //Wait on timeout +} diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c new file mode 100644 index 000000000..61cc039ef --- /dev/null +++ b/tmk_core/common/arm_atsam/eeprom.c @@ -0,0 +1,98 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "eeprom.h" + +#define EEPROM_SIZE 32 + +static uint8_t buffer[EEPROM_SIZE]; + +uint8_t eeprom_read_byte(const uint8_t *addr) { + uintptr_t offset = (uintptr_t)addr; + return buffer[offset]; +} + +void eeprom_write_byte(uint8_t *addr, uint8_t value) { + uintptr_t offset = (uintptr_t)addr; + buffer[offset] = value; +} + +uint16_t eeprom_read_word(const uint16_t *addr) { + const uint8_t *p = (const uint8_t *)addr; + return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8); +} + +uint32_t eeprom_read_dword(const uint32_t *addr) { + const uint8_t *p = (const uint8_t *)addr; + return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8) + | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24); +} + +void eeprom_read_block(void *buf, const void *addr, uint32_t len) { + const uint8_t *p = (const uint8_t *)addr; + uint8_t *dest = (uint8_t *)buf; + while (len--) { + *dest++ = eeprom_read_byte(p++); + } +} + +void eeprom_write_word(uint16_t *addr, uint16_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p, value >> 8); +} + +void eeprom_write_dword(uint32_t *addr, uint32_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p++, value >> 8); + eeprom_write_byte(p++, value >> 16); + eeprom_write_byte(p, value >> 24); +} + +void eeprom_write_block(const void *buf, void *addr, uint32_t len) { + uint8_t *p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} + +void eeprom_update_byte(uint8_t *addr, uint8_t value) { + eeprom_write_byte(addr, value); +} + +void eeprom_update_word(uint16_t *addr, uint16_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p, value >> 8); +} + +void eeprom_update_dword(uint32_t *addr, uint32_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p++, value >> 8); + eeprom_write_byte(p++, value >> 16); + eeprom_write_byte(p, value >> 24); +} + +void eeprom_update_block(const void *buf, void *addr, uint32_t len) { + uint8_t *p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} diff --git a/tmk_core/common/arm_atsam/printf.c b/tmk_core/common/arm_atsam/printf.c new file mode 100644 index 000000000..7f298d1fd --- /dev/null +++ b/tmk_core/common/arm_atsam/printf.c @@ -0,0 +1,66 @@ +/* +Copyright 2018 Massdrop Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef CONSOLE_ENABLE + +#include "samd51j18a.h" +#include "arm_atsam_protocol.h" +#include "printf.h" +#include <string.h> +#include <stdarg.h> + +void console_printf(char *fmt, ...) { + while (udi_hid_con_b_report_trans_ongoing) {} //Wait for any previous transfers to complete + + static char console_printbuf[CONSOLE_PRINTBUF_SIZE]; //Print and send buffer + va_list va; + int result; + + va_start(va, fmt); + result = vsnprintf(console_printbuf, CONSOLE_PRINTBUF_SIZE, fmt, va); + va_end(va); + + uint32_t irqflags; + char *pconbuf = console_printbuf; //Pointer to start send from + int send_out = CONSOLE_EPSIZE; //Bytes to send per transfer + + while (result > 0) { //While not error and bytes remain + while (udi_hid_con_b_report_trans_ongoing) {} //Wait for any previous transfers to complete + + irqflags = __get_PRIMASK(); + __disable_irq(); + __DMB(); + + if (result < CONSOLE_EPSIZE) { //If remaining bytes are less than console epsize + memset(udi_hid_con_report, 0, CONSOLE_EPSIZE); //Clear the buffer + send_out = result; //Send remaining size + } + + memcpy(udi_hid_con_report, pconbuf, send_out); //Copy data into the send buffer + + udi_hid_con_b_report_valid = 1; //Set report valid + udi_hid_con_send_report(); //Send report + + __DMB(); + __set_PRIMASK(irqflags); + + result -= send_out; //Decrement result by bytes sent + pconbuf += send_out; //Increment buffer point by bytes sent + } +} + +#endif //CONSOLE_ENABLE diff --git a/tmk_core/common/arm_atsam/printf.h b/tmk_core/common/arm_atsam/printf.h new file mode 100644 index 000000000..1f1c2280b --- /dev/null +++ b/tmk_core/common/arm_atsam/printf.h @@ -0,0 +1,11 @@ +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#define CONSOLE_PRINTBUF_SIZE 512 + +void console_printf(char *fmt, ...); + +#define __xprintf console_printf + +#endif //_PRINTF_H_ + diff --git a/tmk_core/common/arm_atsam/suspend.c b/tmk_core/common/arm_atsam/suspend.c new file mode 100644 index 000000000..e34965df6 --- /dev/null +++ b/tmk_core/common/arm_atsam/suspend.c @@ -0,0 +1,85 @@ +#include "matrix.h" +#include "i2c_master.h" +#include "led_matrix.h" +#include "suspend.h" + +/** \brief Suspend idle + * + * FIXME: needs doc + */ +void suspend_idle(uint8_t time) { + /* Note: Not used anywhere currently */ +} + +/** \brief Run user level Power down + * + * FIXME: needs doc + */ +__attribute__ ((weak)) +void suspend_power_down_user (void) { + +} + +/** \brief Run keyboard level Power down + * + * FIXME: needs doc + */ +__attribute__ ((weak)) +void suspend_power_down_kb(void) { + suspend_power_down_user(); +} + +/** \brief Suspend power down + * + * FIXME: needs doc + */ +void suspend_power_down(void) +{ + I2C3733_Control_Set(0); //Disable LED driver + + suspend_power_down_kb(); +} + +__attribute__ ((weak)) void matrix_power_up(void) {} +__attribute__ ((weak)) void matrix_power_down(void) {} +bool suspend_wakeup_condition(void) { + matrix_power_up(); + matrix_scan(); + matrix_power_down(); + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { + if (matrix_get_row(r)) return true; + } + return false; +} + +/** \brief run user level code immediately after wakeup + * + * FIXME: needs doc + */ +__attribute__ ((weak)) +void suspend_wakeup_init_user(void) { + +} + +/** \brief run keyboard level code immediately after wakeup + * + * FIXME: needs doc + */ +__attribute__ ((weak)) +void suspend_wakeup_init_kb(void) { + suspend_wakeup_init_user(); +} + +/** \brief run immediately after wakeup + * + * FIXME: needs doc + */ +void suspend_wakeup_init(void) { + /* If LEDs are set to enabled, enable the hardware */ + if (led_enabled) { + I2C3733_Control_Set(1); + } + + suspend_wakeup_init_kb(); +} + diff --git a/tmk_core/common/arm_atsam/timer.c b/tmk_core/common/arm_atsam/timer.c new file mode 100644 index 000000000..bcfe5002c --- /dev/null +++ b/tmk_core/common/arm_atsam/timer.c @@ -0,0 +1,59 @@ +#include "samd51j18a.h" +#include "timer.h" +#include "tmk_core/protocol/arm_atsam/clks.h" + +void set_time(uint64_t tset) +{ + ms_clk = tset; +} + +void timer_init(void) +{ + ms_clk = 0; +} + +uint16_t timer_read(void) +{ + return (uint16_t)ms_clk; +} + +uint32_t timer_read32(void) +{ + return (uint32_t)ms_clk; +} + +uint64_t timer_read64(void) +{ + return ms_clk; +} + +uint16_t timer_elapsed(uint16_t tlast) +{ + return TIMER_DIFF_16(timer_read(), tlast); +} + +uint32_t timer_elapsed32(uint32_t tlast) +{ + return TIMER_DIFF_32(timer_read32(), tlast); +} + +uint32_t timer_elapsed64(uint32_t tlast) +{ + uint64_t tnow = timer_read64(); + return (tnow >= tlast ? tnow - tlast : UINT64_MAX - tlast + tnow); +} + +void timer_clear(void) +{ + ms_clk = 0; +} + +void wait_ms(uint64_t msec) +{ + CLK_delay_ms(msec); +} + +void wait_us(uint16_t usec) +{ + CLK_delay_us(usec); +} diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c index 3d4a48439..5bca64685 100644 --- a/tmk_core/common/avr/suspend.c +++ b/tmk_core/common/avr/suspend.c @@ -10,6 +10,7 @@ #include "timer.h" #include "led.h" #include "host.h" +#include "rgblight_reconfig.h" #ifdef PROTOCOL_LUFA #include "lufa.h" @@ -55,6 +56,24 @@ void suspend_idle(uint8_t time) sleep_disable(); } + +// TODO: This needs some cleanup + +/** \brief Run keyboard level Power down + * + * FIXME: needs doc + */ +__attribute__ ((weak)) +void suspend_power_down_user (void) { } +/** \brief Run keyboard level Power down + * + * FIXME: needs doc + */ +__attribute__ ((weak)) +void suspend_power_down_kb(void) { + suspend_power_down_user(); +} + #ifndef NO_SUSPEND_POWER_DOWN /** \brief Power down MCU with watchdog timer * @@ -72,21 +91,6 @@ void suspend_idle(uint8_t time) */ static uint8_t wdt_timeout = 0; -/** \brief Run keyboard level Power down - * - * FIXME: needs doc - */ -__attribute__ ((weak)) -void suspend_power_down_user (void) { } -/** \brief Run keyboard level Power down - * - * FIXME: needs doc - */ -__attribute__ ((weak)) -void suspend_power_down_kb(void) { - suspend_power_down_user(); -} - /** \brief Power down * * FIXME: needs doc @@ -143,6 +147,8 @@ static void power_down(uint8_t wdto) */ void suspend_power_down(void) { + suspend_power_down_kb(); + #ifndef NO_SUSPEND_POWER_DOWN power_down(WDTO_15MS); #endif @@ -189,12 +195,15 @@ void suspend_wakeup_init(void) #endif led_set(host_keyboard_leds()); #if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) +#ifdef BOOTLOADER_TEENSY + wait_ms(10); +#endif rgblight_enable_noeeprom(); #ifdef RGBLIGHT_ANIMATIONS rgblight_timer_enable(); #endif #endif - suspend_wakeup_init_kb(); + suspend_wakeup_init_kb(); } #ifndef NO_SUSPEND_POWER_DOWN diff --git a/tmk_core/common/backlight.c b/tmk_core/common/backlight.c index 3e29aacc4..8ddacd98b 100644 --- a/tmk_core/common/backlight.c +++ b/tmk_core/common/backlight.c @@ -76,12 +76,51 @@ void backlight_decrease(void) */ void backlight_toggle(void) { - backlight_config.enable ^= 1; - if (backlight_config.raw == 1) // enabled but level = 0 - backlight_config.level = 1; - eeconfig_update_backlight(backlight_config.raw); - dprintf("backlight toggle: %u\n", backlight_config.enable); - backlight_set(backlight_config.enable ? backlight_config.level : 0); + bool enabled = backlight_config.enable; + dprintf("backlight toggle: %u\n", enabled); + if (enabled) + backlight_disable(); + else + backlight_enable(); +} + +/** \brief Enable backlight + * + * FIXME: needs doc + */ +void backlight_enable(void) +{ + if (backlight_config.enable) return; // do nothing if backlight is already on + + backlight_config.enable = true; + if (backlight_config.raw == 1) // enabled but level == 0 + backlight_config.level = 1; + eeconfig_update_backlight(backlight_config.raw); + dprintf("backlight enable\n"); + backlight_set(backlight_config.level); +} + +/** /brief Disable backlight + * + * FIXME: needs doc + */ +void backlight_disable(void) +{ + if (!backlight_config.enable) return; // do nothing if backlight is already off + + backlight_config.enable = false; + eeconfig_update_backlight(backlight_config.raw); + dprintf("backlight disable\n"); + backlight_set(0); +} + +/** /brief Get the backlight status + * + * FIXME: needs doc + */ +bool is_backlight_enabled(void) +{ + return backlight_config.enable; } /** \brief Backlight step through levels diff --git a/tmk_core/common/backlight.h b/tmk_core/common/backlight.h index f57309267..420c9d19e 100644 --- a/tmk_core/common/backlight.h +++ b/tmk_core/common/backlight.h @@ -15,8 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef BACKLIGHT_H -#define BACKLIGHT_H +#pragma once #include <stdint.h> #include <stdbool.h> @@ -33,9 +32,11 @@ void backlight_init(void); void backlight_increase(void); void backlight_decrease(void); void backlight_toggle(void); +void backlight_enable(void); +void backlight_disable(void); +bool is_backlight_enabled(void); void backlight_step(void); void backlight_set(uint8_t level); void backlight_level(uint8_t level); uint8_t get_backlight_level(void); -#endif diff --git a/tmk_core/common/chibios/eeprom_stm32.c b/tmk_core/common/chibios/eeprom_stm32.c new file mode 100755 index 000000000..a86998550 --- /dev/null +++ b/tmk_core/common/chibios/eeprom_stm32.c @@ -0,0 +1,673 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * 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. + * + * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and + * https://github.com/leaflabs/libmaple + * + * Modifications for QMK and STM32F303 by Yiancar + */ + +#include "eeprom_stm32.h" + + FLASH_Status EE_ErasePage(uint32_t); + + uint16_t EE_CheckPage(uint32_t, uint16_t); + uint16_t EE_CheckErasePage(uint32_t, uint16_t); + uint16_t EE_Format(void); + uint32_t EE_FindValidPage(void); + uint16_t EE_GetVariablesCount(uint32_t, uint16_t); + uint16_t EE_PageTransfer(uint32_t, uint32_t, uint16_t); + uint16_t EE_VerifyPageFullWriteVariable(uint16_t, uint16_t); + + uint32_t PageBase0 = EEPROM_PAGE0_BASE; + uint32_t PageBase1 = EEPROM_PAGE1_BASE; + uint32_t PageSize = EEPROM_PAGE_SIZE; + uint16_t Status = EEPROM_NOT_INIT; + +// See http://www.st.com/web/en/resource/technical/document/application_note/CD00165693.pdf + +/** + * @brief Check page for blank + * @param page base address + * @retval Success or error + * EEPROM_BAD_FLASH: page not empty after erase + * EEPROM_OK: page blank + */ +uint16_t EE_CheckPage(uint32_t pageBase, uint16_t status) +{ + uint32_t pageEnd = pageBase + (uint32_t)PageSize; + + // Page Status not EEPROM_ERASED and not a "state" + if ((*(__IO uint16_t*)pageBase) != EEPROM_ERASED && (*(__IO uint16_t*)pageBase) != status) + return EEPROM_BAD_FLASH; + for(pageBase += 4; pageBase < pageEnd; pageBase += 4) + if ((*(__IO uint32_t*)pageBase) != 0xFFFFFFFF) // Verify if slot is empty + return EEPROM_BAD_FLASH; + return EEPROM_OK; +} + +/** + * @brief Erase page with increment erase counter (page + 2) + * @param page base address + * @retval Success or error + * FLASH_COMPLETE: success erase + * - Flash error code: on write Flash error + */ +FLASH_Status EE_ErasePage(uint32_t pageBase) +{ + FLASH_Status FlashStatus; + uint16_t data = (*(__IO uint16_t*)(pageBase)); + if ((data == EEPROM_ERASED) || (data == EEPROM_VALID_PAGE) || (data == EEPROM_RECEIVE_DATA)) + data = (*(__IO uint16_t*)(pageBase + 2)) + 1; + else + data = 0; + + FlashStatus = FLASH_ErasePage(pageBase); + if (FlashStatus == FLASH_COMPLETE) + FlashStatus = FLASH_ProgramHalfWord(pageBase + 2, data); + + return FlashStatus; +} + +/** + * @brief Check page for blank and erase it + * @param page base address + * @retval Success or error + * - Flash error code: on write Flash error + * - EEPROM_BAD_FLASH: page not empty after erase + * - EEPROM_OK: page blank + */ +uint16_t EE_CheckErasePage(uint32_t pageBase, uint16_t status) +{ + uint16_t FlashStatus; + if (EE_CheckPage(pageBase, status) != EEPROM_OK) + { + FlashStatus = EE_ErasePage(pageBase); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + return EE_CheckPage(pageBase, status); + } + return EEPROM_OK; +} + +/** + * @brief Find valid Page for write or read operation + * @param Page0: Page0 base address + * Page1: Page1 base address + * @retval Valid page address (PAGE0 or PAGE1) or NULL in case of no valid page was found + */ +uint32_t EE_FindValidPage(void) +{ + uint16_t status0 = (*(__IO uint16_t*)PageBase0); // Get Page0 actual status + uint16_t status1 = (*(__IO uint16_t*)PageBase1); // Get Page1 actual status + + if (status0 == EEPROM_VALID_PAGE && status1 == EEPROM_ERASED) + return PageBase0; + if (status1 == EEPROM_VALID_PAGE && status0 == EEPROM_ERASED) + return PageBase1; + + return 0; +} + +/** + * @brief Calculate unique variables in EEPROM + * @param start: address of first slot to check (page + 4) + * @param end: page end address + * @param address: 16 bit virtual address of the variable to excluse (or 0XFFFF) + * @retval count of variables + */ +uint16_t EE_GetVariablesCount(uint32_t pageBase, uint16_t skipAddress) +{ + uint16_t varAddress, nextAddress; + uint32_t idx; + uint32_t pageEnd = pageBase + (uint32_t)PageSize; + uint16_t count = 0; + + for (pageBase += 6; pageBase < pageEnd; pageBase += 4) + { + varAddress = (*(__IO uint16_t*)pageBase); + if (varAddress == 0xFFFF || varAddress == skipAddress) + continue; + + count++; + for(idx = pageBase + 4; idx < pageEnd; idx += 4) + { + nextAddress = (*(__IO uint16_t*)idx); + if (nextAddress == varAddress) + { + count--; + break; + } + } + } + return count; +} + +/** + * @brief Transfers last updated variables data from the full Page to an empty one. + * @param newPage: new page base address + * @param oldPage: old page base address + * @param SkipAddress: 16 bit virtual address of the variable (or 0xFFFF) + * @retval Success or error status: + * - FLASH_COMPLETE: on success + * - EEPROM_OUT_SIZE: if valid new page is full + * - Flash error code: on write Flash error + */ +uint16_t EE_PageTransfer(uint32_t newPage, uint32_t oldPage, uint16_t SkipAddress) +{ + uint32_t oldEnd, newEnd; + uint32_t oldIdx, newIdx, idx; + uint16_t address, data, found; + FLASH_Status FlashStatus; + + // Transfer process: transfer variables from old to the new active page + newEnd = newPage + ((uint32_t)PageSize); + + // Find first free element in new page + for (newIdx = newPage + 4; newIdx < newEnd; newIdx += 4) + if ((*(__IO uint32_t*)newIdx) == 0xFFFFFFFF) // Verify if element + break; // contents are 0xFFFFFFFF + if (newIdx >= newEnd) + return EEPROM_OUT_SIZE; + + oldEnd = oldPage + 4; + oldIdx = oldPage + (uint32_t)(PageSize - 2); + + for (; oldIdx > oldEnd; oldIdx -= 4) + { + address = *(__IO uint16_t*)oldIdx; + if (address == 0xFFFF || address == SkipAddress) + continue; // it's means that power off after write data + + found = 0; + for (idx = newPage + 6; idx < newIdx; idx += 4) + if ((*(__IO uint16_t*)(idx)) == address) + { + found = 1; + break; + } + + if (found) + continue; + + if (newIdx < newEnd) + { + data = (*(__IO uint16_t*)(oldIdx - 2)); + + FlashStatus = FLASH_ProgramHalfWord(newIdx, data); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + + FlashStatus = FLASH_ProgramHalfWord(newIdx + 2, address); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + + newIdx += 4; + } + else + return EEPROM_OUT_SIZE; + } + + // Erase the old Page: Set old Page status to EEPROM_EEPROM_ERASED status + data = EE_CheckErasePage(oldPage, EEPROM_ERASED); + if (data != EEPROM_OK) + return data; + + // Set new Page status + FlashStatus = FLASH_ProgramHalfWord(newPage, EEPROM_VALID_PAGE); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + + return EEPROM_OK; +} + +/** + * @brief Verify if active page is full and Writes variable in EEPROM. + * @param Address: 16 bit virtual address of the variable + * @param Data: 16 bit data to be written as variable value + * @retval Success or error status: + * - FLASH_COMPLETE: on success + * - EEPROM_PAGE_FULL: if valid page is full (need page transfer) + * - EEPROM_NO_VALID_PAGE: if no valid page was found + * - EEPROM_OUT_SIZE: if EEPROM size exceeded + * - Flash error code: on write Flash error + */ +uint16_t EE_VerifyPageFullWriteVariable(uint16_t Address, uint16_t Data) +{ + FLASH_Status FlashStatus; + uint32_t idx, pageBase, pageEnd, newPage; + uint16_t count; + + // Get valid Page for write operation + pageBase = EE_FindValidPage(); + if (pageBase == 0) + return EEPROM_NO_VALID_PAGE; + + // Get the valid Page end Address + pageEnd = pageBase + PageSize; // Set end of page + + for (idx = pageEnd - 2; idx > pageBase; idx -= 4) + { + if ((*(__IO uint16_t*)idx) == Address) // Find last value for address + { + count = (*(__IO uint16_t*)(idx - 2)); // Read last data + if (count == Data) + return EEPROM_OK; + if (count == 0xFFFF) + { + FlashStatus = FLASH_ProgramHalfWord(idx - 2, Data); // Set variable data + if (FlashStatus == FLASH_COMPLETE) + return EEPROM_OK; + } + break; + } + } + + // Check each active page address starting from begining + for (idx = pageBase + 4; idx < pageEnd; idx += 4) + if ((*(__IO uint32_t*)idx) == 0xFFFFFFFF) // Verify if element + { // contents are 0xFFFFFFFF + FlashStatus = FLASH_ProgramHalfWord(idx, Data); // Set variable data + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + FlashStatus = FLASH_ProgramHalfWord(idx + 2, Address); // Set variable virtual address + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + return EEPROM_OK; + } + + // Empty slot not found, need page transfer + // Calculate unique variables in page + count = EE_GetVariablesCount(pageBase, Address) + 1; + if (count >= (PageSize / 4 - 1)) + return EEPROM_OUT_SIZE; + + if (pageBase == PageBase1) + newPage = PageBase0; // New page address where variable will be moved to + else + newPage = PageBase1; + + // Set the new Page status to RECEIVE_DATA status + FlashStatus = FLASH_ProgramHalfWord(newPage, EEPROM_RECEIVE_DATA); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + + // Write the variable passed as parameter in the new active page + FlashStatus = FLASH_ProgramHalfWord(newPage + 4, Data); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + + FlashStatus = FLASH_ProgramHalfWord(newPage + 6, Address); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + + return EE_PageTransfer(newPage, pageBase, Address); +} + +/*EEPROMClass::EEPROMClass(void) +{ + PageBase0 = EEPROM_PAGE0_BASE; + PageBase1 = EEPROM_PAGE1_BASE; + PageSize = EEPROM_PAGE_SIZE; + Status = EEPROM_NOT_INIT; +}*/ +/* +uint16_t EEPROM_init(uint32_t pageBase0, uint32_t pageBase1, uint32_t pageSize) +{ + PageBase0 = pageBase0; + PageBase1 = pageBase1; + PageSize = pageSize; + return EEPROM_init(); +}*/ + +uint16_t EEPROM_init(void) +{ + uint16_t status0 = 6, status1 = 6; + FLASH_Status FlashStatus; + + FLASH_Unlock(); + Status = EEPROM_NO_VALID_PAGE; + + status0 = (*(__IO uint16_t *)PageBase0); + status1 = (*(__IO uint16_t *)PageBase1); + + switch (status0) + { +/* + Page0 Page1 + ----- ----- + EEPROM_ERASED EEPROM_VALID_PAGE Page1 valid, Page0 erased + EEPROM_RECEIVE_DATA Page1 need set to valid, Page0 erased + EEPROM_ERASED make EE_Format + any Error: EEPROM_NO_VALID_PAGE +*/ + case EEPROM_ERASED: + if (status1 == EEPROM_VALID_PAGE) // Page0 erased, Page1 valid + Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED); + else if (status1 == EEPROM_RECEIVE_DATA) // Page0 erased, Page1 receive + { + FlashStatus = FLASH_ProgramHalfWord(PageBase1, EEPROM_VALID_PAGE); + if (FlashStatus != FLASH_COMPLETE) + Status = FlashStatus; + else + Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED); + } + else if (status1 == EEPROM_ERASED) // Both in erased state so format EEPROM + Status = EEPROM_format(); + break; +/* + Page0 Page1 + ----- ----- + EEPROM_RECEIVE_DATA EEPROM_VALID_PAGE Transfer Page1 to Page0 + EEPROM_ERASED Page0 need set to valid, Page1 erased + any EEPROM_NO_VALID_PAGE +*/ + case EEPROM_RECEIVE_DATA: + if (status1 == EEPROM_VALID_PAGE) // Page0 receive, Page1 valid + Status = EE_PageTransfer(PageBase0, PageBase1, 0xFFFF); + else if (status1 == EEPROM_ERASED) // Page0 receive, Page1 erased + { + Status = EE_CheckErasePage(PageBase1, EEPROM_ERASED); + if (Status == EEPROM_OK) + { + FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE); + if (FlashStatus != FLASH_COMPLETE) + Status = FlashStatus; + else + Status = EEPROM_OK; + } + } + break; +/* + Page0 Page1 + ----- ----- + EEPROM_VALID_PAGE EEPROM_VALID_PAGE Error: EEPROM_NO_VALID_PAGE + EEPROM_RECEIVE_DATA Transfer Page0 to Page1 + any Page0 valid, Page1 erased +*/ + case EEPROM_VALID_PAGE: + if (status1 == EEPROM_VALID_PAGE) // Both pages valid + Status = EEPROM_NO_VALID_PAGE; + else if (status1 == EEPROM_RECEIVE_DATA) + Status = EE_PageTransfer(PageBase1, PageBase0, 0xFFFF); + else + Status = EE_CheckErasePage(PageBase1, EEPROM_ERASED); + break; +/* + Page0 Page1 + ----- ----- + any EEPROM_VALID_PAGE Page1 valid, Page0 erased + EEPROM_RECEIVE_DATA Page1 valid, Page0 erased + any EEPROM_NO_VALID_PAGE +*/ + default: + if (status1 == EEPROM_VALID_PAGE) + Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED); // Check/Erase Page0 + else if (status1 == EEPROM_RECEIVE_DATA) + { + FlashStatus = FLASH_ProgramHalfWord(PageBase1, EEPROM_VALID_PAGE); + if (FlashStatus != FLASH_COMPLETE) + Status = FlashStatus; + else + Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED); + } + break; + } + return Status; +} + +/** + * @brief Erases PAGE0 and PAGE1 and writes EEPROM_VALID_PAGE / 0 header to PAGE0 + * @param PAGE0 and PAGE1 base addresses + * @retval Status of the last operation (Flash write or erase) done during EEPROM formating + */ +uint16_t EEPROM_format(void) +{ + uint16_t status; + FLASH_Status FlashStatus; + + FLASH_Unlock(); + + // Erase Page0 + status = EE_CheckErasePage(PageBase0, EEPROM_VALID_PAGE); + if (status != EEPROM_OK) + return status; + if ((*(__IO uint16_t*)PageBase0) == EEPROM_ERASED) + { + // Set Page0 as valid page: Write VALID_PAGE at Page0 base address + FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE); + if (FlashStatus != FLASH_COMPLETE) + return FlashStatus; + } + // Erase Page1 + return EE_CheckErasePage(PageBase1, EEPROM_ERASED); +} + +/** + * @brief Returns the erase counter for current page + * @param Data: Global variable contains the read variable value + * @retval Success or error status: + * - EEPROM_OK: if erases counter return. + * - EEPROM_NO_VALID_PAGE: if no valid page was found. + */ +uint16_t EEPROM_erases(uint16_t *Erases) +{ + uint32_t pageBase; + if (Status != EEPROM_OK) + if (EEPROM_init() != EEPROM_OK) + return Status; + + // Get active Page for read operation + pageBase = EE_FindValidPage(); + if (pageBase == 0) + return EEPROM_NO_VALID_PAGE; + + *Erases = (*(__IO uint16_t*)pageBase+2); + return EEPROM_OK; +} + +/** + * @brief Returns the last stored variable data, if found, + * which correspond to the passed virtual address + * @param Address: Variable virtual address + * @retval Data for variable or EEPROM_DEFAULT_DATA, if any errors + */ +/* +uint16_t EEPROM_read (uint16_t Address) +{ + uint16_t data; + EEPROM_read(Address, &data); + return data; +}*/ + +/** + * @brief Returns the last stored variable data, if found, + * which correspond to the passed virtual address + * @param Address: Variable virtual address + * @param Data: Pointer to data variable + * @retval Success or error status: + * - EEPROM_OK: if variable was found + * - EEPROM_BAD_ADDRESS: if the variable was not found + * - EEPROM_NO_VALID_PAGE: if no valid page was found. + */ +uint16_t EEPROM_read(uint16_t Address, uint16_t *Data) +{ + uint32_t pageBase, pageEnd; + + // Set default data (empty EEPROM) + *Data = EEPROM_DEFAULT_DATA; + + if (Status == EEPROM_NOT_INIT) + if (EEPROM_init() != EEPROM_OK) + return Status; + + // Get active Page for read operation + pageBase = EE_FindValidPage(); + if (pageBase == 0) + return EEPROM_NO_VALID_PAGE; + + // Get the valid Page end Address + pageEnd = pageBase + ((uint32_t)(PageSize - 2)); + + // Check each active page address starting from end + for (pageBase += 6; pageEnd >= pageBase; pageEnd -= 4) + if ((*(__IO uint16_t*)pageEnd) == Address) // Compare the read address with the virtual address + { + *Data = (*(__IO uint16_t*)(pageEnd - 2)); // Get content of Address-2 which is variable value + return EEPROM_OK; + } + + // Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) + return EEPROM_BAD_ADDRESS; +} + +/** + * @brief Writes/upadtes variable data in EEPROM. + * @param VirtAddress: Variable virtual address + * @param Data: 16 bit data to be written + * @retval Success or error status: + * - FLASH_COMPLETE: on success + * - EEPROM_BAD_ADDRESS: if address = 0xFFFF + * - EEPROM_PAGE_FULL: if valid page is full + * - EEPROM_NO_VALID_PAGE: if no valid page was found + * - EEPROM_OUT_SIZE: if no empty EEPROM variables + * - Flash error code: on write Flash error + */ +uint16_t EEPROM_write(uint16_t Address, uint16_t Data) +{ + if (Status == EEPROM_NOT_INIT) + if (EEPROM_init() != EEPROM_OK) + return Status; + + if (Address == 0xFFFF) + return EEPROM_BAD_ADDRESS; + + // Write the variable virtual address and value in the EEPROM + uint16_t status = EE_VerifyPageFullWriteVariable(Address, Data); + return status; +} + +/** + * @brief Writes/upadtes variable data in EEPROM. + The value is written only if differs from the one already saved at the same address. + * @param VirtAddress: Variable virtual address + * @param Data: 16 bit data to be written + * @retval Success or error status: + * - EEPROM_SAME_VALUE: If new Data matches existing EEPROM Data + * - FLASH_COMPLETE: on success + * - EEPROM_BAD_ADDRESS: if address = 0xFFFF + * - EEPROM_PAGE_FULL: if valid page is full + * - EEPROM_NO_VALID_PAGE: if no valid page was found + * - EEPROM_OUT_SIZE: if no empty EEPROM variables + * - Flash error code: on write Flash error + */ +uint16_t EEPROM_update(uint16_t Address, uint16_t Data) +{ + uint16_t temp; + EEPROM_read(Address, &temp); + if (temp == Data) + return EEPROM_SAME_VALUE; + else + return EEPROM_write(Address, Data); +} + +/** + * @brief Return number of variable + * @retval Number of variables + */ +uint16_t EEPROM_count(uint16_t *Count) +{ + if (Status == EEPROM_NOT_INIT) + if (EEPROM_init() != EEPROM_OK) + return Status; + + // Get valid Page for write operation + uint32_t pageBase = EE_FindValidPage(); + if (pageBase == 0) + return EEPROM_NO_VALID_PAGE; // No valid page, return max. numbers + + *Count = EE_GetVariablesCount(pageBase, 0xFFFF); + return EEPROM_OK; +} + +uint16_t EEPROM_maxcount(void) +{ + return ((PageSize / 4)-1); +} + + +uint8_t eeprom_read_byte (const uint8_t *Address) +{ + const uint16_t p = (const uint32_t) Address; + uint16_t temp; + EEPROM_read(p, &temp); + return (uint8_t) temp; +} + +void eeprom_write_byte (uint8_t *Address, uint8_t Value) +{ + uint16_t p = (uint32_t) Address; + EEPROM_write(p, (uint16_t) Value); +} + +void eeprom_update_byte (uint8_t *Address, uint8_t Value) +{ + uint16_t p = (uint32_t) Address; + EEPROM_update(p, (uint16_t) Value); +} + +uint16_t eeprom_read_word (const uint16_t *Address) +{ + const uint16_t p = (const uint32_t) Address; + uint16_t temp; + EEPROM_read(p, &temp); + return temp; +} + +void eeprom_write_word (uint16_t *Address, uint16_t Value) +{ + uint16_t p = (uint32_t) Address; + EEPROM_write(p, Value); +} + +void eeprom_update_word (uint16_t *Address, uint16_t Value) +{ + uint16_t p = (uint32_t) Address; + EEPROM_update(p, Value); +} + +uint32_t eeprom_read_dword (const uint32_t *Address) +{ + const uint16_t p = (const uint32_t) Address; + uint16_t temp1, temp2; + EEPROM_read(p, &temp1); + EEPROM_read(p + 1, &temp2); + return temp1 | (temp2 << 16); +} + +void eeprom_write_dword (uint32_t *Address, uint32_t Value) +{ + uint16_t temp = (uint16_t) Value; + uint16_t p = (uint32_t) Address; + EEPROM_write(p, temp); + temp = (uint16_t) (Value >> 16); + EEPROM_write(p + 1, temp); +} + +void eeprom_update_dword (uint32_t *Address, uint32_t Value) +{ + uint16_t temp = (uint16_t) Value; + uint16_t p = (uint32_t) Address; + EEPROM_update(p, temp); + temp = (uint16_t) (Value >> 16); + EEPROM_update(p + 1, temp); +} diff --git a/tmk_core/common/chibios/eeprom_stm32.h b/tmk_core/common/chibios/eeprom_stm32.h new file mode 100755 index 000000000..09229530c --- /dev/null +++ b/tmk_core/common/chibios/eeprom_stm32.h @@ -0,0 +1,95 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * 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. + * + * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and + * https://github.com/leaflabs/libmaple + * + * Modifications for QMK and STM32F303 by Yiancar + */ + +// This file must be modified if the MCU is not defined below. +// This library also assumes that the pages are not used by the firmware. + +#ifndef __EEPROM_H +#define __EEPROM_H + +#include "ch.h" +#include "hal.h" +#include "flash_stm32.h" + +// HACK ALERT. This definition may not match your processor +// To Do. Work out correct value for EEPROM_PAGE_SIZE on the STM32F103CT6 etc +#if defined(EEPROM_EMU_STM32F303xC) + #define MCU_STM32F303CC +#elif defined(EEPROM_EMU_STM32F103xB) + #define MCU_STM32F103RB +#else + #error "not implemented." +#endif + +#ifndef EEPROM_PAGE_SIZE + #if defined (MCU_STM32F103RB) + #define EEPROM_PAGE_SIZE (uint16_t)0x400 /* Page size = 1KByte */ + #elif defined (MCU_STM32F103ZE) || defined (MCU_STM32F103RE) || defined (MCU_STM32F103RD) || defined (MCU_STM32F303CC) + #define EEPROM_PAGE_SIZE (uint16_t)0x800 /* Page size = 2KByte */ + #else + #error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)." + #endif +#endif + +#ifndef EEPROM_START_ADDRESS + #if defined (MCU_STM32F103RB) + #define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 128 * 1024 - 2 * EEPROM_PAGE_SIZE)) + #elif defined (MCU_STM32F103ZE) || defined (MCU_STM32F103RE) + #define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 512 * 1024 - 2 * EEPROM_PAGE_SIZE)) + #elif defined (MCU_STM32F103RD) + #define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 384 * 1024 - 2 * EEPROM_PAGE_SIZE)) + #elif defined (MCU_STM32F303CC) + #define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 256 * 1024 - 2 * EEPROM_PAGE_SIZE)) + #else + #error "No MCU type specified. Add something like -DMCU_STM32F103RB to your compiler arguments (probably in a Makefile)." + #endif +#endif + +/* Pages 0 and 1 base and end addresses */ +#define EEPROM_PAGE0_BASE ((uint32_t)(EEPROM_START_ADDRESS + 0x000)) +#define EEPROM_PAGE1_BASE ((uint32_t)(EEPROM_START_ADDRESS + EEPROM_PAGE_SIZE)) + +/* Page status definitions */ +#define EEPROM_ERASED ((uint16_t)0xFFFF) /* PAGE is empty */ +#define EEPROM_RECEIVE_DATA ((uint16_t)0xEEEE) /* PAGE is marked to receive data */ +#define EEPROM_VALID_PAGE ((uint16_t)0x0000) /* PAGE containing valid data */ + +/* Page full define */ +enum uint16_t + { + EEPROM_OK = ((uint16_t)0x0000), + EEPROM_OUT_SIZE = ((uint16_t)0x0081), + EEPROM_BAD_ADDRESS = ((uint16_t)0x0082), + EEPROM_BAD_FLASH = ((uint16_t)0x0083), + EEPROM_NOT_INIT = ((uint16_t)0x0084), + EEPROM_SAME_VALUE = ((uint16_t)0x0085), + EEPROM_NO_VALID_PAGE = ((uint16_t)0x00AB) + }; + +#define EEPROM_DEFAULT_DATA 0xFFFF + + uint16_t EEPROM_init(void); + uint16_t EEPROM_format(void); + uint16_t EEPROM_erases(uint16_t *); + uint16_t EEPROM_read (uint16_t address, uint16_t *data); + uint16_t EEPROM_write(uint16_t address, uint16_t data); + uint16_t EEPROM_update(uint16_t address, uint16_t data); + uint16_t EEPROM_count(uint16_t *); + uint16_t EEPROM_maxcount(void); + +#endif /* __EEPROM_H */ diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom_teensy.c index 9061b790c..9061b790c 100644 --- a/tmk_core/common/chibios/eeprom.c +++ b/tmk_core/common/chibios/eeprom_teensy.c diff --git a/tmk_core/common/chibios/flash_stm32.c b/tmk_core/common/chibios/flash_stm32.c new file mode 100755 index 000000000..273593484 --- /dev/null +++ b/tmk_core/common/chibios/flash_stm32.c @@ -0,0 +1,188 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * 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. + * + * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and + * https://github.com/leaflabs/libmaple + * + * Modifications for QMK and STM32F303 by Yiancar + */ + +#if defined(EEPROM_EMU_STM32F303xC) + #define STM32F303xC + #include "stm32f3xx.h" +#elif defined(EEPROM_EMU_STM32F103xB) + #define STM32F103xB + #include "stm32f1xx.h" +#else + #error "not implemented." +#endif + +#include "flash_stm32.h" + +#if defined(EEPROM_EMU_STM32F103xB) + #define FLASH_SR_WRPERR FLASH_SR_WRPRTERR +#endif + +/* Delay definition */ +#define EraseTimeout ((uint32_t)0x00000FFF) +#define ProgramTimeout ((uint32_t)0x0000001F) + +#define ASSERT(exp) (void)((0)) + +/** + * @brief Inserts a time delay. + * @param None + * @retval None + */ +static void delay(void) +{ + __IO uint32_t i = 0; + for(i = 0xFF; i != 0; i--) { } +} + +/** + * @brief Returns the FLASH Status. + * @param None + * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, + * FLASH_ERROR_WRP or FLASH_COMPLETE + */ +FLASH_Status FLASH_GetStatus(void) +{ + if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY) + return FLASH_BUSY; + + if ((FLASH->SR & FLASH_SR_PGERR) != 0) + return FLASH_ERROR_PG; + + if ((FLASH->SR & FLASH_SR_WRPERR) != 0 ) + return FLASH_ERROR_WRP; + + if ((FLASH->SR & FLASH_OBR_OPTERR) != 0 ) + return FLASH_ERROR_OPT; + + return FLASH_COMPLETE; +} + +/** + * @brief Waits for a Flash operation to complete or a TIMEOUT to occur. + * @param Timeout: FLASH progamming Timeout + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) +{ + FLASH_Status status; + + /* Check for the Flash Status */ + status = FLASH_GetStatus(); + /* Wait for a Flash operation to complete or a TIMEOUT to occur */ + while ((status == FLASH_BUSY) && (Timeout != 0x00)) + { + delay(); + status = FLASH_GetStatus(); + Timeout--; + } + if (Timeout == 0) + status = FLASH_TIMEOUT; + /* Return the operation status */ + return status; +} + +/** + * @brief Erases a specified FLASH page. + * @param Page_Address: The page address to be erased. + * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ErasePage(uint32_t Page_Address) +{ + FLASH_Status status = FLASH_COMPLETE; + /* Check the parameters */ + ASSERT(IS_FLASH_ADDRESS(Page_Address)); + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(EraseTimeout); + + if(status == FLASH_COMPLETE) + { + /* if the previous operation is completed, proceed to erase the page */ + FLASH->CR |= FLASH_CR_PER; + FLASH->AR = Page_Address; + FLASH->CR |= FLASH_CR_STRT; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(EraseTimeout); + if(status != FLASH_TIMEOUT) + { + /* if the erase operation is completed, disable the PER Bit */ + FLASH->CR &= ~FLASH_CR_PER; + } + FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); + } + /* Return the Erase Status */ + return status; +} + +/** + * @brief Programs a half word at a specified address. + * @param Address: specifies the address to be programmed. + * @param Data: specifies the data to be programmed. + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) +{ + FLASH_Status status = FLASH_BAD_ADDRESS; + + if (IS_FLASH_ADDRESS(Address)) + { + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(ProgramTimeout); + if(status == FLASH_COMPLETE) + { + /* if the previous operation is completed, proceed to program the new data */ + FLASH->CR |= FLASH_CR_PG; + *(__IO uint16_t*)Address = Data; + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(ProgramTimeout); + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the PG Bit */ + FLASH->CR &= ~FLASH_CR_PG; + } + FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); + } + } + return status; +} + +/** + * @brief Unlocks the FLASH Program Erase Controller. + * @param None + * @retval None + */ +void FLASH_Unlock(void) +{ + /* Authorize the FPEC Access */ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; +} + +/** + * @brief Locks the FLASH Program Erase Controller. + * @param None + * @retval None + */ +void FLASH_Lock(void) +{ + /* Set the Lock Bit to lock the FPEC and the FCR */ + FLASH->CR |= FLASH_CR_LOCK; +} diff --git a/tmk_core/common/chibios/flash_stm32.h b/tmk_core/common/chibios/flash_stm32.h new file mode 100755 index 000000000..cc065cbca --- /dev/null +++ b/tmk_core/common/chibios/flash_stm32.h @@ -0,0 +1,53 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * 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. + * + * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and + * https://github.com/leaflabs/libmaple + * + * Modifications for QMK and STM32F303 by Yiancar + */ + +#ifndef __FLASH_STM32_H +#define __FLASH_STM32_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "ch.h" +#include "hal.h" + +typedef enum + { + FLASH_BUSY = 1, + FLASH_ERROR_PG, + FLASH_ERROR_WRP, + FLASH_ERROR_OPT, + FLASH_COMPLETE, + FLASH_TIMEOUT, + FLASH_BAD_ADDRESS + } FLASH_Status; + +#define IS_FLASH_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) < 0x0807FFFF)) + +FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); +FLASH_Status FLASH_ErasePage(uint32_t Page_Address); +FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); + +void FLASH_Unlock(void); +void FLASH_Lock(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __FLASH_STM32_H */ diff --git a/tmk_core/common/command.c b/tmk_core/common/command.c index f79d5a257..aab99290d 100644 --- a/tmk_core/common/command.c +++ b/tmk_core/common/command.c @@ -181,7 +181,11 @@ static void print_version(void) print("VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") " "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") " "VER: " STR(DEVICE_VER) "\n"); +#ifdef SKIP_VERSION + print("BUILD: (" __DATE__ ")\n"); +#else print("BUILD: " STR(QMK_VERSION) " (" __TIME__ " " __DATE__ ")\n"); +#endif /* build options */ print("OPTIONS:" diff --git a/tmk_core/common/command.h b/tmk_core/common/command.h index d9d89ba0f..c38f2b9e8 100644 --- a/tmk_core/common/command.h +++ b/tmk_core/common/command.h @@ -15,8 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef COMMAND_H -#define COMMAND +#pragma once /* FIXME: Add doxygen comments for the behavioral defines in here. */ @@ -155,5 +154,3 @@ bool command_proc(uint8_t code); #define XMAGIC_KC(key) KC_##key #define MAGIC_KC(key) XMAGIC_KC(key) - -#endif diff --git a/tmk_core/common/eeconfig.c b/tmk_core/common/eeconfig.c index 3e5987ee3..d8bab7d2e 100644 --- a/tmk_core/common/eeconfig.c +++ b/tmk_core/common/eeconfig.c @@ -3,29 +3,59 @@ #include "eeprom.h" #include "eeconfig.h" -/** \brief eeconfig initialization +#ifdef STM32_EEPROM_ENABLE +#include "hal.h" +#include "eeprom_stm32.h" +#endif + +extern uint32_t default_layer_state; +/** \brief eeconfig enable * * FIXME: needs doc */ -void eeconfig_init(void) -{ - eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); - eeprom_update_byte(EECONFIG_DEBUG, 0); - eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0); - eeprom_update_byte(EECONFIG_KEYMAP, 0); - eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0); -#ifdef BACKLIGHT_ENABLE - eeprom_update_byte(EECONFIG_BACKLIGHT, 0); -#endif -#ifdef AUDIO_ENABLE - eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default -#endif -#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE) - eeprom_update_dword(EECONFIG_RGBLIGHT, 0); -#endif -#ifdef STENO_ENABLE - eeprom_update_byte(EECONFIG_STENOMODE, 0); +__attribute__ ((weak)) +void eeconfig_init_user(void) { + // Reset user EEPROM value to blank, rather than to a set value + eeconfig_update_user(0); +} + +__attribute__ ((weak)) +void eeconfig_init_kb(void) { + // Reset Keyboard EEPROM value to blank, rather than to a set value + eeconfig_update_kb(0); + + eeconfig_init_user(); +} + + +/* + * FIXME: needs doc + */ +void eeconfig_init_quantum(void) { +#ifdef STM32_EEPROM_ENABLE + EEPROM_format(); #endif + eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); + eeprom_update_byte(EECONFIG_DEBUG, 0); + eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0); + default_layer_state = 0; + eeprom_update_byte(EECONFIG_KEYMAP, 0); + eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0); + eeprom_update_byte(EECONFIG_BACKLIGHT, 0); + eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default + eeprom_update_dword(EECONFIG_RGBLIGHT, 0); + eeprom_update_byte(EECONFIG_STENOMODE, 0); + + eeconfig_init_kb(); +} + +/** \brief eeconfig initialization + * + * FIXME: needs doc + */ +void eeconfig_init(void) { + + eeconfig_init_quantum(); } /** \brief eeconfig enable @@ -43,7 +73,10 @@ void eeconfig_enable(void) */ void eeconfig_disable(void) { - eeprom_update_word(EECONFIG_MAGIC, 0xFFFF); +#ifdef STM32_EEPROM_ENABLE + EEPROM_format(); +#endif + eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER_OFF); } /** \brief eeconfig is enabled @@ -55,6 +88,15 @@ bool eeconfig_is_enabled(void) return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER); } +/** \brief eeconfig is disabled + * + * FIXME: needs doc + */ +bool eeconfig_is_disabled(void) +{ + return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER_OFF); +} + /** \brief eeconfig read debug * * FIXME: needs doc @@ -88,7 +130,6 @@ uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMA */ void eeconfig_update_keymap(uint8_t val) { eeprom_update_byte(EECONFIG_KEYMAP, val); } -#ifdef BACKLIGHT_ENABLE /** \brief eeconfig read backlight * * FIXME: needs doc @@ -99,9 +140,8 @@ uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BA * FIXME: needs doc */ void eeconfig_update_backlight(uint8_t val) { eeprom_update_byte(EECONFIG_BACKLIGHT, val); } -#endif -#ifdef AUDIO_ENABLE + /** \brief eeconfig read audio * * FIXME: needs doc @@ -112,4 +152,28 @@ uint8_t eeconfig_read_audio(void) { return eeprom_read_byte(EECONFIG_AUDIO) * FIXME: needs doc */ void eeconfig_update_audio(uint8_t val) { eeprom_update_byte(EECONFIG_AUDIO, val); } -#endif + + +/** \brief eeconfig read kb + * + * FIXME: needs doc + */ +uint32_t eeconfig_read_kb(void) { return eeprom_read_dword(EECONFIG_KEYBOARD); } +/** \brief eeconfig update kb + * + * FIXME: needs doc + */ + +void eeconfig_update_kb(uint32_t val) { eeprom_update_dword(EECONFIG_KEYBOARD, val); } +/** \brief eeconfig read user + * + * FIXME: needs doc + */ +uint32_t eeconfig_read_user(void) { return eeprom_read_dword(EECONFIG_USER); } +/** \brief eeconfig update user + * + * FIXME: needs doc + */ +void eeconfig_update_user(uint32_t val) { eeprom_update_dword(EECONFIG_USER, val); } + + diff --git a/tmk_core/common/eeconfig.h b/tmk_core/common/eeconfig.h index 1397a90c7..8d4e1d4d0 100644 --- a/tmk_core/common/eeconfig.h +++ b/tmk_core/common/eeconfig.h @@ -23,21 +23,42 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEED +#define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF /* eeprom parameteter address */ +#if !defined(STM32_EEPROM_ENABLE) #define EECONFIG_MAGIC (uint16_t *)0 -#define EECONFIG_DEBUG (uint8_t *)2 -#define EECONFIG_DEFAULT_LAYER (uint8_t *)3 -#define EECONFIG_KEYMAP (uint8_t *)4 -#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5 -#define EECONFIG_BACKLIGHT (uint8_t *)6 -#define EECONFIG_AUDIO (uint8_t *)7 +#define EECONFIG_DEBUG (uint8_t *)2 +#define EECONFIG_DEFAULT_LAYER (uint8_t *)3 +#define EECONFIG_KEYMAP (uint8_t *)4 +#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5 +#define EECONFIG_BACKLIGHT (uint8_t *)6 +#define EECONFIG_AUDIO (uint8_t *)7 #define EECONFIG_RGBLIGHT (uint32_t *)8 #define EECONFIG_UNICODEMODE (uint8_t *)12 #define EECONFIG_STENOMODE (uint8_t *)13 // EEHANDS for two handed boards -#define EECONFIG_HANDEDNESS (uint8_t *)14 +#define EECONFIG_HANDEDNESS (uint8_t *)14 +#define EECONFIG_KEYBOARD (uint32_t *)15 +#define EECONFIG_USER (uint32_t *)19 +#else +/* STM32F3 uses 16byte block. Reconfigure memory map */ +#define EECONFIG_MAGIC (uint16_t *)0 +#define EECONFIG_DEBUG (uint8_t *)1 +#define EECONFIG_DEFAULT_LAYER (uint8_t *)2 +#define EECONFIG_KEYMAP (uint8_t *)3 +#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)4 +#define EECONFIG_BACKLIGHT (uint8_t *)5 +#define EECONFIG_AUDIO (uint8_t *)6 +#define EECONFIG_RGBLIGHT (uint32_t *)7 +#define EECONFIG_UNICODEMODE (uint8_t *)9 +#define EECONFIG_STENOMODE (uint8_t *)10 +// EEHANDS for two handed boards +#define EECONFIG_HANDEDNESS (uint8_t *)11 +#define EECONFIG_KEYBOARD (uint32_t *)12 +#define EECONFIG_USER (uint32_t *)14 +#endif /* debug bit */ #define EECONFIG_DEBUG_ENABLE (1<<0) @@ -57,8 +78,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. bool eeconfig_is_enabled(void); +bool eeconfig_is_disabled(void); void eeconfig_init(void); +void eeconfig_init_quantum(void); +void eeconfig_init_kb(void); +void eeconfig_init_user(void); void eeconfig_enable(void); @@ -83,4 +108,9 @@ uint8_t eeconfig_read_audio(void); void eeconfig_update_audio(uint8_t val); #endif +uint32_t eeconfig_read_kb(void); +void eeconfig_update_kb(uint32_t val); +uint32_t eeconfig_read_user(void); +void eeconfig_update_user(uint32_t val); + #endif diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c index e12b62216..f5d041699 100644 --- a/tmk_core/common/host.c +++ b/tmk_core/common/host.c @@ -22,6 +22,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "util.h" #include "debug.h" +#ifdef NKRO_ENABLE + #include "keycode_config.h" + extern keymap_config_t keymap_config; +#endif + static host_driver_t *driver; static uint16_t last_system_report = 0; static uint16_t last_consumer_report = 0; @@ -46,6 +51,20 @@ uint8_t host_keyboard_leds(void) void host_keyboard_send(report_keyboard_t *report) { if (!driver) return; +#if defined(NKRO_ENABLE) && defined(NKRO_SHARED_EP) + if (keyboard_protocol && keymap_config.nkro) { + /* The callers of this function assume that report->mods is where mods go in. + * But report->nkro.mods can be at a different offset if core keyboard does not have a report ID. + */ + report->nkro.mods = report->mods; + report->nkro.report_id = REPORT_ID_NKRO; + } else +#endif + { +#ifdef KEYBOARD_SHARED_EP + report->report_id = REPORT_ID_KEYBOARD; +#endif + } (*driver->send_keyboard)(report); if (debug_keyboard) { @@ -60,6 +79,9 @@ void host_keyboard_send(report_keyboard_t *report) void host_mouse_send(report_mouse_t *report) { if (!driver) return; +#ifdef MOUSE_SHARED_EP + report->report_id = REPORT_ID_MOUSE; +#endif (*driver->send_mouse)(report); } diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c index fe626efb3..1bfd4c9cc 100644 --- a/tmk_core/common/keyboard.c +++ b/tmk_core/common/keyboard.c @@ -73,6 +73,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #ifdef HD44780_ENABLE # include "hd44780.h" #endif +#ifdef QWIIC_ENABLE +# include "qwiic.h" +#endif #ifdef MATRIX_HAS_GHOST extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; @@ -121,6 +124,14 @@ static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) #endif +void disable_jtag(void) { +// To use PORTF disable JTAG with writing JTD bit twice within four cycles. +#if (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega32U4__)) + MCUCR |= _BV(JTD); + MCUCR |= _BV(JTD); +#endif +} + /** \brief matrix_setup * * FIXME: needs doc @@ -134,6 +145,7 @@ void matrix_setup(void) { * FIXME: needs doc */ void keyboard_setup(void) { + disable_jtag(); matrix_setup(); } @@ -152,13 +164,11 @@ bool is_keyboard_master(void) { */ void keyboard_init(void) { timer_init(); -// To use PORTF disable JTAG with writing JTD bit twice within four cycles. -#if (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega32U4__)) - MCUCR |= _BV(JTD); - MCUCR |= _BV(JTD); -#endif matrix_init(); matrix_debounce_init(); +#ifdef QWIIC_ENABLE + qwiic_init(); +#endif #ifdef PS2_MOUSE_ENABLE ps2_mouse_init(); #endif @@ -256,6 +266,10 @@ void keyboard_task(void) MATRIX_LOOP_END: +#ifdef QWIIC_ENABLE + qwiic_task(); +#endif + #ifdef MOUSEKEY_ENABLE // mousekey repeat & acceleration mousekey_task(); diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h index f17003c2f..71e594a89 100644 --- a/tmk_core/common/keyboard.h +++ b/tmk_core/common/keyboard.h @@ -57,6 +57,8 @@ static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) && .time = (timer_read() | 1) \ } +void disable_jtag(void); + /* it runs once at early stage of startup before keyboard_init. */ void keyboard_setup(void); /* it runs once after initializing host side protocol, debug and MCU peripherals. */ diff --git a/tmk_core/common/keycode.h b/tmk_core/common/keycode.h index 61642ae84..ac3edbd21 100644 --- a/tmk_core/common/keycode.h +++ b/tmk_core/common/keycode.h @@ -33,7 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) #define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE) -#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_MRWD) +#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_BRID) #define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31) @@ -140,6 +140,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define KC_LWIN KC_LGUI #define KC_RCTL KC_RCTRL #define KC_RSFT KC_RSHIFT +#define KC_ALGR KC_RALT #define KC_RCMD KC_RGUI #define KC_RWIN KC_RGUI @@ -170,6 +171,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define KC_WFAV KC_WWW_FAVORITES #define KC_MFFD KC_MEDIA_FAST_FORWARD #define KC_MRWD KC_MEDIA_REWIND +#define KC_BRIU KC_BRIGHTNESS_UP +#define KC_BRID KC_BRIGHTNESS_DOWN /* Mouse Keys */ #define KC_MS_U KC_MS_UP @@ -457,6 +460,8 @@ enum internal_special_keycodes { KC_WWW_FAVORITES, KC_MEDIA_FAST_FORWARD, KC_MEDIA_REWIND, + KC_BRIGHTNESS_UP, + KC_BRIGHTNESS_DOWN, /* Fn keys */ KC_FN0 = 0xC0, diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h index 8836c0fc7..2d7184bd0 100644 --- a/tmk_core/common/print.h +++ b/tmk_core/common/print.h @@ -29,7 +29,7 @@ #include <stdbool.h> #include "util.h" -#if defined(PROTOCOL_CHIBIOS) +#if defined(PROTOCOL_CHIBIOS) || defined(PROTOCOL_ARM_ATSAM) #define PSTR(x) x #endif @@ -60,7 +60,7 @@ # define println(s) xputs(PSTR(s "\r\n")) # define uprint(s) print(s) # define uprintln(s) println(s) -# define uprintf(fmt, ...) xprintf(fmt, ...) +# define uprintf(fmt, ...) xprintf(fmt, ##__VA_ARGS__) # endif /* USER_PRINT / NORMAL PRINT */ @@ -73,7 +73,9 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); #elif defined(PROTOCOL_CHIBIOS) /* PROTOCOL_CHIBIOS */ +#ifndef TERMINAL_ENABLE # include "chibios/printf.h" +#endif # ifdef USER_PRINT /* USER_PRINT */ @@ -99,6 +101,34 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); # endif /* USER_PRINT / NORMAL PRINT */ +#elif defined(PROTOCOL_ARM_ATSAM) /* PROTOCOL_ARM_ATSAM */ + +# include "arm_atsam/printf.h" + +# ifdef USER_PRINT /* USER_PRINT */ + +// Remove normal print defines +# define print(s) +# define println(s) +# define xprintf(fmt, ...) + +// Create user print defines +# define uprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__) +# define uprint(s) xprintf(s) +# define uprintln(s) xprintf(s "\r\n") + +# else /* NORMAL PRINT */ + +// Create user & normal print defines +# define xprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__) +# define print(s) xprintf(s) +# define println(s) xprintf(s "\r\n") +# define uprint(s) print(s) +# define uprintln(s) println(s) +# define uprintf(fmt, ...) xprintf(fmt, ##__VA_ARGS__) + +# endif /* USER_PRINT / NORMAL PRINT */ + #elif defined(__arm__) /* __arm__ */ # include "mbed/xprintf.h" @@ -111,26 +141,26 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); # define xprintf(fmt, ...) // Create user print defines -# define uprintf(fmt, ...) __xprintf(fmt, ...) +# define uprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__) # define uprint(s) xprintf(s) # define uprintln(s) xprintf(s "\r\n") # else /* NORMAL PRINT */ // Create user & normal print defines -# define xprintf(fmt, ...) __xprintf(fmt, ...) +# define xprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__) # define print(s) xprintf(s) # define println(s) xprintf(s "\r\n") # define uprint(s) print(s) # define uprintln(s) println(s) -# define uprintf(fmt, ...) xprintf(fmt, ...) +# define uprintf(fmt, ...) xprintf(fmt, ##__VA_ARGS__) # endif /* USER_PRINT / NORMAL PRINT */ /* TODO: to select output destinations: UART/USBSerial */ # define print_set_sendchar(func) -#endif /* __AVR__ / PROTOCOL_CHIBIOS / __arm__ */ +#endif /* __AVR__ / PROTOCOL_CHIBIOS / PROTOCOL_ARM_ATSAM / __arm__ */ // User print disables the normal print messages in the body of QMK/TMK code and // is meant as a lightweight alternative to NOPRINT. Use it when you only want to do diff --git a/tmk_core/common/report.c b/tmk_core/common/report.c index eb3b44312..6a06b70c6 100644 --- a/tmk_core/common/report.c +++ b/tmk_core/common/report.c @@ -19,6 +19,7 @@ #include "keycode_config.h" #include "debug.h" #include "util.h" +#include <string.h> /** \brief has_anykey * @@ -27,8 +28,16 @@ uint8_t has_anykey(report_keyboard_t* keyboard_report) { uint8_t cnt = 0; - for (uint8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) { - if (keyboard_report->raw[i]) + uint8_t *p = keyboard_report->keys; + uint8_t lp = sizeof(keyboard_report->keys); +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + p = keyboard_report->nkro.bits; + lp = sizeof(keyboard_report->nkro.bits); + } +#endif + while (lp--) { + if (*p++) cnt++; } return cnt; @@ -237,7 +246,11 @@ void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key) void clear_keys_from_report(report_keyboard_t* keyboard_report) { // not clear mods - for (int8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) { - keyboard_report->raw[i] = 0; +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits)); + return; } +#endif + memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys)); } diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h index 6c27eb9dc..eb9afb727 100644 --- a/tmk_core/common/report.h +++ b/tmk_core/common/report.h @@ -23,9 +23,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. /* report id */ -#define REPORT_ID_MOUSE 1 -#define REPORT_ID_SYSTEM 2 -#define REPORT_ID_CONSUMER 3 +#define REPORT_ID_KEYBOARD 1 +#define REPORT_ID_MOUSE 2 +#define REPORT_ID_SYSTEM 3 +#define REPORT_ID_CONSUMER 4 +#define REPORT_ID_NKRO 5 /* mouse buttons */ #define MOUSE_BTN1 (1<<0) @@ -36,6 +38,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. /* Consumer Page(0x0C) * following are supported by Windows: http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx + * see also https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/display-brightness-control */ #define AUDIO_MUTE 0x00E2 #define AUDIO_VOL_UP 0x00E9 @@ -45,6 +48,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define TRANSPORT_STOP 0x00B7 #define TRANSPORT_STOP_EJECT 0x00CC #define TRANSPORT_PLAY_PAUSE 0x00CD +#define BRIGHTNESSUP 0x006F +#define BRIGHTNESSDOWN 0x0070 /* application launch */ #define AL_CC_CONFIG 0x0183 #define AL_EMAIL 0x018A @@ -72,27 +77,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #define SYSTEM_WAKE_UP 0x0083 +#define NKRO_SHARED_EP /* key report size(NKRO or boot mode) */ #if defined(NKRO_ENABLE) - #if defined(PROTOCOL_PJRC) - #include "usb.h" - #define KEYBOARD_REPORT_SIZE KBD2_SIZE - #define KEYBOARD_REPORT_KEYS (KBD2_SIZE - 2) - #define KEYBOARD_REPORT_BITS (KBD2_SIZE - 1) - #elif defined(PROTOCOL_LUFA) || defined(PROTOCOL_CHIBIOS) + #if defined(PROTOCOL_LUFA) || defined(PROTOCOL_CHIBIOS) #include "protocol/usb_descriptor.h" - #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE - #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) + #define KEYBOARD_REPORT_BITS (SHARED_EPSIZE - 2) + #elif defined(PROTOCOL_ARM_ATSAM) + #include "protocol/arm_atsam/usb/udi_device_epsize.h" #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) + #undef NKRO_SHARED_EP + #undef MOUSE_SHARED_EP #else #error "NKRO not supported with this protocol" + #endif #endif +#ifdef KEYBOARD_SHARED_EP +# define KEYBOARD_REPORT_SIZE 9 #else # define KEYBOARD_REPORT_SIZE 8 -# define KEYBOARD_REPORT_KEYS 6 #endif +#define KEYBOARD_REPORT_KEYS 6 + +/* VUSB hardcodes keyboard and mouse+extrakey only */ +#if defined(PROTOCOL_VUSB) + #undef KEYBOARD_SHARED_EP + #undef MOUSE_SHARED_EP +#endif #ifdef __cplusplus extern "C" { @@ -121,12 +134,18 @@ extern "C" { typedef union { uint8_t raw[KEYBOARD_REPORT_SIZE]; struct { +#ifdef KEYBOARD_SHARED_EP + uint8_t report_id; +#endif uint8_t mods; uint8_t reserved; uint8_t keys[KEYBOARD_REPORT_KEYS]; }; #ifdef NKRO_ENABLE - struct { + struct nkro_report { +#ifdef NKRO_SHARED_EP + uint8_t report_id; +#endif uint8_t mods; uint8_t bits[KEYBOARD_REPORT_BITS]; } nkro; @@ -134,6 +153,9 @@ typedef union { } __attribute__ ((packed)) report_keyboard_t; typedef struct { +#ifdef MOUSE_SHARED_EP + uint8_t report_id; +#endif uint8_t buttons; int8_t x; int8_t y; @@ -170,7 +192,9 @@ typedef struct { (key == KC_WWW_FORWARD ? AC_FORWARD : \ (key == KC_WWW_STOP ? AC_STOP : \ (key == KC_WWW_REFRESH ? AC_REFRESH : \ - (key == KC_WWW_FAVORITES ? AC_BOOKMARKS : 0))))))))))))))))))))) + (key == KC_BRIGHTNESS_UP ? BRIGHTNESSUP : \ + (key == KC_BRIGHTNESS_DOWN ? BRIGHTNESSDOWN : \ + (key == KC_WWW_FAVORITES ? AC_BOOKMARKS : 0))))))))))))))))))))))) uint8_t has_anykey(report_keyboard_t* keyboard_report); uint8_t get_first_key(report_keyboard_t* keyboard_report); |