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 f7c039f457..b99c2acaa7 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 acc55c7d38..8e47e5339e 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 f3cd381ab0..120ce3f51b 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 72a6bd8f68..f1551d2519 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 0000000000..ba71bfeb0b --- /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 0000000000..61cc039efa --- /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 0000000000..7f298d1fda --- /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 0000000000..1f1c2280b5 --- /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 0000000000..e34965df64 --- /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 0000000000..bcfe5002c3 --- /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 3d4a48439b..5bca646854 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 3e29aacc49..8ddacd98b6 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 f573092674..420c9d19ed 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 0000000000..a869985501 --- /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 0000000000..09229530ca --- /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 9061b790c4..9061b790c4 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 0000000000..2735934844 --- /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 0000000000..cc065cbca2 --- /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 f79d5a257b..aab99290d2 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 d9d89ba0f1..c38f2b9e80 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 3e5987ee3b..d8bab7d2e5 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 1397a90c79..8d4e1d4d00 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 e12b622165..f5d0416996 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 fe626efb35..1bfd4c9cca 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 f17003c2ff..71e594a890 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 61642ae84f..ac3edbd215 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 8836c0fc7c..2d7184bd0d 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 eb3b44312f..6a06b70c60 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 6c27eb9dc6..eb9afb727e 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); | 
