From 30680c6eb396a2bb06928afd69edae9908ac84fb Mon Sep 17 00:00:00 2001 From: patrickmt <40182064+patrickmt@users.noreply.github.com> Date: Wed, 29 Aug 2018 15:07:52 -0400 Subject: Massdrop keyboard support (#3780) * Massdrop SAMD51 Massdrop SAMD51 keyboards initial project upload * Removing relocated files Removing files that were relocated and not deleted from previous location * LED queue fix and cleaning Cleaned some white space or comments. Fix for LED I2C command queue. Cleaned up interrupts. Added debug function for printing numbers to scope through m15 line. * Factory programmed serial usage Ability to use factory programmed serial in hub and keyboard usb descriptors * USB serial number and bugfix Added support for factory programmed serial and usage. Incorporated bootloader's conditional compiling to align project closer. Fixed issue when USB device attempted to send before enabled. General white space and comment cleanup. * Project cleanup Cleaned up project in terms of white space, commented code, and unecessary files. NKRO keyboard is now using correct setreport although KBD was fine to use. Fixed broken linkage to __xprintf for serial debug statements. * Fix for extra keys Fixed possible USB hang on extra keys report set missing * I2C cleanup I2C cleanup and file renames necessary for master branch merge * Boot tracing and clocks cleanup Added optional boot debug trace mode through debug LED codes. General clock code cleanup. * Relocate ARM/Atmel headers Moved ARM/Atmel header folder from drivers to lib and made necessary makefile changes. * Pull request changes Pull request changes * Keymap and compile flag fix Keymap fix for momentary layer. Potential compile flag fix for Travis CI failure. * va_list include fix Fix for va_list compile failure * Include file case fixes Fixes for include files with incorrect case * ctrl and alt67 keyboard readme Added ctrl and alt67 keyboard readme files --- tmk_core/common.mk | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tmk_core/common.mk') diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 3e407f1573..fd91d29dce 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -3,6 +3,8 @@ ifeq ($(PLATFORM),AVR) PLATFORM_COMMON_DIR = $(COMMON_DIR)/avr else ifeq ($(PLATFORM),CHIBIOS) PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios +else ifeq ($(PLATFORM),ARM_ATSAM) + PLATFORM_COMMON_DIR = $(COMMON_DIR)/arm_atsam else PLATFORM_COMMON_DIR = $(COMMON_DIR)/test endif @@ -35,6 +37,10 @@ ifeq ($(PLATFORM),CHIBIOS) endif endif +ifeq ($(PLATFORM),ARM_ATSAM) + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c +endif + ifeq ($(PLATFORM),TEST) TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c endif -- cgit v1.2.3 From 621ce29a53e9e94e085fbd86c0b7134e9df4bfe5 Mon Sep 17 00:00:00 2001 From: yiancar Date: Wed, 29 Aug 2018 23:14:49 +0300 Subject: STM32 EEPROM Emulation (#3741) * STM32 EEPROM Emulation - Added EEPROM emulation libaries from libmaple and Arduino_STM32. https://github.com/rogerclarkmelbourne/Arduino_STM32 and https://github.com/leaflabs/libmaple. - Renamed teensy EEPROM library and added conditional selection of library. - Remapped EEPROM memory map for 16 byte blocks (as is with STM32f3xx MCUs). - Added EEPROM initialization in main.c of Chibios. - Added EEPROM format to clear the emulated pages when EEPROM is marked as invalid. * Fixed ifdef --- tmk_core/common.mk | 7 +- tmk_core/common/chibios/eeprom.c | 632 ------------------------------ tmk_core/common/chibios/eeprom_stm32.c | 673 ++++++++++++++++++++++++++++++++ tmk_core/common/chibios/eeprom_stm32.h | 89 +++++ tmk_core/common/chibios/eeprom_teensy.c | 632 ++++++++++++++++++++++++++++++ tmk_core/common/chibios/flash_stm32.c | 180 +++++++++ tmk_core/common/chibios/flash_stm32.h | 53 +++ tmk_core/common/eeconfig.c | 11 + tmk_core/common/eeconfig.h | 16 + tmk_core/protocol/chibios/main.c | 7 + 10 files changed, 1667 insertions(+), 633 deletions(-) delete mode 100644 tmk_core/common/chibios/eeprom.c create mode 100755 tmk_core/common/chibios/eeprom_stm32.c create mode 100755 tmk_core/common/chibios/eeprom_stm32.h create mode 100644 tmk_core/common/chibios/eeprom_teensy.c create mode 100755 tmk_core/common/chibios/flash_stm32.c create mode 100755 tmk_core/common/chibios/flash_stm32.h (limited to 'tmk_core/common.mk') diff --git a/tmk_core/common.mk b/tmk_core/common.mk index fd91d29dce..319d196aec 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -31,7 +31,12 @@ endif ifeq ($(PLATFORM),CHIBIOS) TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c - TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c + ifeq ($(MCU_SERIES), STM32F3xx) + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32.c + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c + else + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_teensy.c +endif ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes) TMK_COMMON_SRC += $(CHIBIOS)/os/various/syscalls.c endif diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom.c deleted file mode 100644 index 9061b790c4..0000000000 --- a/tmk_core/common/chibios/eeprom.c +++ /dev/null @@ -1,632 +0,0 @@ -#include "ch.h" -#include "hal.h" - -#include "eeconfig.h" - -/*************************************/ -/* Hardware backend */ -/* */ -/* Code from PJRC/Teensyduino */ -/*************************************/ - -/* Teensyduino Core Library - * http://www.pjrc.com/teensy/ - * Copyright (c) 2013 PJRC.COM, LLC. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * 1. The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * 2. If the Software is incorporated into a build system that allows - * selection among a list of target devices, then similar target - * devices manufactured by PJRC.COM must be included in the list of - * target devices and selectable in the same manner. - * - * 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. - */ - - -#if defined(K20x) /* chip selection */ -/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */ - -// The EEPROM is really RAM with a hardware-based backup system to -// flash memory. Selecting a smaller size EEPROM allows more wear -// leveling, for higher write endurance. If you edit this file, -// set this to the smallest size your application can use. Also, -// due to Freescale's implementation, writing 16 or 32 bit words -// (aligned to 2 or 4 byte boundaries) has twice the endurance -// compared to writing 8 bit bytes. -// -#define EEPROM_SIZE 32 - -// Writing unaligned 16 or 32 bit data is handled automatically when -// this is defined, but at a cost of extra code size. Without this, -// any unaligned write will cause a hard fault exception! If you're -// absolutely sure all 16 and 32 bit writes will be aligned, you can -// remove the extra unnecessary code. -// -#define HANDLE_UNALIGNED_WRITES - -// Minimum EEPROM Endurance -// ------------------------ -#if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word - #define EEESIZE 0x33 -#elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word - #define EEESIZE 0x34 -#elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word - #define EEESIZE 0x35 -#elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word - #define EEESIZE 0x36 -#elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word - #define EEESIZE 0x37 -#elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word - #define EEESIZE 0x38 -#elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word - #define EEESIZE 0x39 -#endif - -/** \brief eeprom initialization - * - * FIXME: needs doc - */ -void eeprom_initialize(void) -{ - uint32_t count=0; - uint16_t do_flash_cmd[] = { - 0xf06f, 0x037f, 0x7003, 0x7803, - 0xf013, 0x0f80, 0xd0fb, 0x4770}; - uint8_t status; - - if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) { - // FlexRAM is configured as traditional RAM - // We need to reconfigure for EEPROM usage - FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command - FTFL->FCCOB4 = EEESIZE; // EEPROM Size - FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup - __disable_irq(); - // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... - (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT)); - __enable_irq(); - status = FTFL->FSTAT; - if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) { - FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)); - return; // error - } - } - // wait for eeprom to become ready (is this really necessary?) - while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { - if (++count > 20000) break; - } -} - -#define FlexRAM ((uint8_t *)0x14000000) - -/** \brief eeprom read byte - * - * FIXME: needs doc - */ -uint8_t eeprom_read_byte(const uint8_t *addr) -{ - uint32_t offset = (uint32_t)addr; - if (offset >= EEPROM_SIZE) return 0; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - return FlexRAM[offset]; -} - -/** \brief eeprom read word - * - * FIXME: needs doc - */ -uint16_t eeprom_read_word(const uint16_t *addr) -{ - uint32_t offset = (uint32_t)addr; - if (offset >= EEPROM_SIZE-1) return 0; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - return *(uint16_t *)(&FlexRAM[offset]); -} - -/** \brief eeprom read dword - * - * FIXME: needs doc - */ -uint32_t eeprom_read_dword(const uint32_t *addr) -{ - uint32_t offset = (uint32_t)addr; - if (offset >= EEPROM_SIZE-3) return 0; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - return *(uint32_t *)(&FlexRAM[offset]); -} - -/** \brief eeprom read block - * - * FIXME: needs doc - */ -void eeprom_read_block(void *buf, const void *addr, uint32_t len) -{ - uint32_t offset = (uint32_t)addr; - uint8_t *dest = (uint8_t *)buf; - uint32_t end = offset + len; - - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - if (end > EEPROM_SIZE) end = EEPROM_SIZE; - while (offset < end) { - *dest++ = FlexRAM[offset++]; - } -} - -/** \brief eeprom is ready - * - * FIXME: needs doc - */ -int eeprom_is_ready(void) -{ - return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; -} - -/** \brief flexram wait - * - * FIXME: needs doc - */ -static void flexram_wait(void) -{ - while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { - // TODO: timeout - } -} - -/** \brief eeprom_write_byte - * - * FIXME: needs doc - */ -void eeprom_write_byte(uint8_t *addr, uint8_t value) -{ - uint32_t offset = (uint32_t)addr; - - if (offset >= EEPROM_SIZE) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - if (FlexRAM[offset] != value) { - FlexRAM[offset] = value; - flexram_wait(); - } -} - -/** \brief eeprom write word - * - * FIXME: needs doc - */ -void eeprom_write_word(uint16_t *addr, uint16_t value) -{ - uint32_t offset = (uint32_t)addr; - - if (offset >= EEPROM_SIZE-1) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); -#ifdef HANDLE_UNALIGNED_WRITES - if ((offset & 1) == 0) { -#endif - if (*(uint16_t *)(&FlexRAM[offset]) != value) { - *(uint16_t *)(&FlexRAM[offset]) = value; - flexram_wait(); - } -#ifdef HANDLE_UNALIGNED_WRITES - } else { - if (FlexRAM[offset] != value) { - FlexRAM[offset] = value; - flexram_wait(); - } - if (FlexRAM[offset + 1] != (value >> 8)) { - FlexRAM[offset + 1] = value >> 8; - flexram_wait(); - } - } -#endif -} - -/** \brief eeprom write dword - * - * FIXME: needs doc - */ -void eeprom_write_dword(uint32_t *addr, uint32_t value) -{ - uint32_t offset = (uint32_t)addr; - - if (offset >= EEPROM_SIZE-3) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); -#ifdef HANDLE_UNALIGNED_WRITES - switch (offset & 3) { - case 0: -#endif - if (*(uint32_t *)(&FlexRAM[offset]) != value) { - *(uint32_t *)(&FlexRAM[offset]) = value; - flexram_wait(); - } - return; -#ifdef HANDLE_UNALIGNED_WRITES - case 2: - if (*(uint16_t *)(&FlexRAM[offset]) != value) { - *(uint16_t *)(&FlexRAM[offset]) = value; - flexram_wait(); - } - if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { - *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; - flexram_wait(); - } - return; - default: - if (FlexRAM[offset] != value) { - FlexRAM[offset] = value; - flexram_wait(); - } - if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { - *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; - flexram_wait(); - } - if (FlexRAM[offset + 3] != (value >> 24)) { - FlexRAM[offset + 3] = value >> 24; - flexram_wait(); - } - } -#endif -} - -/** \brief eeprom write block - * - * FIXME: needs doc - */ -void eeprom_write_block(const void *buf, void *addr, uint32_t len) -{ - uint32_t offset = (uint32_t)addr; - const uint8_t *src = (const uint8_t *)buf; - - if (offset >= EEPROM_SIZE) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - if (len >= EEPROM_SIZE) len = EEPROM_SIZE; - if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset; - while (len > 0) { - uint32_t lsb = offset & 3; - if (lsb == 0 && len >= 4) { - // write aligned 32 bits - uint32_t val32; - val32 = *src++; - val32 |= (*src++ << 8); - val32 |= (*src++ << 16); - val32 |= (*src++ << 24); - if (*(uint32_t *)(&FlexRAM[offset]) != val32) { - *(uint32_t *)(&FlexRAM[offset]) = val32; - flexram_wait(); - } - offset += 4; - len -= 4; - } else if ((lsb == 0 || lsb == 2) && len >= 2) { - // write aligned 16 bits - uint16_t val16; - val16 = *src++; - val16 |= (*src++ << 8); - if (*(uint16_t *)(&FlexRAM[offset]) != val16) { - *(uint16_t *)(&FlexRAM[offset]) = val16; - flexram_wait(); - } - offset += 2; - len -= 2; - } else { - // write 8 bits - uint8_t val8 = *src++; - if (FlexRAM[offset] != val8) { - FlexRAM[offset] = val8; - flexram_wait(); - } - offset++; - len--; - } - } -} - -/* -void do_flash_cmd(volatile uint8_t *fstat) -{ - *fstat = 0x80; - while ((*fstat & 0x80) == 0) ; // wait -} -00000000 : - 0: f06f 037f mvn.w r3, #127 ; 0x7f - 4: 7003 strb r3, [r0, #0] - 6: 7803 ldrb r3, [r0, #0] - 8: f013 0f80 tst.w r3, #128 ; 0x80 - c: d0fb beq.n 6 - e: 4770 bx lr -*/ - -#elif defined(KL2x) /* chip selection */ -/* Teensy LC (emulated) */ - -#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) - -extern uint32_t __eeprom_workarea_start__; -extern uint32_t __eeprom_workarea_end__; - -#define EEPROM_SIZE 128 - -static uint32_t flashend = 0; - -void eeprom_initialize(void) -{ - const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); - - do { - if (*p++ == 0xFFFF) { - flashend = (uint32_t)(p - 2); - return; - } - } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__)); - flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1); -} - -uint8_t eeprom_read_byte(const uint8_t *addr) -{ - uint32_t offset = (uint32_t)addr; - const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); - const uint16_t *end = (const uint16_t *)((uint32_t)flashend); - uint16_t val; - uint8_t data=0xFF; - - if (!end) { - eeprom_initialize(); - end = (const uint16_t *)((uint32_t)flashend); - } - if (offset < EEPROM_SIZE) { - while (p <= end) { - val = *p++; - if ((val & 255) == offset) data = val >> 8; - } - } - return data; -} - -static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) -{ - // with great power comes great responsibility.... - uint32_t stat; - *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC); - *(uint32_t *)&(FTFA->FCCOB7) = data; - __disable_irq(); - (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT)); - __enable_irq(); - stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL); - if (stat) { - FTFA->FSTAT = stat; - } - MCM->PLACR |= MCM_PLACR_CFCC; -} - -void eeprom_write_byte(uint8_t *addr, uint8_t data) -{ - uint32_t offset = (uint32_t)addr; - const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend); - uint32_t i, val, flashaddr; - uint16_t do_flash_cmd[] = { - 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770}; - uint8_t buf[EEPROM_SIZE]; - - if (offset >= EEPROM_SIZE) return; - if (!end) { - eeprom_initialize(); - end = (const uint16_t *)((uint32_t)flashend); - } - if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) { - val = (data << 8) | offset; - flashaddr = (uint32_t)end; - flashend = flashaddr; - if ((flashaddr & 2) == 0) { - val |= 0xFFFF0000; - } else { - val <<= 16; - val |= 0x0000FFFF; - } - flash_write(do_flash_cmd, flashaddr, val); - } else { - for (i=0; i < EEPROM_SIZE; i++) { - buf[i] = 0xFF; - } - val = 0; - for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) { - val = *p; - if ((val & 255) < EEPROM_SIZE) { - buf[val & 255] = val >> 8; - } - } - buf[offset] = data; - for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) { - *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr; - __disable_irq(); - (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT)); - __enable_irq(); - val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);; - if (val) FTFA->FSTAT = val; - MCM->PLACR |= MCM_PLACR_CFCC; - } - flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); - for (i=0; i < EEPROM_SIZE; i++) { - if (buf[i] == 0xFF) continue; - if ((flashaddr & 2) == 0) { - val = (buf[i] << 8) | i; - } else { - val = val | (buf[i] << 24) | (i << 16); - flash_write(do_flash_cmd, flashaddr, val); - } - flashaddr += 2; - } - flashend = flashaddr; - if ((flashaddr & 2)) { - val |= 0xFFFF0000; - flash_write(do_flash_cmd, flashaddr, val); - } - } -} - -/* -void do_flash_cmd(volatile uint8_t *fstat) -{ - *fstat = 0x80; - while ((*fstat & 0x80) == 0) ; // wait -} -00000000 : - 0: 2380 movs r3, #128 ; 0x80 - 2: 7003 strb r3, [r0, #0] - 4: 7803 ldrb r3, [r0, #0] - 6: b25b sxtb r3, r3 - 8: 2b00 cmp r3, #0 - a: dafb bge.n 4 - c: 4770 bx lr -*/ - - -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++); - } -} - -int eeprom_is_ready(void) -{ - return 1; -} - -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++); - } -} - -#else -// No EEPROM supported, so emulate it - -#define EEPROM_SIZE 32 -static uint8_t buffer[EEPROM_SIZE]; - -uint8_t eeprom_read_byte(const uint8_t *addr) { - uint32_t offset = (uint32_t)addr; - return buffer[offset]; -} - -void eeprom_write_byte(uint8_t *addr, uint8_t value) { - uint32_t offset = (uint32_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++); - } -} - -#endif /* chip selection */ -// The update functions just calls write for now, but could probably be optimized - -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/chibios/eeprom_stm32.c b/tmk_core/common/chibios/eeprom_stm32.c new file mode 100755 index 0000000000..3c19451223 --- /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 (Address == 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..d06d302665 --- /dev/null +++ b/tmk_core/common/chibios/eeprom_stm32.h @@ -0,0 +1,89 @@ +/* + * 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 +#define MCU_STM32F303CC + +#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 + 250 * 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_teensy.c b/tmk_core/common/chibios/eeprom_teensy.c new file mode 100644 index 0000000000..9061b790c4 --- /dev/null +++ b/tmk_core/common/chibios/eeprom_teensy.c @@ -0,0 +1,632 @@ +#include "ch.h" +#include "hal.h" + +#include "eeconfig.h" + +/*************************************/ +/* Hardware backend */ +/* */ +/* Code from PJRC/Teensyduino */ +/*************************************/ + +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * 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. + */ + + +#if defined(K20x) /* chip selection */ +/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */ + +// The EEPROM is really RAM with a hardware-based backup system to +// flash memory. Selecting a smaller size EEPROM allows more wear +// leveling, for higher write endurance. If you edit this file, +// set this to the smallest size your application can use. Also, +// due to Freescale's implementation, writing 16 or 32 bit words +// (aligned to 2 or 4 byte boundaries) has twice the endurance +// compared to writing 8 bit bytes. +// +#define EEPROM_SIZE 32 + +// Writing unaligned 16 or 32 bit data is handled automatically when +// this is defined, but at a cost of extra code size. Without this, +// any unaligned write will cause a hard fault exception! If you're +// absolutely sure all 16 and 32 bit writes will be aligned, you can +// remove the extra unnecessary code. +// +#define HANDLE_UNALIGNED_WRITES + +// Minimum EEPROM Endurance +// ------------------------ +#if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word + #define EEESIZE 0x33 +#elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word + #define EEESIZE 0x34 +#elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word + #define EEESIZE 0x35 +#elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word + #define EEESIZE 0x36 +#elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word + #define EEESIZE 0x37 +#elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word + #define EEESIZE 0x38 +#elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word + #define EEESIZE 0x39 +#endif + +/** \brief eeprom initialization + * + * FIXME: needs doc + */ +void eeprom_initialize(void) +{ + uint32_t count=0; + uint16_t do_flash_cmd[] = { + 0xf06f, 0x037f, 0x7003, 0x7803, + 0xf013, 0x0f80, 0xd0fb, 0x4770}; + uint8_t status; + + if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) { + // FlexRAM is configured as traditional RAM + // We need to reconfigure for EEPROM usage + FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command + FTFL->FCCOB4 = EEESIZE; // EEPROM Size + FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup + __disable_irq(); + // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... + (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT)); + __enable_irq(); + status = FTFL->FSTAT; + if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) { + FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)); + return; // error + } + } + // wait for eeprom to become ready (is this really necessary?) + while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { + if (++count > 20000) break; + } +} + +#define FlexRAM ((uint8_t *)0x14000000) + +/** \brief eeprom read byte + * + * FIXME: needs doc + */ +uint8_t eeprom_read_byte(const uint8_t *addr) +{ + uint32_t offset = (uint32_t)addr; + if (offset >= EEPROM_SIZE) return 0; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + return FlexRAM[offset]; +} + +/** \brief eeprom read word + * + * FIXME: needs doc + */ +uint16_t eeprom_read_word(const uint16_t *addr) +{ + uint32_t offset = (uint32_t)addr; + if (offset >= EEPROM_SIZE-1) return 0; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + return *(uint16_t *)(&FlexRAM[offset]); +} + +/** \brief eeprom read dword + * + * FIXME: needs doc + */ +uint32_t eeprom_read_dword(const uint32_t *addr) +{ + uint32_t offset = (uint32_t)addr; + if (offset >= EEPROM_SIZE-3) return 0; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + return *(uint32_t *)(&FlexRAM[offset]); +} + +/** \brief eeprom read block + * + * FIXME: needs doc + */ +void eeprom_read_block(void *buf, const void *addr, uint32_t len) +{ + uint32_t offset = (uint32_t)addr; + uint8_t *dest = (uint8_t *)buf; + uint32_t end = offset + len; + + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + if (end > EEPROM_SIZE) end = EEPROM_SIZE; + while (offset < end) { + *dest++ = FlexRAM[offset++]; + } +} + +/** \brief eeprom is ready + * + * FIXME: needs doc + */ +int eeprom_is_ready(void) +{ + return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; +} + +/** \brief flexram wait + * + * FIXME: needs doc + */ +static void flexram_wait(void) +{ + while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { + // TODO: timeout + } +} + +/** \brief eeprom_write_byte + * + * FIXME: needs doc + */ +void eeprom_write_byte(uint8_t *addr, uint8_t value) +{ + uint32_t offset = (uint32_t)addr; + + if (offset >= EEPROM_SIZE) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + if (FlexRAM[offset] != value) { + FlexRAM[offset] = value; + flexram_wait(); + } +} + +/** \brief eeprom write word + * + * FIXME: needs doc + */ +void eeprom_write_word(uint16_t *addr, uint16_t value) +{ + uint32_t offset = (uint32_t)addr; + + if (offset >= EEPROM_SIZE-1) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); +#ifdef HANDLE_UNALIGNED_WRITES + if ((offset & 1) == 0) { +#endif + if (*(uint16_t *)(&FlexRAM[offset]) != value) { + *(uint16_t *)(&FlexRAM[offset]) = value; + flexram_wait(); + } +#ifdef HANDLE_UNALIGNED_WRITES + } else { + if (FlexRAM[offset] != value) { + FlexRAM[offset] = value; + flexram_wait(); + } + if (FlexRAM[offset + 1] != (value >> 8)) { + FlexRAM[offset + 1] = value >> 8; + flexram_wait(); + } + } +#endif +} + +/** \brief eeprom write dword + * + * FIXME: needs doc + */ +void eeprom_write_dword(uint32_t *addr, uint32_t value) +{ + uint32_t offset = (uint32_t)addr; + + if (offset >= EEPROM_SIZE-3) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); +#ifdef HANDLE_UNALIGNED_WRITES + switch (offset & 3) { + case 0: +#endif + if (*(uint32_t *)(&FlexRAM[offset]) != value) { + *(uint32_t *)(&FlexRAM[offset]) = value; + flexram_wait(); + } + return; +#ifdef HANDLE_UNALIGNED_WRITES + case 2: + if (*(uint16_t *)(&FlexRAM[offset]) != value) { + *(uint16_t *)(&FlexRAM[offset]) = value; + flexram_wait(); + } + if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { + *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; + flexram_wait(); + } + return; + default: + if (FlexRAM[offset] != value) { + FlexRAM[offset] = value; + flexram_wait(); + } + if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { + *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; + flexram_wait(); + } + if (FlexRAM[offset + 3] != (value >> 24)) { + FlexRAM[offset + 3] = value >> 24; + flexram_wait(); + } + } +#endif +} + +/** \brief eeprom write block + * + * FIXME: needs doc + */ +void eeprom_write_block(const void *buf, void *addr, uint32_t len) +{ + uint32_t offset = (uint32_t)addr; + const uint8_t *src = (const uint8_t *)buf; + + if (offset >= EEPROM_SIZE) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + if (len >= EEPROM_SIZE) len = EEPROM_SIZE; + if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset; + while (len > 0) { + uint32_t lsb = offset & 3; + if (lsb == 0 && len >= 4) { + // write aligned 32 bits + uint32_t val32; + val32 = *src++; + val32 |= (*src++ << 8); + val32 |= (*src++ << 16); + val32 |= (*src++ << 24); + if (*(uint32_t *)(&FlexRAM[offset]) != val32) { + *(uint32_t *)(&FlexRAM[offset]) = val32; + flexram_wait(); + } + offset += 4; + len -= 4; + } else if ((lsb == 0 || lsb == 2) && len >= 2) { + // write aligned 16 bits + uint16_t val16; + val16 = *src++; + val16 |= (*src++ << 8); + if (*(uint16_t *)(&FlexRAM[offset]) != val16) { + *(uint16_t *)(&FlexRAM[offset]) = val16; + flexram_wait(); + } + offset += 2; + len -= 2; + } else { + // write 8 bits + uint8_t val8 = *src++; + if (FlexRAM[offset] != val8) { + FlexRAM[offset] = val8; + flexram_wait(); + } + offset++; + len--; + } + } +} + +/* +void do_flash_cmd(volatile uint8_t *fstat) +{ + *fstat = 0x80; + while ((*fstat & 0x80) == 0) ; // wait +} +00000000 : + 0: f06f 037f mvn.w r3, #127 ; 0x7f + 4: 7003 strb r3, [r0, #0] + 6: 7803 ldrb r3, [r0, #0] + 8: f013 0f80 tst.w r3, #128 ; 0x80 + c: d0fb beq.n 6 + e: 4770 bx lr +*/ + +#elif defined(KL2x) /* chip selection */ +/* Teensy LC (emulated) */ + +#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) + +extern uint32_t __eeprom_workarea_start__; +extern uint32_t __eeprom_workarea_end__; + +#define EEPROM_SIZE 128 + +static uint32_t flashend = 0; + +void eeprom_initialize(void) +{ + const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); + + do { + if (*p++ == 0xFFFF) { + flashend = (uint32_t)(p - 2); + return; + } + } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__)); + flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1); +} + +uint8_t eeprom_read_byte(const uint8_t *addr) +{ + uint32_t offset = (uint32_t)addr; + const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); + const uint16_t *end = (const uint16_t *)((uint32_t)flashend); + uint16_t val; + uint8_t data=0xFF; + + if (!end) { + eeprom_initialize(); + end = (const uint16_t *)((uint32_t)flashend); + } + if (offset < EEPROM_SIZE) { + while (p <= end) { + val = *p++; + if ((val & 255) == offset) data = val >> 8; + } + } + return data; +} + +static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) +{ + // with great power comes great responsibility.... + uint32_t stat; + *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC); + *(uint32_t *)&(FTFA->FCCOB7) = data; + __disable_irq(); + (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT)); + __enable_irq(); + stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL); + if (stat) { + FTFA->FSTAT = stat; + } + MCM->PLACR |= MCM_PLACR_CFCC; +} + +void eeprom_write_byte(uint8_t *addr, uint8_t data) +{ + uint32_t offset = (uint32_t)addr; + const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend); + uint32_t i, val, flashaddr; + uint16_t do_flash_cmd[] = { + 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770}; + uint8_t buf[EEPROM_SIZE]; + + if (offset >= EEPROM_SIZE) return; + if (!end) { + eeprom_initialize(); + end = (const uint16_t *)((uint32_t)flashend); + } + if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) { + val = (data << 8) | offset; + flashaddr = (uint32_t)end; + flashend = flashaddr; + if ((flashaddr & 2) == 0) { + val |= 0xFFFF0000; + } else { + val <<= 16; + val |= 0x0000FFFF; + } + flash_write(do_flash_cmd, flashaddr, val); + } else { + for (i=0; i < EEPROM_SIZE; i++) { + buf[i] = 0xFF; + } + val = 0; + for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) { + val = *p; + if ((val & 255) < EEPROM_SIZE) { + buf[val & 255] = val >> 8; + } + } + buf[offset] = data; + for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) { + *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr; + __disable_irq(); + (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT)); + __enable_irq(); + val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);; + if (val) FTFA->FSTAT = val; + MCM->PLACR |= MCM_PLACR_CFCC; + } + flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); + for (i=0; i < EEPROM_SIZE; i++) { + if (buf[i] == 0xFF) continue; + if ((flashaddr & 2) == 0) { + val = (buf[i] << 8) | i; + } else { + val = val | (buf[i] << 24) | (i << 16); + flash_write(do_flash_cmd, flashaddr, val); + } + flashaddr += 2; + } + flashend = flashaddr; + if ((flashaddr & 2)) { + val |= 0xFFFF0000; + flash_write(do_flash_cmd, flashaddr, val); + } + } +} + +/* +void do_flash_cmd(volatile uint8_t *fstat) +{ + *fstat = 0x80; + while ((*fstat & 0x80) == 0) ; // wait +} +00000000 : + 0: 2380 movs r3, #128 ; 0x80 + 2: 7003 strb r3, [r0, #0] + 4: 7803 ldrb r3, [r0, #0] + 6: b25b sxtb r3, r3 + 8: 2b00 cmp r3, #0 + a: dafb bge.n 4 + c: 4770 bx lr +*/ + + +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++); + } +} + +int eeprom_is_ready(void) +{ + return 1; +} + +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++); + } +} + +#else +// No EEPROM supported, so emulate it + +#define EEPROM_SIZE 32 +static uint8_t buffer[EEPROM_SIZE]; + +uint8_t eeprom_read_byte(const uint8_t *addr) { + uint32_t offset = (uint32_t)addr; + return buffer[offset]; +} + +void eeprom_write_byte(uint8_t *addr, uint8_t value) { + uint32_t offset = (uint32_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++); + } +} + +#endif /* chip selection */ +// The update functions just calls write for now, but could probably be optimized + +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/chibios/flash_stm32.c b/tmk_core/common/chibios/flash_stm32.c new file mode 100755 index 0000000000..e7199ac7b1 --- /dev/null +++ b/tmk_core/common/chibios/flash_stm32.c @@ -0,0 +1,180 @@ +/* + * 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 + */ + +#define STM32F303xC + +#include "stm32f3xx.h" +#include "flash_stm32.h" + +#define FLASH_KEY1 ((uint32_t)0x45670123) +#define FLASH_KEY2 ((uint32_t)0xCDEF89AB) + +/* 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/eeconfig.c b/tmk_core/common/eeconfig.c index 3e5987ee3b..35de574a96 100644 --- a/tmk_core/common/eeconfig.c +++ b/tmk_core/common/eeconfig.c @@ -3,12 +3,20 @@ #include "eeprom.h" #include "eeconfig.h" +#ifdef STM32F303xC +#include "hal.h" +#include "eeprom_stm32.h" +#endif + /** \brief eeconfig initialization * * FIXME: needs doc */ void eeconfig_init(void) { +#ifdef STM32F303xC + EEPROM_format(); +#endif eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); eeprom_update_byte(EECONFIG_DEBUG, 0); eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0); @@ -43,6 +51,9 @@ void eeconfig_enable(void) */ void eeconfig_disable(void) { +#ifdef STM32F303xC + EEPROM_format(); +#endif eeprom_update_word(EECONFIG_MAGIC, 0xFFFF); } diff --git a/tmk_core/common/eeconfig.h b/tmk_core/common/eeconfig.h index 1397a90c79..fa498df48c 100644 --- a/tmk_core/common/eeconfig.h +++ b/tmk_core/common/eeconfig.h @@ -25,6 +25,7 @@ along with this program. If not, see . #define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEED /* eeprom parameteter address */ +#if !defined(STM32F303xC) #define EECONFIG_MAGIC (uint16_t *)0 #define EECONFIG_DEBUG (uint8_t *)2 #define EECONFIG_DEFAULT_LAYER (uint8_t *)3 @@ -38,6 +39,21 @@ along with this program. If not, see . // EEHANDS for two handed boards #define EECONFIG_HANDEDNESS (uint8_t *)14 +#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 +#endif /* debug bit */ #define EECONFIG_DEBUG_ENABLE (1<<0) diff --git a/tmk_core/protocol/chibios/main.c b/tmk_core/protocol/chibios/main.c index f2abc438d4..568c1edb28 100644 --- a/tmk_core/protocol/chibios/main.c +++ b/tmk_core/protocol/chibios/main.c @@ -44,6 +44,9 @@ #ifdef MIDI_ENABLE #include "qmk_midi.h" #endif +#ifdef STM32F303xC +#include "eeprom_stm32.h" +#endif #include "suspend.h" #include "wait.h" @@ -109,6 +112,10 @@ int main(void) { halInit(); chSysInit(); +#ifdef STM32F303xC + EEPROM_init(); +#endif + // TESTING // chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); -- cgit v1.2.3 From ab91e07753720f8114d6c427139a1436e6efa3ce Mon Sep 17 00:00:00 2001 From: patrickmt <40182064+patrickmt@users.noreply.github.com> Date: Tue, 9 Oct 2018 15:14:13 -0400 Subject: Massdrop keyboards console device support for hid_listen Added hid_listen USB device for arm_atsam USB protocol. Debug printing is now done through the console device (CONSOLE_ENABLE = yes) rather than the virtser device, for viewing in hid_listen. Function dpf(...) renamed to CDC_printf(...) and should now be called directly if intending to print to the virtual serial device. --- tmk_core/common.mk | 1 + tmk_core/common/arm_atsam/printf.c | 66 ++++++++++ tmk_core/common/arm_atsam/printf.h | 7 +- tmk_core/protocol/arm_atsam/main_arm_atsam.c | 12 +- tmk_core/protocol/arm_atsam/usb/conf_usb.h | 5 + tmk_core/protocol/arm_atsam/usb/main_usb.c | 14 ++ tmk_core/protocol/arm_atsam/usb/udi_cdc.c | 4 +- tmk_core/protocol/arm_atsam/usb/udi_cdc.h | 1 + tmk_core/protocol/arm_atsam/usb/udi_device_conf.h | 88 +++++++++++-- tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c | 146 +++++++++++++++++++++ tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h | 11 ++ tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c | 6 + tmk_core/protocol/arm_atsam/usb/usb_main.h | 6 + 13 files changed, 347 insertions(+), 20 deletions(-) create mode 100644 tmk_core/common/arm_atsam/printf.c (limited to 'tmk_core/common.mk') diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 319d196aec..4a0f7dcf9a 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -43,6 +43,7 @@ endif endif ifeq ($(PLATFORM),ARM_ATSAM) + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c endif diff --git a/tmk_core/common/arm_atsam/printf.c b/tmk_core/common/arm_atsam/printf.c new file mode 100644 index 0000000000..d49d234de2 --- /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 . +*/ + +#ifdef CONSOLE_PRINT + +#include "samd51j18a.h" +#include "arm_atsam_protocol.h" +#include "printf.h" +#include +#include + +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_PRINT diff --git a/tmk_core/common/arm_atsam/printf.h b/tmk_core/common/arm_atsam/printf.h index 3206b40bdb..1f1c2280b5 100644 --- a/tmk_core/common/arm_atsam/printf.h +++ b/tmk_core/common/arm_atsam/printf.h @@ -1,8 +1,11 @@ #ifndef _PRINTF_H_ #define _PRINTF_H_ -int dpf(const char *_Format, ...); -#define __xprintf dpf +#define CONSOLE_PRINTBUF_SIZE 512 + +void console_printf(char *fmt, ...); + +#define __xprintf console_printf #endif //_PRINTF_H_ diff --git a/tmk_core/protocol/arm_atsam/main_arm_atsam.c b/tmk_core/protocol/arm_atsam/main_arm_atsam.c index 676dac4ea3..54d056a14e 100644 --- a/tmk_core/protocol/arm_atsam/main_arm_atsam.c +++ b/tmk_core/protocol/arm_atsam/main_arm_atsam.c @@ -276,9 +276,9 @@ int main(void) host_set_driver(&arm_atsam_driver); -#ifdef VIRTSER_ENABLE +#ifdef CONSOLE_ENABLE uint64_t next_print = 0; -#endif //VIRTSER_ENABLE +#endif //CONSOLE_ENABLE v_5v_avg = adc_get(ADC_5V); @@ -290,15 +290,17 @@ int main(void) main_subtasks(); //Note these tasks will also be run while waiting for USB keyboard polling intervals -#ifdef VIRTSER_ENABLE +#ifdef CONSOLE_ENABLE if (CLK_get_ms() > next_print) { next_print = CLK_get_ms() + 250; - dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n",v_5v,v_5v_avg,v_5v_avg-V5_LOW,v_5v_avg-V5_HIGH,gcr_actual,gcr_desired); + //Add any debug information here that you want to see very often + //dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n", v_5v, v_5v_avg, v_5v_avg - V5_LOW, v_5v_avg - V5_HIGH, gcr_actual, gcr_desired); } -#endif //VIRTSER_ENABLE +#endif //CONSOLE_ENABLE } + return 1; } diff --git a/tmk_core/protocol/arm_atsam/usb/conf_usb.h b/tmk_core/protocol/arm_atsam/usb/conf_usb.h index 8f0f472687..c91caffe02 100644 --- a/tmk_core/protocol/arm_atsam/usb/conf_usb.h +++ b/tmk_core/protocol/arm_atsam/usb/conf_usb.h @@ -134,6 +134,11 @@ #define UDI_HID_EXK_DISABLE_EXT() main_exk_disable() #endif +#ifdef CON +#define UDI_HID_CON_ENABLE_EXT() main_con_enable() +#define UDI_HID_CON_DISABLE_EXT() main_con_disable() +#endif + #ifdef MOU #define UDI_HID_MOU_ENABLE_EXT() main_mou_enable() #define UDI_HID_MOU_DISABLE_EXT() main_mou_disable() diff --git a/tmk_core/protocol/arm_atsam/usb/main_usb.c b/tmk_core/protocol/arm_atsam/usb/main_usb.c index e943cbcdcd..0f676ab639 100644 --- a/tmk_core/protocol/arm_atsam/usb/main_usb.c +++ b/tmk_core/protocol/arm_atsam/usb/main_usb.c @@ -88,6 +88,20 @@ void main_exk_disable(void) } #endif +#ifdef CON +volatile bool main_b_con_enable = false; +bool main_con_enable(void) +{ + main_b_con_enable = true; + return true; +} + +void main_con_disable(void) +{ + main_b_con_enable = false; +} +#endif + #ifdef MOU volatile bool main_b_mou_enable = false; bool main_mou_enable(void) diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc.c b/tmk_core/protocol/arm_atsam/usb/udi_cdc.c index 15f0f760cc..5f3c289e81 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_cdc.c +++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc.c @@ -1260,7 +1260,7 @@ uint32_t CDC_print(char *printbuf) char printbuf[CDC_PRINTBUF_SIZE]; -int dpf(const char *_Format, ...) +int CDC_printf(const char *_Format, ...) { va_list va; //Variable argument list variable int result; @@ -1356,7 +1356,7 @@ uint32_t CDC_print(char *printbuf) return 0; } -int dpf(const char *_Format, ...) +int CDC_printf(const char *_Format, ...) { return 0; } diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc.h b/tmk_core/protocol/arm_atsam/usb/udi_cdc.h index e134cf2360..86077ce53b 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_cdc.h +++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc.h @@ -365,6 +365,7 @@ extern inbuf_t inbuf; #endif //CDC uint32_t CDC_print(char *printbuf); +int CDC_printf(const char *_Format, ...); uint32_t CDC_input(void); void CDC_init(void); diff --git a/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h b/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h index c787262340..1e82b9eccb 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h +++ b/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h @@ -44,10 +44,10 @@ along with this program. If not, see . #define RAW #endif -//#define CONSOLE_ENABLE //deferred implementation -//#ifdef CONSOLE_ENABLE -//#define CON -//#endif +//#define CONSOLE_ENABLE //rules.mk +#ifdef CONSOLE_ENABLE +#define CON +#endif //#define NKRO_ENABLE //rules.mk #ifdef NKRO_ENABLE @@ -110,8 +110,9 @@ along with this program. If not, see . #endif #ifdef CON -#define CONSOLE_INTERFACE NEXT_INTERFACE_4 -#define NEXT_INTERFACE_5 (CONSOLE_INTERFACE + 1) +#define CON_INTERFACE NEXT_INTERFACE_4 +#define NEXT_INTERFACE_5 (CON_INTERFACE + 1) +#define UDI_HID_CON_IFACE_NUMBER CON_INTERFACE #else #define NEXT_INTERFACE_5 NEXT_INTERFACE_4 #endif @@ -211,11 +212,16 @@ along with this program. If not, see . #endif #ifdef CON -#define CONSOLE_IN_EPNUM NEXT_IN_EPNUM_4 -#define NEXT_IN_EPNUM_5 (CONSOLE_IN_EPNUM + 1) -#define CONSOLE_OUT_EPNUM NEXT_OUT_EPNUM_1 -#define NEXT_OUT_EPNUM_2 (CONSOLE_OUT_EPNUM + 1) -#define CONSOLE_POLLING_INTERVAL 1 +#define CON_IN_EPNUM NEXT_IN_EPNUM_4 +#define UDI_HID_CON_EP_IN CON_IN_EPNUM +#define NEXT_IN_EPNUM_5 (CON_IN_EPNUM + 1) +#define CON_OUT_EPNUM NEXT_OUT_EPNUM_1 +#define UDI_HID_CON_EP_OUT CON_OUT_EPNUM +#define NEXT_OUT_EPNUM_2 (CON_OUT_EPNUM + 1) +#define CON_POLLING_INTERVAL 1 +#ifndef UDI_HID_CON_STRING_ID +#define UDI_HID_CON_STRING_ID 0 +#endif #else #define NEXT_IN_EPNUM_5 NEXT_IN_EPNUM_4 #define NEXT_OUT_EPNUM_2 NEXT_OUT_EPNUM_1 @@ -558,6 +564,66 @@ COMPILER_PACK_RESET() #endif //RAW +// ********************************************************************** +// CON Descriptor structure and content +// ********************************************************************** +#ifdef CON + +COMPILER_PACK_SET(1) + +typedef struct { + usb_iface_desc_t iface; + usb_hid_descriptor_t hid; + usb_ep_desc_t ep_out; + usb_ep_desc_t ep_in; +} udi_hid_con_desc_t; + +typedef struct { + uint8_t array[34]; +} udi_hid_con_report_desc_t; + +#define UDI_HID_CON_DESC {\ + .iface.bLength = sizeof(usb_iface_desc_t),\ + .iface.bDescriptorType = USB_DT_INTERFACE,\ + .iface.bInterfaceNumber = UDI_HID_CON_IFACE_NUMBER,\ + .iface.bAlternateSetting = 0,\ + .iface.bNumEndpoints = 2,\ + .iface.bInterfaceClass = HID_CLASS,\ + .iface.bInterfaceSubClass = HID_SUB_CLASS_NOBOOT,\ + .iface.bInterfaceProtocol = HID_SUB_CLASS_NOBOOT,\ + .iface.iInterface = UDI_HID_CON_STRING_ID,\ + .hid.bLength = sizeof(usb_hid_descriptor_t),\ + .hid.bDescriptorType = USB_DT_HID,\ + .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\ + .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\ + .hid.bNumDescriptors = USB_HID_NUM_DESC,\ + .hid.bRDescriptorType = USB_DT_HID_REPORT,\ + .hid.wDescriptorLength = LE16(sizeof(udi_hid_con_report_desc_t)),\ + .ep_out.bLength = sizeof(usb_ep_desc_t),\ + .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_out.bEndpointAddress = UDI_HID_CON_EP_OUT | USB_EP_DIR_OUT,\ + .ep_out.bmAttributes = USB_EP_TYPE_INTERRUPT,\ + .ep_out.wMaxPacketSize = LE16(CONSOLE_EPSIZE),\ + .ep_out.bInterval = CON_POLLING_INTERVAL,\ + .ep_in.bLength = sizeof(usb_ep_desc_t),\ + .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ + .ep_in.bEndpointAddress = UDI_HID_CON_EP_IN | USB_EP_DIR_IN,\ + .ep_in.bmAttributes = USB_EP_TYPE_INTERRUPT,\ + .ep_in.wMaxPacketSize = LE16(CONSOLE_EPSIZE),\ + .ep_in.bInterval = CON_POLLING_INTERVAL,\ +} + +#define UDI_HID_CON_REPORT_SIZE CONSOLE_EPSIZE + +extern uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE]; + +//report buffer +extern uint8_t udi_hid_con_report[UDI_HID_CON_REPORT_SIZE]; + +COMPILER_PACK_RESET() + +#endif //CON + // ********************************************************************** // CDC Descriptor structure and content // ********************************************************************** diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c index 1a6f7905e6..18f9784ae6 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c @@ -843,3 +843,149 @@ static void udi_hid_raw_setreport_valid(void) } #endif //RAW + +//******************************************************************************************** +// CON +//******************************************************************************************** +#ifdef CON + +bool udi_hid_con_enable(void); +void udi_hid_con_disable(void); +bool udi_hid_con_setup(void); +uint8_t udi_hid_con_getsetting(void); + +UDC_DESC_STORAGE udi_api_t udi_api_hid_con = { + .enable = (bool(*)(void))udi_hid_con_enable, + .disable = (void (*)(void))udi_hid_con_disable, + .setup = (bool(*)(void))udi_hid_con_setup, + .getsetting = (uint8_t(*)(void))udi_hid_con_getsetting, + .sof_notify = NULL, +}; + +COMPILER_WORD_ALIGNED +static uint8_t udi_hid_con_rate; + +COMPILER_WORD_ALIGNED +static uint8_t udi_hid_con_protocol; + +COMPILER_WORD_ALIGNED +uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE]; + +bool udi_hid_con_b_report_valid; + +COMPILER_WORD_ALIGNED +uint8_t udi_hid_con_report[UDI_HID_CON_REPORT_SIZE]; + +volatile bool udi_hid_con_b_report_trans_ongoing; + +COMPILER_WORD_ALIGNED +static uint8_t udi_hid_con_report_trans[UDI_HID_CON_REPORT_SIZE]; + +COMPILER_WORD_ALIGNED +UDC_DESC_STORAGE udi_hid_con_report_desc_t udi_hid_con_report_desc = { + { + 0x06, 0x31, 0xFF, // Vendor Page (PJRC Teensy compatible) + 0x09, 0x74, // Vendor Usage (PJRC Teensy compatible) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x75, // Usage (Vendor) + 0x15, 0x00, // Logical Minimum (0x00) + 0x26, 0xFF, 0x00, // Logical Maximum (0x00FF) + 0x95, CONSOLE_EPSIZE, // Report Count + 0x75, 0x08, // Report Size (8) + 0x81, 0x02, // Input (Data) + 0x09, 0x76, // Usage (Vendor) + 0x15, 0x00, // Logical Minimum (0x00) + 0x26, 0xFF, 0x00, // Logical Maximum (0x00FF) + 0x95, CONSOLE_EPSIZE, // Report Count + 0x75, 0x08, // Report Size (8) + 0x91, 0x02, // Output (Data) + 0xC0, // End Collection + } +}; + +static bool udi_hid_con_setreport(void); +static void udi_hid_con_setreport_valid(void); + +static void udi_hid_con_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep); + +bool udi_hid_con_enable(void) +{ + // Initialize internal values + udi_hid_con_rate = 0; + udi_hid_con_protocol = 0; + udi_hid_con_b_report_trans_ongoing = false; + memset(udi_hid_con_report, 0, UDI_HID_CON_REPORT_SIZE); + udi_hid_con_b_report_valid = false; + return UDI_HID_CON_ENABLE_EXT(); +} + +void udi_hid_con_disable(void) +{ + UDI_HID_CON_DISABLE_EXT(); +} + +bool udi_hid_con_setup(void) +{ + return udi_hid_setup(&udi_hid_con_rate, + &udi_hid_con_protocol, + (uint8_t *) &udi_hid_con_report_desc, + udi_hid_con_setreport); +} + +uint8_t udi_hid_con_getsetting(void) +{ + return 0; +} + +static bool udi_hid_con_setreport(void) +{ + if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8)) + && (0 == (0xFF & udd_g_ctrlreq.req.wValue)) + && (UDI_HID_CON_REPORT_SIZE == udd_g_ctrlreq.req.wLength)) { + udd_g_ctrlreq.payload = udi_hid_con_report_set; + udd_g_ctrlreq.callback = udi_hid_con_setreport_valid; + udd_g_ctrlreq.payload_size = UDI_HID_CON_REPORT_SIZE; + return true; + } + return false; +} + +bool udi_hid_con_send_report(void) +{ + if (!main_b_con_enable) { + return false; + } + + if (udi_hid_con_b_report_trans_ongoing) { + return false; + } + + memcpy(udi_hid_con_report_trans, udi_hid_con_report,UDI_HID_CON_REPORT_SIZE); + udi_hid_con_b_report_valid = false; + udi_hid_con_b_report_trans_ongoing = + udd_ep_run(UDI_HID_CON_EP_IN | USB_EP_DIR_IN, + false, + udi_hid_con_report_trans, + UDI_HID_CON_REPORT_SIZE, + udi_hid_con_report_sent); + + return udi_hid_con_b_report_trans_ongoing; +} + +static void udi_hid_con_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep) +{ + UNUSED(status); + UNUSED(nb_sent); + UNUSED(ep); + udi_hid_con_b_report_trans_ongoing = false; + if (udi_hid_con_b_report_valid) { + udi_hid_con_send_report(); + } +} + +static void udi_hid_con_setreport_valid(void) +{ + +} + +#endif //CON diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h index babfdb7a78..e442919a9b 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h @@ -85,6 +85,17 @@ extern uint8_t udi_hid_exk_report_set; bool udi_hid_exk_send_report(void); #endif //EXK +//******************************************************************************************** +// CON Console +//******************************************************************************************** +#ifdef CON +extern UDC_DESC_STORAGE udi_api_t udi_api_hid_con; +extern bool udi_hid_con_b_report_valid; +extern uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE]; +extern volatile bool udi_hid_con_b_report_trans_ongoing; +bool udi_hid_con_send_report(void); +#endif //CON + //******************************************************************************************** // MOU Mouse //******************************************************************************************** diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c index 16bd4e514c..2d6e35e254 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c @@ -134,6 +134,9 @@ UDC_DESC_STORAGE udc_desc_t udc_desc = { #ifdef EXK .hid_exk = UDI_HID_EXK_DESC, #endif +#ifdef CON + .hid_con = UDI_HID_CON_DESC, +#endif #ifdef NKRO .hid_nkro = UDI_HID_NKRO_DESC, #endif @@ -155,6 +158,9 @@ UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = { #ifdef EXK &udi_api_hid_exk, #endif + #ifdef CON + &udi_api_hid_con, + #endif #ifdef NKRO &udi_api_hid_nkro, #endif diff --git a/tmk_core/protocol/arm_atsam/usb/usb_main.h b/tmk_core/protocol/arm_atsam/usb/usb_main.h index b7adaa1a72..76ced474dc 100644 --- a/tmk_core/protocol/arm_atsam/usb/usb_main.h +++ b/tmk_core/protocol/arm_atsam/usb/usb_main.h @@ -82,6 +82,12 @@ bool main_exk_enable(void); void main_exk_disable(void); #endif //EXK +#ifdef CON +extern volatile bool main_b_con_enable; +bool main_con_enable(void); +void main_con_disable(void); +#endif //CON + #ifdef MOU extern volatile bool main_b_mou_enable; bool main_mou_enable(void); -- cgit v1.2.3 From f4094930a393ec3dc597e06e95cd3365e3f8cb97 Mon Sep 17 00:00:00 2001 From: Takuya Urakawa Date: Fri, 19 Oct 2018 13:33:23 +0900 Subject: stm32f1xx EEPROM emulation (#3914) * * Add stm32f1xx EEPROM emulation * Fix eeprom update compare bug Squashed commit of the following: commit b8f248ae08cec0cd81ecbb8854d9b39221d4d573 Author: hsgw Date: Sat Sep 15 19:13:48 2018 +0900 fix EEPROM_update wrong compare commit d4ed4e6ea864e967a3e17f7edee4b0c3b4a25541 Author: hsgw Date: Sat Sep 15 17:43:47 2018 +0900 eeprom fix initialization define commit b61aa7c04d70c64df3416d63e5da08b73b6053af Author: hsgw Date: Sat Sep 15 16:33:40 2018 +0900 maybe working * Fix FLASH_KEY defines --- tmk_core/common.mk | 7 +++++++ tmk_core/common/chibios/eeprom_stm32.c | 8 ++++---- tmk_core/common/chibios/eeprom_stm32.h | 12 +++++++++--- tmk_core/common/chibios/flash_stm32.c | 24 ++++++++++++++++-------- tmk_core/common/eeconfig.c | 6 +++--- tmk_core/common/eeconfig.h | 2 +- tmk_core/protocol/chibios/main.c | 4 ++-- 7 files changed, 42 insertions(+), 21 deletions(-) (limited to 'tmk_core/common.mk') diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 4a0f7dcf9a..33bcc97b2e 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -34,6 +34,13 @@ ifeq ($(PLATFORM),CHIBIOS) ifeq ($(MCU_SERIES), STM32F3xx) TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32.c TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c + TMK_COMMON_DEFS += -DEEPROM_EMU_STM32F303xC + TMK_COMMON_DEFS += -DSTM32_EEPROM_ENABLE + else ifeq ($(MCU_SERIES), STM32F1xx) + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32.c + TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c + TMK_COMMON_DEFS += -DEEPROM_EMU_STM32F103xB + TMK_COMMON_DEFS += -DSTM32_EEPROM_ENABLE else TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_teensy.c endif diff --git a/tmk_core/common/chibios/eeprom_stm32.c b/tmk_core/common/chibios/eeprom_stm32.c index 3c19451223..a869985501 100755 --- a/tmk_core/common/chibios/eeprom_stm32.c +++ b/tmk_core/common/chibios/eeprom_stm32.c @@ -10,7 +10,7 @@ * 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 + * 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 @@ -274,7 +274,7 @@ uint16_t EE_VerifyPageFullWriteVariable(uint16_t Address, uint16_t Data) // 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 + if ((*(__IO uint32_t*)idx) == 0xFFFFFFFF) // Verify if element { // contents are 0xFFFFFFFF FlashStatus = FLASH_ProgramHalfWord(idx, Data); // Set variable data if (FlashStatus != FLASH_COMPLETE) @@ -517,7 +517,7 @@ uint16_t EEPROM_read(uint16_t Address, uint16_t *Data) // 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 @@ -574,7 +574,7 @@ uint16_t EEPROM_update(uint16_t Address, uint16_t Data) { uint16_t temp; EEPROM_read(Address, &temp); - if (Address == Data) + if (temp == Data) return EEPROM_SAME_VALUE; else return EEPROM_write(Address, Data); diff --git a/tmk_core/common/chibios/eeprom_stm32.h b/tmk_core/common/chibios/eeprom_stm32.h index 68aa14f6d4..09229530ca 100755 --- a/tmk_core/common/chibios/eeprom_stm32.h +++ b/tmk_core/common/chibios/eeprom_stm32.h @@ -10,7 +10,7 @@ * 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 + * 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 @@ -27,8 +27,14 @@ #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 -#define MCU_STM32F303CC +// 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) diff --git a/tmk_core/common/chibios/flash_stm32.c b/tmk_core/common/chibios/flash_stm32.c index e7199ac7b1..2735934844 100755 --- a/tmk_core/common/chibios/flash_stm32.c +++ b/tmk_core/common/chibios/flash_stm32.c @@ -10,19 +10,27 @@ * 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 + * 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 */ -#define STM32F303xC +#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 "stm32f3xx.h" #include "flash_stm32.h" -#define FLASH_KEY1 ((uint32_t)0x45670123) -#define FLASH_KEY2 ((uint32_t)0xCDEF89AB) +#if defined(EEPROM_EMU_STM32F103xB) + #define FLASH_SR_WRPERR FLASH_SR_WRPRTERR +#endif /* Delay definition */ #define EraseTimeout ((uint32_t)0x00000FFF) @@ -71,7 +79,7 @@ FLASH_Status FLASH_GetStatus(void) * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. */ FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) -{ +{ FLASH_Status status; /* Check for the Flash Status */ @@ -102,7 +110,7 @@ FLASH_Status FLASH_ErasePage(uint32_t Page_Address) 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 */ @@ -128,7 +136,7 @@ FLASH_Status FLASH_ErasePage(uint32_t Page_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_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. */ FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { diff --git a/tmk_core/common/eeconfig.c b/tmk_core/common/eeconfig.c index 0fec410a9c..d8bab7d2e5 100644 --- a/tmk_core/common/eeconfig.c +++ b/tmk_core/common/eeconfig.c @@ -3,7 +3,7 @@ #include "eeprom.h" #include "eeconfig.h" -#ifdef STM32F303xC +#ifdef STM32_EEPROM_ENABLE #include "hal.h" #include "eeprom_stm32.h" #endif @@ -32,7 +32,7 @@ void eeconfig_init_kb(void) { * FIXME: needs doc */ void eeconfig_init_quantum(void) { -#ifdef STM32F303xC +#ifdef STM32_EEPROM_ENABLE EEPROM_format(); #endif eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); @@ -73,7 +73,7 @@ void eeconfig_enable(void) */ void eeconfig_disable(void) { -#ifdef STM32F303xC +#ifdef STM32_EEPROM_ENABLE EEPROM_format(); #endif eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER_OFF); diff --git a/tmk_core/common/eeconfig.h b/tmk_core/common/eeconfig.h index a45cb8b12d..8d4e1d4d00 100644 --- a/tmk_core/common/eeconfig.h +++ b/tmk_core/common/eeconfig.h @@ -26,7 +26,7 @@ along with this program. If not, see . #define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF /* eeprom parameteter address */ -#if !defined(STM32F303xC) +#if !defined(STM32_EEPROM_ENABLE) #define EECONFIG_MAGIC (uint16_t *)0 #define EECONFIG_DEBUG (uint8_t *)2 #define EECONFIG_DEFAULT_LAYER (uint8_t *)3 diff --git a/tmk_core/protocol/chibios/main.c b/tmk_core/protocol/chibios/main.c index dcc6d9d076..6cceccd23c 100644 --- a/tmk_core/protocol/chibios/main.c +++ b/tmk_core/protocol/chibios/main.c @@ -44,7 +44,7 @@ #ifdef MIDI_ENABLE #include "qmk_midi.h" #endif -#ifdef STM32F303xC +#ifdef STM32_EEPROM_ENABLE #include "eeprom_stm32.h" #endif #include "suspend.h" @@ -112,7 +112,7 @@ int main(void) { halInit(); chSysInit(); -#ifdef STM32F303xC +#ifdef STM32_EEPROM_ENABLE EEPROM_init(); #endif -- cgit v1.2.3 From 4ffcacd92086870eb7a3102d54178a7af64edb0c Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sat, 27 Oct 2018 11:53:50 -0700 Subject: Add Bootmagic Lite to QMK (#4215) * Preliminary additon of bootmagic lite functionality * Cleanup code * Clean up bootmagic code * Add documentation and clean up code * Make 'lite' an option for BOOTMAGIC_ENABLE * Update Templates with note about Bootmagic Lite option * Detect Debounce variable * Make sure debounce is a non-zero number * Capitalize Bootmagic * Capitalize bootmagic * Update wording * Re-add EEPROM reset, by popular demand And add eeprom-less version to drashna userspace for his sanity * Fix spacing * Set BOOTMAGIC_ENABLE to use full/lite/off And default yes to "full" for compatibility * Add Bootmagic lite info to templates * Remove text from makefiles * Cleanup of makefile * mention yes in bootmagic docs * Wordsmitthing the docs * Fix white spaces * Readd default bootmagic setting, because it's necessary --- docs/feature_bootmagic.md | 52 +++++++++++++++++++++++++++++++++++++- quantum/quantum.c | 34 ++++++++++++++++++++++++- quantum/quantum.h | 9 +++++++ quantum/template/avr/config.h | 3 +++ quantum/template/ps2avrgb/config.h | 4 +++ tmk_core/common.mk | 14 +++++++++- users/drashna/drashna.c | 16 ++++++++++++ 7 files changed, 129 insertions(+), 3 deletions(-) (limited to 'tmk_core/common.mk') diff --git a/docs/feature_bootmagic.md b/docs/feature_bootmagic.md index 586b5d8370..20c76d9b74 100644 --- a/docs/feature_bootmagic.md +++ b/docs/feature_bootmagic.md @@ -11,7 +11,15 @@ There are three separate but related features that allow you to change the behav On some keyboards Bootmagic is disabled by default. If this is the case, it must be explicitly enabled in your `rules.mk` with: ```make -BOOTMAGIC_ENABLE = yes +BOOTMAGIC_ENABLE = full +``` + +?> You may see `yes` being used in place of `full`, and this is okay. However, `yes` is deprecated, and ideally `full` (or `lite`) ideally should be used instead. + +Additionally, you can use [Bootmagic Lite](#bootmagic-lite) (a scaled down, very basic version of Bootmagic) by adding the following to your `rules.mk` file: + +```make +BOOTMAGIC_ENABLE = lite ``` ## Hotkeys @@ -99,3 +107,45 @@ If you would like to change the hotkey assignments for Bootmagic, `#define` thes |`BOOTMAGIC_KEY_DEFAULT_LAYER_5` |`KC_5` |Make layer 5 the default layer | |`BOOTMAGIC_KEY_DEFAULT_LAYER_6` |`KC_6` |Make layer 6 the default layer | |`BOOTMAGIC_KEY_DEFAULT_LAYER_7` |`KC_7` |Make layer 7 the default layer | + +# Bootmagic Lite + +In addition to the full blown Bootmagic feature, is the Bootmagic Lite feature that only handles jumping into the bootloader. This is great for boards that don't have a physical reset button but you need a way to jump into the bootloader, and don't want to deal with the headache that Bootmagic can cause. + +To enable this version of Bootmagic, you need to enable it in your `rules.mk` with: + +```make +BOOTMAGIC_ENABLE = lite +``` + +Additionally, you may want to specify which key to use. This is especially useful for keyboards that have unusual matrices. To do so, you need to specify the row and column of the key that you want to use. Add these entries to your `config.h` file: + +```c +#define BOOTMAGIC_LITE_ROW 0 +#define BOOTMAGIC_LITE_COLUMN 1 +``` + +By default, these are set to 0 and 0, which is usually the "ESC" key on a majority of keyboards. + +And to trigger the bootloader, you hold this key down when plugging the keyboard in. Just the single key. + +## Advanced Bootmagic Lite + +The `bootmagic_lite` function is defined weakly, so that you can replace this in your code, if you need. A great example of this is the Zeal60 boards that have some additional handling needed. + +To replace the function, all you need to do is add something like this to your code: + +```c +void bootmagic_lite(void) { + matrix_scan(); + wait_ms(DEBOUNCING_DELAY * 2); + matrix_scan(); + + if (matrix_get_row(BOOTMAGIC_LITE_ROW) & (1 << BOOTMAGIC_LITE_COLUMN)) { + // Jump to bootloader. + bootloader_jump(); + } +} +``` + +You can additional feature here. For instance, resetting the eeprom or requiring additional keys to be pressed to trigger bootmagic. Keep in mind that `bootmagic_lite` is called before a majority of features are initialized in the firmware. diff --git a/quantum/quantum.c b/quantum/quantum.c index c9bec6740b..5f1a691c88 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -949,8 +949,40 @@ void tap_random_base64(void) { } } +__attribute__((weak)) +void bootmagic_lite(void) { + // The lite version of TMK's bootmagic based on Wilba. + // 100% less potential for accidentally making the + // keyboard do stupid things. + + // We need multiple scans because debouncing can't be turned off. + matrix_scan(); + #if defined(DEBOUNCING_DELAY) && DEBOUNCING_DELAY > 0 + wait_ms(DEBOUNCING_DELAY * 2); + #elif defined(DEBOUNCE) && DEBOUNCE > 0 + wait_ms(DEBOUNCE * 2); + #else + wait_ms(30); + #endif + matrix_scan(); + + // If the Esc and space bar are held down on power up, + // reset the EEPROM valid state and jump to bootloader. + // Assumes Esc is at [0,0]. + // This isn't very generalized, but we need something that doesn't + // rely on user's keymaps in firmware or EEPROM. + if (matrix_get_row(BOOTMAGIC_LITE_ROW) & (1 << BOOTMAGIC_LITE_COLUMN)) { + eeconfig_disable(); + // Jump to bootloader. + bootloader_jump(); + } +} + void matrix_init_quantum() { - if (!eeconfig_is_enabled() && !eeconfig_is_disabled()) { + #ifdef BOOTMAGIC_LITE + bootmagic_lite(); + #endif + if (!eeconfig_is_enabled()) { eeconfig_init(); } #ifdef BACKLIGHT_ENABLE diff --git a/quantum/quantum.h b/quantum/quantum.h index 87a61356c7..1d3ee033fd 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -224,6 +224,15 @@ bool process_action_kb(keyrecord_t *record); bool process_record_kb(uint16_t keycode, keyrecord_t *record); bool process_record_user(uint16_t keycode, keyrecord_t *record); +#ifndef BOOTMAGIC_LITE_COLUMN + #define BOOTMAGIC_LITE_COLUMN 0 +#endif +#ifndef BOOTMAGIC_LITE_ROW + #define BOOTMAGIC_LITE_ROW 0 +#endif + +void bootmagic_lite(void); + void reset_keyboard(void); void startup_user(void); diff --git a/quantum/template/avr/config.h b/quantum/template/avr/config.h index caa72af0c2..56395f376f 100644 --- a/quantum/template/avr/config.h +++ b/quantum/template/avr/config.h @@ -222,3 +222,6 @@ along with this program. If not, see . #endif */ +/* Bootmagic Lite key configuration */ +// #define BOOTMAGIC_LITE_ROW 0 +// #define BOOTMAGIC_LITE_COLUMN 0 diff --git a/quantum/template/ps2avrgb/config.h b/quantum/template/ps2avrgb/config.h index d2c83781fa..4ff3513bc7 100644 --- a/quantum/template/ps2avrgb/config.h +++ b/quantum/template/ps2avrgb/config.h @@ -44,3 +44,7 @@ along with this program. If not, see . /* key combination for command */ #define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) + +/* Bootmagic Lite key configuration */ +// #define BOOTMAGIC_LITE_ROW 0 +// #define BOOTMAGIC_LITE_COLUMN 0 diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 33bcc97b2e..3844b13d48 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -61,14 +61,26 @@ endif # Option modules -ifeq ($(strip $(BOOTMAGIC_ENABLE)), yes) +BOOTMAGIC_ENABLE ?= no +VALID_MAGIC_TYPES := yes full lite +ifneq ($(strip $(BOOTMAGIC_ENABLE)), no) + ifeq ($(filter $(BOOTMAGIC_ENABLE),$(VALID_MAGIC_TYPES)),) + $(error BOOTMAGIC_ENABLE="$(BOOTMAGIC_ENABLE)" is not a valid type of magic) + endif + ifeq ($(strip $(BOOTMAGIC_ENABLE)), lite) + TMK_COMMON_DEFS += -DBOOTMAGIC_LITE + TMK_COMMON_DEFS += -DMAGIC_ENABLE + TMK_COMMON_SRC += $(COMMON_DIR)/magic.c + else TMK_COMMON_DEFS += -DBOOTMAGIC_ENABLE TMK_COMMON_SRC += $(COMMON_DIR)/bootmagic.c + endif else TMK_COMMON_DEFS += -DMAGIC_ENABLE TMK_COMMON_SRC += $(COMMON_DIR)/magic.c endif + ifeq ($(strip $(MOUSEKEY_ENABLE)), yes) TMK_COMMON_SRC += $(COMMON_DIR)/mousekey.c TMK_COMMON_DEFS += -DMOUSEKEY_ENABLE diff --git a/users/drashna/drashna.c b/users/drashna/drashna.c index 5b6620cf33..7c280e2ddd 100644 --- a/users/drashna/drashna.c +++ b/users/drashna/drashna.c @@ -424,3 +424,19 @@ void eeconfig_init_user(void) { userspace_config.raw = 0; eeconfig_update_user(userspace_config.raw); } + +void bootmagic_lite(void) { + matrix_scan(); + #if defined(DEBOUNCING_DELAY) && DEBOUNCING_DELAY > 0 + wait_ms(DEBOUNCING_DELAY * 2); + #elif defined(DEBOUNCE) && DEBOUNCE > 0 + wait_ms(DEBOUNCE * 2); + #else + wait_ms(30); + #endif + matrix_scan(); + + if (matrix_get_row(BOOTMAGIC_LITE_ROW) & (1 << BOOTMAGIC_LITE_COLUMN)) { + bootloader_jump(); + } +} -- cgit v1.2.3 From 40313cfa3b4a4f1643382f0446e0a889ef3e76dc Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Tue, 30 Oct 2018 18:00:43 -0700 Subject: Fix Terminal feature on ChibiOS --- common_features.mk | 1 + tmk_core/common.mk | 4 +++- tmk_core/common/print.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'tmk_core/common.mk') diff --git a/common_features.mk b/common_features.mk index f44dfc47de..8f53a82aae 100644 --- a/common_features.mk +++ b/common_features.mk @@ -213,6 +213,7 @@ endif ifeq ($(strip $(TERMINAL_ENABLE)), yes) SRC += $(QUANTUM_DIR)/process_keycode/process_terminal.c OPT_DEFS += -DTERMINAL_ENABLE + OPT_DEFS += -DUSER_PRINT endif ifeq ($(strip $(USB_HID_ENABLE)), yes) diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 3844b13d48..65dcf96f66 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -43,9 +43,11 @@ ifeq ($(PLATFORM),CHIBIOS) TMK_COMMON_DEFS += -DSTM32_EEPROM_ENABLE else TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom_teensy.c -endif + endif ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes) TMK_COMMON_SRC += $(CHIBIOS)/os/various/syscalls.c + else ifeq($(strip $(TERMINAL_ENABLE)), yes) + TMK_COMMON_SRC += $(CHIBIOS)/os/various/syscalls.c endif endif diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h index d945276572..06c6cbd7f1 100644 --- a/tmk_core/common/print.h +++ b/tmk_core/common/print.h @@ -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 */ -- cgit v1.2.3 From 388df5359b913eaf1ce6fb0ef624e430ad010ea5 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Tue, 6 Nov 2018 01:31:56 -0800 Subject: Fix Spacing issue in makefile that breaks Terminal config --- tmk_core/common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tmk_core/common.mk') diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 65dcf96f66..8eac1734f4 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -46,7 +46,7 @@ ifeq ($(PLATFORM),CHIBIOS) endif ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes) TMK_COMMON_SRC += $(CHIBIOS)/os/various/syscalls.c - else ifeq($(strip $(TERMINAL_ENABLE)), yes) + else ifeq ($(strip $(TERMINAL_ENABLE)), yes) TMK_COMMON_SRC += $(CHIBIOS)/os/various/syscalls.c endif endif -- cgit v1.2.3 From 39bd760faf2666e91d6dc5b199f02fa3206c6acd Mon Sep 17 00:00:00 2001 From: James Laird-Wah Date: Fri, 16 Nov 2018 17:22:05 +1100 Subject: Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format --- docs/config_options.md | 29 ++++ tmk_core/common.mk | 21 +++ tmk_core/common/host.c | 22 +++ tmk_core/common/report.c | 21 ++- tmk_core/common/report.h | 46 ++++-- tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c | 5 +- tmk_core/protocol/chibios/usb_main.c | 176 ++++++++++----------- tmk_core/protocol/chibios/usb_main.h | 11 +- tmk_core/protocol/lufa/lufa.c | 92 ++++++----- tmk_core/protocol/usb_descriptor.c | 213 ++++++++++++-------------- tmk_core/protocol/usb_descriptor.h | 170 ++++++++------------ 11 files changed, 426 insertions(+), 380 deletions(-) (limited to 'tmk_core/common.mk') diff --git a/docs/config_options.md b/docs/config_options.md index c4921c21d7..b811fa877d 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -261,3 +261,32 @@ Use these to enable or disable building certain features. The more you have enab * Forces the keyboard to wait for a USB connection to be established before it starts up * `NO_USB_STARTUP_CHECK` * Disables usb suspend check after keyboard startup. Usually the keyboard waits for the host to wake it up before any tasks are performed. This is useful for split keyboards as one half will not get a wakeup call but must send commands to the master. + +## USB Endpoint Limitations + +In order to provide services over USB, QMK has to use USB endpoints. +These are a finite resource: each microcontroller has only a certain number. +This limits what features can be enabled together. +If the available endpoints are exceeded, a build error is thrown. + +The following features can require separate endpoints: + +* `MOUSEKEY_ENABLE` +* `EXTRAKEY_ENABLE` +* `CONSOLE_ENABLE` +* `NKRO_ENABLE` +* `MIDI_ENABLE` +* `RAW_ENABLE` +* `VIRTSER_ENABLE` + +In order to improve utilisation of the endpoints, the HID features can be combined to use a single endpoint. +By default, `MOUSEKEY`, `EXTRAKEY`, and `NKRO` are combined into a single endpoint. + +The base keyboard functionality can also be combined into the endpoint, +by setting `KEYBOARD_SHARED_EP = yes`. +This frees up one more endpoint, +but it can prevent the keyboard working in some BIOSes, +as they do not implement Boot Keyboard protocol switching. + +Combining the mouse also breaks Boot Mouse compatibility. +The mouse can be uncombined by setting `MOUSE_SHARED_EP = no` if this functionality is required. diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 8eac1734f4..063115acb1 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -82,15 +82,31 @@ else TMK_COMMON_SRC += $(COMMON_DIR)/magic.c endif +SHARED_EP_ENABLE = no +MOUSE_SHARED_EP ?= yes +ifeq ($(strip $(KEYBOARD_SHARED_EP)), yes) + TMK_COMMON_DEFS += -DKEYBOARD_SHARED_EP + SHARED_EP_ENABLE = yes + # With the current usb_descriptor.c code, + # you can't share kbd without sharing mouse; + # that would be a very unexpected use case anyway + MOUSE_SHARED_EP = yes +endif ifeq ($(strip $(MOUSEKEY_ENABLE)), yes) TMK_COMMON_SRC += $(COMMON_DIR)/mousekey.c TMK_COMMON_DEFS += -DMOUSEKEY_ENABLE TMK_COMMON_DEFS += -DMOUSE_ENABLE + + ifeq ($(strip $(MOUSE_SHARED_EP)), yes) + TMK_COMMON_DEFS += -DMOUSE_SHARED_EP + SHARED_EP_ENABLE = yes + endif endif ifeq ($(strip $(EXTRAKEY_ENABLE)), yes) TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE + SHARED_EP_ENABLE = yes endif ifeq ($(strip $(RAW_ENABLE)), yes) @@ -111,6 +127,7 @@ endif ifeq ($(strip $(NKRO_ENABLE)), yes) TMK_COMMON_DEFS += -DNKRO_ENABLE + SHARED_EP_ENABLE = yes endif ifeq ($(strip $(USB_6KRO_ENABLE)), yes) @@ -182,6 +199,10 @@ ifeq ($(strip $(KEYMAP_SECTION_ENABLE)), yes) endif endif +ifeq ($(strip $(SHARED_EP_ENABLE)), yes) + TMK_COMMON_DEFS += -DSHARED_EP_ENABLE +endif + # Bootloader address ifdef STM32_BOOTLOADER_ADDRESS TMK_COMMON_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS) 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 . #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/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 /** \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 167f382751..5a1a6b19c7 100644 --- a/tmk_core/common/report.h +++ b/tmk_core/common/report.h @@ -23,9 +23,11 @@ along with this program. If not, see . /* 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) @@ -72,32 +74,35 @@ along with this program. If not, see . #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 (NKRO_EPSIZE - 1) + #define KEYBOARD_REPORT_BITS (SHARED_EPSIZE - 2) #elif defined(PROTOCOL_ARM_ATSAM) #include "protocol/arm_atsam/usb/udi_device_epsize.h" - #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE - #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) #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" { @@ -126,12 +131,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; @@ -139,6 +150,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; diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c index 18f9784ae6..c263ac4aa1 100644 --- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c +++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c @@ -54,6 +54,7 @@ #include "udi_hid.h" #include "udi_hid_kbd.h" #include +#include "report.h" //*************************************************************************** // KBD @@ -430,7 +431,7 @@ UDC_DESC_STORAGE udi_hid_exk_report_desc_t udi_hid_exk_report_desc = { 0x05, 0x01, // Usage Page (Generic Desktop), 0x09, 0x80, // Usage (System Control), 0xA1, 0x01, // Collection (Application), - 0x85, 0x02, // Report ID (2) (System), + 0x85, REPORT_ID_SYSTEM, // Report ID (2) (System), 0x16, 0x01, 0x00, // Logical Minimum (1), 0x26, 0x03, 0x00, // Logical Maximum (3), 0x1A, 0x81, 0x00, // Usage Minimum (81) (System Power Down), @@ -445,7 +446,7 @@ UDC_DESC_STORAGE udi_hid_exk_report_desc_t udi_hid_exk_report_desc = { 0x05, 0x0C, // Usage Page (Consumer), 0x09, 0x01, // Usage (Consumer Control), 0xA1, 0x01, // Collection (Application), - 0x85, 0x03, // Report ID (3) (Consumer), + 0x85, REPORT_ID_CONSUMER, // Report ID (3) (Consumer), 0x16, 0x01, 0x00, // Logical Minimum (1), 0x26, 0x9C, 0x02, // Logical Maximum (668), 0x1A, 0x01, 0x00, // Usage Minimum (1), diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index 71892c4f49..3028e7ea2a 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -95,6 +95,7 @@ static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype return &desc; } +#ifndef KEYBOARD_SHARED_EP /* keyboard endpoint state structure */ static USBInEndpointState kbd_ep_state; /* keyboard endpoint initialization structure (IN) */ @@ -110,8 +111,9 @@ static const USBEndpointConfig kbd_ep_config = { 2, /* IN multiplier */ NULL /* SETUP buffer (not a SETUP endpoint) */ }; +#endif -#ifdef MOUSE_ENABLE +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) /* mouse endpoint state structure */ static USBInEndpointState mouse_ep_state; @@ -128,45 +130,26 @@ static const USBEndpointConfig mouse_ep_config = { 2, /* IN multiplier */ NULL /* SETUP buffer (not a SETUP endpoint) */ }; -#endif /* MOUSE_ENABLE */ - -#ifdef EXTRAKEY_ENABLE -/* extrakey endpoint state structure */ -static USBInEndpointState extra_ep_state; - -/* extrakey endpoint initialization structure (IN) */ -static const USBEndpointConfig extra_ep_config = { - USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ - NULL, /* SETUP packet notification callback */ - extra_in_cb, /* IN notification callback */ - NULL, /* OUT notification callback */ - EXTRAKEY_EPSIZE, /* IN maximum packet size */ - 0, /* OUT maximum packet size */ - &extra_ep_state, /* IN Endpoint state */ - NULL, /* OUT endpoint state */ - 2, /* IN multiplier */ - NULL /* SETUP buffer (not a SETUP endpoint) */ -}; -#endif /* EXTRAKEY_ENABLE */ +#endif -#ifdef NKRO_ENABLE -/* nkro endpoint state structure */ -static USBInEndpointState nkro_ep_state; +#ifdef SHARED_EP_ENABLE +/* shared endpoint state structure */ +static USBInEndpointState shared_ep_state; -/* nkro endpoint initialization structure (IN) */ -static const USBEndpointConfig nkro_ep_config = { +/* shared endpoint initialization structure (IN) */ +static const USBEndpointConfig shared_ep_config = { USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ NULL, /* SETUP packet notification callback */ - nkro_in_cb, /* IN notification callback */ + shared_in_cb, /* IN notification callback */ NULL, /* OUT notification callback */ - NKRO_EPSIZE, /* IN maximum packet size */ + SHARED_EPSIZE, /* IN maximum packet size */ 0, /* OUT maximum packet size */ - &nkro_ep_state, /* IN Endpoint state */ + &shared_ep_state, /* IN Endpoint state */ NULL, /* OUT endpoint state */ 2, /* IN multiplier */ NULL /* SETUP buffer (not a SETUP endpoint) */ }; -#endif /* NKRO_ENABLE */ +#endif typedef struct { size_t queue_capacity_in; @@ -309,16 +292,15 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) { case USB_EVENT_CONFIGURED: osalSysLockFromISR(); /* Enable the endpoints specified into the configuration. */ +#ifndef KEYBOARD_SHARED_EP usbInitEndpointI(usbp, KEYBOARD_IN_EPNUM, &kbd_ep_config); -#ifdef MOUSE_ENABLE +#endif +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) usbInitEndpointI(usbp, MOUSE_IN_EPNUM, &mouse_ep_config); -#endif /* MOUSE_ENABLE */ -#ifdef EXTRAKEY_ENABLE - usbInitEndpointI(usbp, EXTRAKEY_IN_EPNUM, &extra_ep_config); -#endif /* EXTRAKEY_ENABLE */ -#ifdef NKRO_ENABLE - usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config); -#endif /* NKRO_ENABLE */ +#endif +#ifdef SHARED_EP_ENABLE + usbInitEndpointI(usbp, SHARED_IN_EPNUM, &shared_ep_config); +#endif for (int i=0;isetup fields: * 0: bmRequestType (bitmask) @@ -409,42 +402,16 @@ static bool usb_request_hook_cb(USBDriver *usbp) { case HID_GET_REPORT: switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0?) */ case KEYBOARD_INTERFACE: -#ifdef NKRO_ENABLE - case NKRO_INTERFACE: -#endif /* NKRO_ENABLE */ usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL); return TRUE; break; -#ifdef MOUSE_ENABLE +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) case MOUSE_INTERFACE: usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL); return TRUE; break; -#endif /* MOUSE_ENABLE */ - -#ifdef EXTRAKEY_ENABLE - case EXTRAKEY_INTERFACE: - if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */ - switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */ - case REPORT_ID_SYSTEM: - extra_report_blank[0] = REPORT_ID_SYSTEM; - usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); - return TRUE; - break; - case REPORT_ID_CONSUMER: - extra_report_blank[0] = REPORT_ID_CONSUMER; - usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL); - return TRUE; - break; - default: - return FALSE; - } - } else { - return FALSE; - } - break; -#endif /* EXTRAKEY_ENABLE */ +#endif default: usbSetupTransfer(usbp, NULL, 0, NULL); @@ -472,12 +439,25 @@ static bool usb_request_hook_cb(USBDriver *usbp) { case HID_SET_REPORT: switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */ case KEYBOARD_INTERFACE: -#ifdef NKRO_ENABLE - case NKRO_INTERFACE: -#endif /* NKRO_ENABLE */ +#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP) + case SHARED_INTERFACE: +#endif /* keyboard_led_stats = * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */ - usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL); + has_report_id = 0; +#if defined(SHARED_EP_ENABLE) + if (usbp->setup[4] == SHARED_INTERFACE) { + has_report_id = 1; + } +#endif + if (usbp->setup[4] == KEYBOARD_INTERFACE && !keyboard_protocol) { + has_report_id = 0; + } + if (has_report_id) { + usbSetupTransfer(usbp, set_report_buf, sizeof(set_report_buf), set_led_transfer_cb); + } else { + usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL); + } return TRUE; break; } @@ -591,20 +571,13 @@ void init_usb_driver(USBDriver *usbp) { * --------------------------------------------------------- */ /* keyboard IN callback hander (a kbd report has made it IN) */ +#ifndef KEYBOARD_SHARED_EP void kbd_in_cb(USBDriver *usbp, usbep_t ep) { /* STUB */ (void)usbp; (void)ep; } - -#ifdef NKRO_ENABLE -/* nkro IN callback hander (a nkro report has made it IN) */ -void nkro_in_cb(USBDriver *usbp, usbep_t ep) { - /* STUB */ - (void)usbp; - (void)ep; -} -#endif /* NKRO_ENABLE */ +#endif /* start-of-frame handler * TODO: i guess it would be better to re-implement using timers, @@ -628,9 +601,9 @@ static void keyboard_idle_timer_cb(void *arg) { } #ifdef NKRO_ENABLE - if(!keymap_config.nkro && keyboard_idle) { + if(!keymap_config.nkro && keyboard_idle && keyboard_protocol) { #else /* NKRO_ENABLE */ - if(keyboard_idle) { + if(keyboard_idle && keyboard_protocol) { #endif /* NKRO_ENABLE */ /* TODO: are we sure we want the KBD_ENDPOINT? */ if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) { @@ -661,25 +634,25 @@ void send_keyboard(report_keyboard_t *report) { osalSysUnlock(); #ifdef NKRO_ENABLE - if(keymap_config.nkro) { /* NKRO protocol */ + if(keymap_config.nkro && keyboard_protocol) { /* NKRO protocol */ /* need to wait until the previous packet has made it through */ /* can rewrite this using the synchronous API, then would wait * until *after* the packet has been transmitted. I think * this is more efficient */ /* busy wait, should be short and not very common */ osalSysLock(); - if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) { + if(usbGetTransmitStatusI(&USB_DRIVER, SHARED_IN_EPNUM)) { /* Need to either suspend, or loop and call unlock/lock during * every iteration - otherwise the system will remain locked, * no interrupts served, so USB not going through as well. * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ - osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread); + osalThreadSuspendS(&(&USB_DRIVER)->epc[SHARED_IN_EPNUM]->in_state->thread); } - usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t)); + usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)report, sizeof(struct nkro_report)); osalSysUnlock(); } else #endif /* NKRO_ENABLE */ - { /* boot protocol */ + { /* regular protocol */ /* need to wait until the previous packet has made it through */ /* busy wait, should be short and not very common */ osalSysLock(); @@ -690,7 +663,15 @@ void send_keyboard(report_keyboard_t *report) { * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */ osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread); } - usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE); + uint8_t *data, size; + if (keyboard_protocol) { + data = (uint8_t*)report; + size = KEYBOARD_REPORT_SIZE; + } else { /* boot protocol */ + data = &report->mods; + size = 8; + } + usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, data, size); osalSysUnlock(); } keyboard_report_sent = *report; @@ -703,11 +684,13 @@ void send_keyboard(report_keyboard_t *report) { #ifdef MOUSE_ENABLE +#ifndef MOUSE_SHARED_EP /* mouse IN callback hander (a mouse report has made it IN) */ void mouse_in_cb(USBDriver *usbp, usbep_t ep) { (void)usbp; (void)ep; } +#endif void send_mouse(report_mouse_t *report) { osalSysLock(); @@ -737,19 +720,24 @@ void send_mouse(report_mouse_t *report) { #endif /* MOUSE_ENABLE */ /* --------------------------------------------------------- - * Extrakey functions + * Shared EP functions * --------------------------------------------------------- */ - -#ifdef EXTRAKEY_ENABLE - -/* extrakey IN callback hander */ -void extra_in_cb(USBDriver *usbp, usbep_t ep) { +#ifdef SHARED_EP_ENABLE +/* shared IN callback hander */ +void shared_in_cb(USBDriver *usbp, usbep_t ep) { /* STUB */ (void)usbp; (void)ep; } +#endif + +/* --------------------------------------------------------- + * Extrakey functions + * --------------------------------------------------------- + */ +#ifdef EXTRAKEY_ENABLE static void send_extra_report(uint8_t report_id, uint16_t data) { osalSysLock(); if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { @@ -762,7 +750,7 @@ static void send_extra_report(uint8_t report_id, uint16_t data) { .usage = data }; - usbStartTransmitI(&USB_DRIVER, EXTRAKEY_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t)); + usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t)); osalSysUnlock(); } diff --git a/tmk_core/protocol/chibios/usb_main.h b/tmk_core/protocol/chibios/usb_main.h index 1f7eb12f8d..55e8882cc4 100644 --- a/tmk_core/protocol/chibios/usb_main.h +++ b/tmk_core/protocol/chibios/usb_main.h @@ -65,6 +65,14 @@ void nkro_in_cb(USBDriver *usbp, usbep_t ep); void mouse_in_cb(USBDriver *usbp, usbep_t ep); #endif /* MOUSE_ENABLE */ +/* --------------- + * Shared EP header + * --------------- + */ + +/* shared IN request callback handler */ +void shared_in_cb(USBDriver *usbp, usbep_t ep); + /* --------------- * Extrakey header * --------------- @@ -72,9 +80,6 @@ void mouse_in_cb(USBDriver *usbp, usbep_t ep); #ifdef EXTRAKEY_ENABLE -/* extrakey IN request callback handler */ -void extra_in_cb(USBDriver *usbp, usbep_t ep); - /* extra report structure */ typedef struct { uint8_t report_id; diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 95e0b95b2f..e88e6f34aa 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -409,19 +409,21 @@ void EVENT_USB_Device_ConfigurationChanged(void) bool ConfigSuccess = true; /* Setup Keyboard HID Report Endpoints */ +#ifndef KEYBOARD_SHARED_EP ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE); +#endif -#ifdef MOUSE_ENABLE +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) /* Setup Mouse HID Report Endpoint */ ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE); #endif -#ifdef EXTRAKEY_ENABLE - /* Setup Extra HID Report Endpoint */ - ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, - EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE); +#ifdef SHARED_EP_ENABLE + /* Setup Shared HID Report Endpoint */ + ConfigSuccess &= ENDPOINT_CONFIG(SHARED_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + SHARED_EPSIZE, ENDPOINT_BANK_SINGLE); #endif #ifdef RAW_ENABLE @@ -442,12 +444,6 @@ void EVENT_USB_Device_ConfigurationChanged(void) #endif #endif -#ifdef NKRO_ENABLE - /* Setup NKRO HID Report Endpoints */ - ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, - NKRO_EPSIZE, ENDPOINT_BANK_SINGLE); -#endif - #ifdef MIDI_ENABLE ConfigSuccess &= Endpoint_ConfigureEndpoint(MIDI_STREAM_IN_EPADDR, EP_TYPE_BULK, MIDI_STREAM_EPSIZE, ENDPOINT_BANK_SINGLE); ConfigSuccess &= Endpoint_ConfigureEndpoint(MIDI_STREAM_OUT_EPADDR, EP_TYPE_BULK, MIDI_STREAM_EPSIZE, ENDPOINT_BANK_SINGLE); @@ -512,8 +508,8 @@ void EVENT_USB_Device_ControlRequest(void) // Interface switch (USB_ControlRequest.wIndex) { case KEYBOARD_INTERFACE: -#ifdef NKRO_ENABLE - case NKRO_INTERFACE: +#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP) + case SHARED_INTERFACE: #endif Endpoint_ClearSETUP(); @@ -521,7 +517,17 @@ void EVENT_USB_Device_ControlRequest(void) if (USB_DeviceState == DEVICE_STATE_Unattached) return; } +#if defined(SHARED_EP_ENABLE) + uint8_t report_id = REPORT_ID_KEYBOARD; + if (keyboard_protocol) { + report_id = Endpoint_Read_8(); + } + if (report_id == REPORT_ID_KEYBOARD || report_id == REPORT_ID_NKRO) { + keyboard_led_stats = Endpoint_Read_8(); + } +#else keyboard_led_stats = Endpoint_Read_8(); +#endif Endpoint_ClearOUT(); Endpoint_ClearStatusStage(); @@ -612,16 +618,20 @@ static void send_keyboard(report_keyboard_t *report) #ifdef MODULE_ADAFRUIT_BLE adafruit_ble_send_keys(report->mods, report->keys, sizeof(report->keys)); #elif MODULE_RN42 - bluefruit_serial_send(0xFD); - bluefruit_serial_send(0x09); - bluefruit_serial_send(0x01); - for (uint8_t i = 0; i < KEYBOARD_EPSIZE; i++) { - bluefruit_serial_send(report->raw[i]); - } + bluefruit_serial_send(0xFD); + bluefruit_serial_send(0x09); + bluefruit_serial_send(0x01); + bluefruit_serial_send(report->mods); + bluefruit_serial_send(report->reserved); + for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { + bluefruit_serial_send(report->keys[i]); + } #else bluefruit_serial_send(0xFD); - for (uint8_t i = 0; i < KEYBOARD_EPSIZE; i++) { - bluefruit_serial_send(report->raw[i]); + bluefruit_serial_send(report->mods); + bluefruit_serial_send(report->reserved); + for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { + bluefruit_serial_send(report->keys[i]); } #endif } @@ -632,30 +642,24 @@ static void send_keyboard(report_keyboard_t *report) } /* Select the Keyboard Report Endpoint */ + uint8_t ep = KEYBOARD_IN_EPNUM; + uint8_t size = KEYBOARD_REPORT_SIZE; #ifdef NKRO_ENABLE if (keyboard_protocol && keymap_config.nkro) { - /* Report protocol - NKRO */ - Endpoint_SelectEndpoint(NKRO_IN_EPNUM); - - /* Check if write ready for a polling interval around 1ms */ - while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4); - if (!Endpoint_IsReadWriteAllowed()) return; - - /* Write Keyboard Report Data */ - Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL); + ep = SHARED_IN_EPNUM; + size = sizeof(struct nkro_report); } - else #endif - { - /* Boot protocol */ - Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM); - - /* Check if write ready for a polling interval around 10ms */ - while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); - if (!Endpoint_IsReadWriteAllowed()) return; + Endpoint_SelectEndpoint(ep); + /* Check if write ready for a polling interval around 10ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); + if (!Endpoint_IsReadWriteAllowed()) return; - /* Write Keyboard Report Data */ - Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL); + /* If we're in Boot Protocol, don't send any report ID or other funky fields */ + if (!keyboard_protocol) { + Endpoint_Write_Stream_LE(&report->mods, 8, NULL); + } else { + Endpoint_Write_Stream_LE(report, size, NULL); } /* Finalize the stream transfer to send the last packet */ @@ -718,6 +722,7 @@ static void send_mouse(report_mouse_t *report) */ static void send_system(uint16_t data) { +#ifdef EXTRAKEY_ENABLE uint8_t timeout = 255; if (USB_DeviceState != DEVICE_STATE_Configured) @@ -727,7 +732,7 @@ static void send_system(uint16_t data) .report_id = REPORT_ID_SYSTEM, .usage = data - SYSTEM_POWER_DOWN + 1 }; - Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM); + Endpoint_SelectEndpoint(SHARED_IN_EPNUM); /* Check if write ready for a polling interval around 10ms */ while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); @@ -735,6 +740,7 @@ static void send_system(uint16_t data) Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); Endpoint_ClearIN(); +#endif } /** \brief Send Consumer @@ -743,6 +749,7 @@ static void send_system(uint16_t data) */ static void send_consumer(uint16_t data) { +#ifdef EXTRAKEY_ENABLE uint8_t timeout = 255; uint8_t where = where_to_send(); @@ -786,7 +793,7 @@ static void send_consumer(uint16_t data) .report_id = REPORT_ID_CONSUMER, .usage = data }; - Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM); + Endpoint_SelectEndpoint(SHARED_IN_EPNUM); /* Check if write ready for a polling interval around 10ms */ while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); @@ -794,6 +801,7 @@ static void send_consumer(uint16_t data) Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); Endpoint_ClearIN(); +#endif } diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c index cab3446752..589ad23cdd 100644 --- a/tmk_core/protocol/usb_descriptor.c +++ b/tmk_core/protocol/usb_descriptor.c @@ -47,11 +47,18 @@ /******************************************************************************* * HID Report Descriptors ******************************************************************************/ -const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = -{ +#ifdef KEYBOARD_SHARED_EP +const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { +#define SHARED_REPORT_STARTED +#else +const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = { +#endif HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x06), /* Keyboard */ HID_RI_COLLECTION(8, 0x01), /* Application */ +# ifdef KEYBOARD_SHARED_EP + HID_RI_REPORT_ID(8, REPORT_ID_KEYBOARD), +# endif HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */ HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */ @@ -84,14 +91,25 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = HID_RI_REPORT_SIZE(8, 0x08), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), HID_RI_END_COLLECTION(0), + +#ifndef KEYBOARD_SHARED_EP }; +#endif -#ifdef MOUSE_ENABLE -const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] = -{ +#if defined(MOUSE_ENABLE) + +# if !defined(MOUSE_SHARED_EP) +const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] = { +# elif !defined(SHARED_REPORT_STARTED) +const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { +#define SHARED_REPORT_STARTED +# endif HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x02), /* Mouse */ HID_RI_COLLECTION(8, 0x01), /* Application */ +# ifdef MOUSE_SHARED_EP + HID_RI_REPORT_ID(8, REPORT_ID_MOUSE), +# endif HID_RI_USAGE(8, 0x01), /* Pointer */ HID_RI_COLLECTION(8, 0x00), /* Physical */ @@ -133,12 +151,15 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] = HID_RI_END_COLLECTION(0), HID_RI_END_COLLECTION(0), +# ifndef MOUSE_SHARED_EP }; +# endif #endif -#ifdef EXTRAKEY_ENABLE -const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] = -{ +#if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED) +const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { +#endif +# ifdef EXTRAKEY_ENABLE HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x80), /* System Control */ HID_RI_COLLECTION(8, 0x01), /* Application */ @@ -164,6 +185,43 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] = HID_RI_REPORT_COUNT(8, 1), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE), HID_RI_END_COLLECTION(0), +# endif + +# ifdef NKRO_ENABLE + HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ + HID_RI_USAGE(8, 0x06), /* Keyboard */ + HID_RI_COLLECTION(8, 0x01), /* Application */ + HID_RI_REPORT_ID(8, REPORT_ID_NKRO), + HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ + HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */ + HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */ + HID_RI_LOGICAL_MINIMUM(8, 0x00), + HID_RI_LOGICAL_MAXIMUM(8, 0x01), + HID_RI_REPORT_COUNT(8, 0x08), + HID_RI_REPORT_SIZE(8, 0x01), + HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + + HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */ + HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */ + HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */ + HID_RI_REPORT_COUNT(8, 0x05), + HID_RI_REPORT_SIZE(8, 0x01), + HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), + HID_RI_REPORT_COUNT(8, 0x01), + HID_RI_REPORT_SIZE(8, 0x03), + HID_RI_OUTPUT(8, HID_IOF_CONSTANT), + + HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ + HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */ + HID_RI_USAGE_MAXIMUM(8, KEYBOARD_REPORT_BITS*8-1), + HID_RI_LOGICAL_MINIMUM(8, 0x00), + HID_RI_LOGICAL_MAXIMUM(8, 0x01), + HID_RI_REPORT_COUNT(8, KEYBOARD_REPORT_BITS*8), + HID_RI_REPORT_SIZE(8, 0x01), + HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_RI_END_COLLECTION(0), +# endif +#ifdef SHARED_EP_ENABLE }; #endif @@ -211,42 +269,6 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = }; #endif -#ifdef NKRO_ENABLE -const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] = -{ - HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ - HID_RI_USAGE(8, 0x06), /* Keyboard */ - HID_RI_COLLECTION(8, 0x01), /* Application */ - HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ - HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */ - HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */ - HID_RI_LOGICAL_MINIMUM(8, 0x00), - HID_RI_LOGICAL_MAXIMUM(8, 0x01), - HID_RI_REPORT_COUNT(8, 0x08), - HID_RI_REPORT_SIZE(8, 0x01), - HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - - HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */ - HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */ - HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */ - HID_RI_REPORT_COUNT(8, 0x05), - HID_RI_REPORT_SIZE(8, 0x01), - HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), - HID_RI_REPORT_COUNT(8, 0x01), - HID_RI_REPORT_SIZE(8, 0x03), - HID_RI_OUTPUT(8, HID_IOF_CONSTANT), - - HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ - HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */ - HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */ - HID_RI_LOGICAL_MINIMUM(8, 0x00), - HID_RI_LOGICAL_MAXIMUM(8, 0x01), - HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8), - HID_RI_REPORT_SIZE(8, 0x01), - HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), - HID_RI_END_COLLECTION(0), -}; -#endif /******************************************************************************* * Device Descriptors @@ -303,6 +325,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = /* * Keyboard */ +#ifndef KEYBOARD_SHARED_EP .Keyboard_Interface = { .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, @@ -339,11 +362,12 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .EndpointSize = KEYBOARD_EPSIZE, .PollingIntervalMS = 0x0A }, +#endif /* * Mouse */ -#ifdef MOUSE_ENABLE +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) .Mouse_Interface = { .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, @@ -383,26 +407,31 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = #endif /* - * Extra + * Shared */ -#ifdef EXTRAKEY_ENABLE - .Extrakey_Interface = +#ifdef SHARED_EP_ENABLE + .Shared_Interface = { .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, - .InterfaceNumber = EXTRAKEY_INTERFACE, + .InterfaceNumber = SHARED_INTERFACE, .AlternateSetting = 0x00, .TotalEndpoints = 1, .Class = HID_CSCP_HIDClass, +# ifdef KEYBOARD_SHARED_EP + .SubClass = HID_CSCP_BootSubclass, + .Protocol = HID_CSCP_KeyboardBootProtocol, +# else .SubClass = HID_CSCP_NonBootSubclass, .Protocol = HID_CSCP_NonBootProtocol, +#endif .InterfaceStrIndex = NO_DESCRIPTOR }, - .Extrakey_HID = + .Shared_HID = { .Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID}, @@ -410,16 +439,16 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .CountryCode = 0x00, .TotalReportDescriptors = 1, .HIDReportType = HID_DTYPE_Report, - .HIDReportLength = sizeof(ExtrakeyReport) + .HIDReportLength = sizeof(SharedReport) }, - .Extrakey_INEndpoint = + .Shared_INEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, - .EndpointAddress = (ENDPOINT_DIR_IN | EXTRAKEY_IN_EPNUM), + .EndpointAddress = (ENDPOINT_DIR_IN | SHARED_IN_EPNUM), .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), - .EndpointSize = EXTRAKEY_EPSIZE, + .EndpointSize = SHARED_EPSIZE, .PollingIntervalMS = 0x0A }, #endif @@ -528,48 +557,6 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = }, #endif - /* - * NKRO - */ -#ifdef NKRO_ENABLE - .NKRO_Interface = - { - .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, - - .InterfaceNumber = NKRO_INTERFACE, - .AlternateSetting = 0x00, - - .TotalEndpoints = 1, - - .Class = HID_CSCP_HIDClass, - .SubClass = HID_CSCP_NonBootSubclass, - .Protocol = HID_CSCP_NonBootProtocol, - - .InterfaceStrIndex = NO_DESCRIPTOR - }, - - .NKRO_HID = - { - .Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID}, - - .HIDSpec = VERSION_BCD(1,1,1), - .CountryCode = 0x00, - .TotalReportDescriptors = 1, - .HIDReportType = HID_DTYPE_Report, - .HIDReportLength = sizeof(NKROReport) - }, - - .NKRO_INEndpoint = - { - .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, - - .EndpointAddress = (ENDPOINT_DIR_IN | NKRO_IN_EPNUM), - .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), - .EndpointSize = NKRO_EPSIZE, - .PollingIntervalMS = 0x01 - }, -#endif - #ifdef MIDI_ENABLE .Audio_Interface_Association = { @@ -936,19 +923,21 @@ uint16_t get_usb_descriptor(const uint16_t wValue, break; case HID_DTYPE_HID: switch (wIndex) { +#ifndef KEYBOARD_SHARED_EP case KEYBOARD_INTERFACE: Address = &ConfigurationDescriptor.Keyboard_HID; Size = sizeof(USB_HID_Descriptor_HID_t); break; -#ifdef MOUSE_ENABLE +#endif +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) case MOUSE_INTERFACE: Address = &ConfigurationDescriptor.Mouse_HID; Size = sizeof(USB_HID_Descriptor_HID_t); break; #endif -#ifdef EXTRAKEY_ENABLE - case EXTRAKEY_INTERFACE: - Address = &ConfigurationDescriptor.Extrakey_HID; +#ifdef SHARED_EP_ENABLE + case SHARED_INTERFACE: + Address = &ConfigurationDescriptor.Shared_HID; Size = sizeof(USB_HID_Descriptor_HID_t); break; #endif @@ -963,31 +952,27 @@ uint16_t get_usb_descriptor(const uint16_t wValue, Address = &ConfigurationDescriptor.Console_HID; Size = sizeof(USB_HID_Descriptor_HID_t); break; -#endif -#ifdef NKRO_ENABLE - case NKRO_INTERFACE: - Address = &ConfigurationDescriptor.NKRO_HID; - Size = sizeof(USB_HID_Descriptor_HID_t); - break; #endif } break; case HID_DTYPE_Report: switch (wIndex) { +#ifndef KEYBOARD_SHARED_EP case KEYBOARD_INTERFACE: Address = &KeyboardReport; Size = sizeof(KeyboardReport); break; -#ifdef MOUSE_ENABLE +#endif +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) case MOUSE_INTERFACE: Address = &MouseReport; Size = sizeof(MouseReport); break; #endif -#ifdef EXTRAKEY_ENABLE - case EXTRAKEY_INTERFACE: - Address = &ExtrakeyReport; - Size = sizeof(ExtrakeyReport); +#ifdef SHARED_EP_ENABLE + case SHARED_INTERFACE: + Address = &SharedReport; + Size = sizeof(SharedReport); break; #endif #ifdef RAW_ENABLE @@ -1001,12 +986,6 @@ uint16_t get_usb_descriptor(const uint16_t wValue, Address = &ConsoleReport; Size = sizeof(ConsoleReport); break; -#endif -#ifdef NKRO_ENABLE - case NKRO_INTERFACE: - Address = &NKROReport; - Size = sizeof(NKROReport); - break; #endif } break; diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h index 586d07df62..3ca0c00b34 100644 --- a/tmk_core/protocol/usb_descriptor.h +++ b/tmk_core/protocol/usb_descriptor.h @@ -53,26 +53,27 @@ typedef struct { USB_Descriptor_Configuration_Header_t Config; +#ifndef KEYBOARD_SHARED_EP // Keyboard HID Interface USB_Descriptor_Interface_t Keyboard_Interface; USB_HID_Descriptor_HID_t Keyboard_HID; USB_Descriptor_Endpoint_t Keyboard_INEndpoint; +#endif -#ifdef MOUSE_ENABLE +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) // Mouse HID Interface USB_Descriptor_Interface_t Mouse_Interface; USB_HID_Descriptor_HID_t Mouse_HID; USB_Descriptor_Endpoint_t Mouse_INEndpoint; #endif -#ifdef EXTRAKEY_ENABLE - // Extrakey HID Interface - USB_Descriptor_Interface_t Extrakey_Interface; - USB_HID_Descriptor_HID_t Extrakey_HID; - USB_Descriptor_Endpoint_t Extrakey_INEndpoint; +#if defined(SHARED_EP_ENABLE) + USB_Descriptor_Interface_t Shared_Interface; + USB_HID_Descriptor_HID_t Shared_HID; + USB_Descriptor_Endpoint_t Shared_INEndpoint; #endif -#ifdef RAW_ENABLE +#if defined(RAW_ENABLE) // Raw HID Interface USB_Descriptor_Interface_t Raw_Interface; USB_HID_Descriptor_HID_t Raw_HID; @@ -88,13 +89,6 @@ typedef struct USB_Descriptor_Endpoint_t Console_OUTEndpoint; #endif -#ifdef NKRO_ENABLE - // NKRO HID Interface - USB_Descriptor_Interface_t NKRO_Interface; - USB_HID_Descriptor_HID_t NKRO_HID; - USB_Descriptor_Endpoint_t NKRO_INEndpoint; -#endif - #ifdef MIDI_ENABLE USB_Descriptor_Interface_Association_t Audio_Interface_Association; // MIDI Audio Control Interface @@ -133,133 +127,105 @@ typedef struct /* index of interface */ -#define KEYBOARD_INTERFACE 0 - +enum usb_interfaces { +#if !defined(KEYBOARD_SHARED_EP) + KEYBOARD_INTERFACE, +#else +# define KEYBOARD_INTERFACE SHARED_INTERFACE +#endif // It is important that the Raw HID interface is at a constant // interface number, to support Linux/OSX platforms and chrome.hid // If Raw HID is enabled, let it be always 1. -#ifdef RAW_ENABLE -# define RAW_INTERFACE (KEYBOARD_INTERFACE + 1) -#else -# define RAW_INTERFACE KEYBOARD_INTERFACE +#if defined(RAW_ENABLE) + RAW_INTERFACE, #endif - -#ifdef MOUSE_ENABLE -# define MOUSE_INTERFACE (RAW_INTERFACE + 1) -#else -# define MOUSE_INTERFACE RAW_INTERFACE +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) + MOUSE_INTERFACE, #endif - -#ifdef EXTRAKEY_ENABLE -# define EXTRAKEY_INTERFACE (MOUSE_INTERFACE + 1) -#else -# define EXTRAKEY_INTERFACE MOUSE_INTERFACE +#if defined(SHARED_EP_ENABLE) + SHARED_INTERFACE, #endif - -#ifdef CONSOLE_ENABLE -# define CONSOLE_INTERFACE (EXTRAKEY_INTERFACE + 1) -#else -# define CONSOLE_INTERFACE EXTRAKEY_INTERFACE -#endif - -#ifdef NKRO_ENABLE -# define NKRO_INTERFACE (CONSOLE_INTERFACE + 1) -#else -# define NKRO_INTERFACE CONSOLE_INTERFACE +#if defined(CONSOLE_ENABLE) + CONSOLE_INTERFACE, #endif - -#ifdef MIDI_ENABLE -# define AC_INTERFACE (NKRO_INTERFACE + 1) -# define AS_INTERFACE (NKRO_INTERFACE + 2) -#else -# define AS_INTERFACE NKRO_INTERFACE +#if defined(MIDI_ENABLE) + AC_INTERFACE, + AS_INTERFACE, #endif - -#ifdef VIRTSER_ENABLE -# define CCI_INTERFACE (AS_INTERFACE + 1) -# define CDI_INTERFACE (AS_INTERFACE + 2) -#else -# define CDI_INTERFACE AS_INTERFACE +#if defined(VIRTSER_ENABLE) + CCI_INTERFACE, + CDI_INTERFACE, #endif + TOTAL_INTERFACES +}; -/* nubmer of interfaces */ -#define TOTAL_INTERFACES (CDI_INTERFACE + 1) - +#define NEXT_EPNUM __COUNTER__ -// Endopoint number and size -#define KEYBOARD_IN_EPNUM 1 - -#ifdef MOUSE_ENABLE -# define MOUSE_IN_EPNUM (KEYBOARD_IN_EPNUM + 1) +enum usb_endpoints { + __unused_epnum__ = NEXT_EPNUM, /* EP numbering starts at 1 */ +#if !defined(KEYBOARD_SHARED_EP) + KEYBOARD_IN_EPNUM = NEXT_EPNUM, #else -# define MOUSE_IN_EPNUM KEYBOARD_IN_EPNUM +# define KEYBOARD_IN_EPNUM SHARED_IN_EPNUM #endif - -#ifdef EXTRAKEY_ENABLE -# define EXTRAKEY_IN_EPNUM (MOUSE_IN_EPNUM + 1) +#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) + MOUSE_IN_EPNUM = NEXT_EPNUM, #else -# define EXTRAKEY_IN_EPNUM MOUSE_IN_EPNUM +# define MOUSE_IN_EPNUM SHARED_IN_EPNUM #endif - -#ifdef RAW_ENABLE -# define RAW_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1) -# define RAW_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 2) -#else -# define RAW_OUT_EPNUM EXTRAKEY_IN_EPNUM +#if defined(RAW_ENABLE) + RAW_IN_EPNUM = NEXT_EPNUM, + RAW_OUT_EPNUM = NEXT_EPNUM, #endif - -#ifdef CONSOLE_ENABLE -# define CONSOLE_IN_EPNUM (RAW_OUT_EPNUM + 1) +#if defined(SHARED_EP_ENABLE) + SHARED_IN_EPNUM = NEXT_EPNUM, +#endif +#if defined(CONSOLE_ENABLE) + CONSOLE_IN_EPNUM = NEXT_EPNUM, #ifdef PROTOCOL_CHIBIOS // ChibiOS has enough memory and descriptor to actually enable the endpoint // It could use the same endpoint numbers, as that's supported by ChibiOS // But the QMK code currently assumes that the endpoint numbers are different -# define CONSOLE_OUT_EPNUM (RAW_OUT_EPNUM + 2) + CONSOLE_OUT_EPNUM = NEXT_EPNUM, #else -# define CONSOLE_OUT_EPNUM (RAW_OUT_EPNUM + 1) +#define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM #endif -#else -# define CONSOLE_OUT_EPNUM RAW_OUT_EPNUM #endif - -#ifdef NKRO_ENABLE -# define NKRO_IN_EPNUM (CONSOLE_OUT_EPNUM + 1) -#else -# define NKRO_IN_EPNUM CONSOLE_OUT_EPNUM -#endif - #ifdef MIDI_ENABLE -# define MIDI_STREAM_IN_EPNUM (NKRO_IN_EPNUM + 1) -// # define MIDI_STREAM_OUT_EPNUM (NKRO_IN_EPNUM + 1) -# define MIDI_STREAM_OUT_EPNUM (NKRO_IN_EPNUM + 2) + MIDI_STREAM_IN_EPNUM = NEXT_EPNUM, + MIDI_STREAM_OUT_EPNUM = NEXT_EPNUM, # define MIDI_STREAM_IN_EPADDR (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM) # define MIDI_STREAM_OUT_EPADDR (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM) -#else -# define MIDI_STREAM_OUT_EPNUM NKRO_IN_EPNUM #endif - #ifdef VIRTSER_ENABLE -# define CDC_NOTIFICATION_EPNUM (MIDI_STREAM_OUT_EPNUM + 1) -# define CDC_IN_EPNUM (MIDI_STREAM_OUT_EPNUM + 2) -# define CDC_OUT_EPNUM (MIDI_STREAM_OUT_EPNUM + 3) + CDC_NOTIFICATION_EPNUM = NEXT_EPNUM, + CDC_IN_EPNUM = NEXT_EPNUM, + CDC_OUT_EPNUM = NEXT_EPNUM, # define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | CDC_NOTIFICATION_EPNUM) # define CDC_IN_EPADDR (ENDPOINT_DIR_IN | CDC_IN_EPNUM) # define CDC_OUT_EPADDR (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM) -#else -# define CDC_OUT_EPNUM MIDI_STREAM_OUT_EPNUM #endif +}; + +#if defined(PROTOCOL_LUFA) +/* LUFA tells us total endpoints including control */ +#define MAX_ENDPOINTS (ENDPOINT_TOTAL_ENDPOINTS - 1) +#elif defined(PROTOCOL_CHIBIOS) +/* ChibiOS gives us number of available user endpoints, not control */ +#define MAX_ENDPOINTS USB_MAX_ENDPOINTS +#endif +/* TODO - ARM_ATSAM */ + -#if (defined(PROTOCOL_LUFA) && CDC_OUT_EPNUM > (ENDPOINT_TOTAL_ENDPOINTS - 1)) || \ - (defined(PROTOCOL_CHIBIOS) && CDC_OUT_EPNUM > USB_MAX_ENDPOINTS) -# error "There are not enough available endpoints to support all functions. Remove some in the rules.mk file.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, SERIAL, STENO)" +#if (NEXT_EPNUM - 1) > MAX_ENDPOINTS +# error There are not enough available endpoints to support all functions. Remove some in the rules.mk file. (MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, SERIAL, STENO) #endif #define KEYBOARD_EPSIZE 8 +#define SHARED_EPSIZE 32 #define MOUSE_EPSIZE 8 -#define EXTRAKEY_EPSIZE 8 #define RAW_EPSIZE 32 #define CONSOLE_EPSIZE 32 -#define NKRO_EPSIZE 32 #define MIDI_STREAM_EPSIZE 64 #define CDC_NOTIFICATION_EPSIZE 8 #define CDC_EPSIZE 16 -- cgit v1.2.3