diff --git a/firmware/.cproject b/firmware/.cproject index 0ccbe54e9a..8c5ffea452 100644 --- a/firmware/.cproject +++ b/firmware/.cproject @@ -1,50 +1,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firmware/.cproject.old b/firmware/.cproject.old new file mode 100644 index 0000000000..a91aafcf8f --- /dev/null +++ b/firmware/.cproject.old @@ -0,0 +1,834 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firmware/ChibiOS3 b/firmware/ChibiOS3 new file mode 160000 index 0000000000..9913d7306e --- /dev/null +++ b/firmware/ChibiOS3 @@ -0,0 +1 @@ +Subproject commit 9913d7306e76902b5c086f2092a631efc71b98b9 diff --git a/firmware/Makefile b/firmware/Makefile index d17d78f9b3..3bf02581e4 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -3,8 +3,6 @@ # NOTE: Can be overridden externally. # -PROJECT_DIR = . - # by default EXTRA_PARAMS is empty and we create 'debug' version of the firmware with additional assertions and statistics # for 'release' options see 'clean_compile_two_versions.bat' file @@ -16,7 +14,7 @@ endif # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = $(EXTRA_PARAMS) $(DEBUG_LEVEL_OPT) $(RFLAGS) -fomit-frame-pointer -falign-functions=16 -Werror-implicit-function-declaration -Werror -Wno-error=pointer-sign -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=sign-compare -Wno-error=unused-parameter -Wno-error=missing-field-initializers -Werror=type-limits -Wno-error=strict-aliasing -Wno-error=attributes + USE_OPT = $(EXTRA_PARAMS) $(DEBUG_LEVEL_OPT) $(RFLAGS) -fomit-frame-pointer -falign-functions=16 -Werror-implicit-function-declaration -Werror -Wno-error=pointer-sign -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=sign-compare -Wno-error=unused-parameter -Wno-error=missing-field-initializers -Werror=type-limits -Wno-error=strict-aliasing -Wno-error=attributes endif # C specific options here (added to USE_OPT). @@ -36,7 +34,7 @@ endif # Linker extra options here. ifeq ($(USE_LDOPT),) - USE_LDOPT = + USE_LDOPT = endif # Enable this if you want link time optimizations (LTO) @@ -54,6 +52,12 @@ ifeq ($(USE_VERBOSE_COMPILE),) USE_VERBOSE_COMPILE = no endif +# If enabled, this option makes the build process faster by not compiling +# modules not used in the current configuration. +ifeq ($(USE_SMART_BUILD),) + USE_SMART_BUILD = no +endif + # # Build global options ############################################################################## @@ -62,11 +66,21 @@ endif # Architecture or project specific options # -USE_FPU = softfp +# Stack size to be allocated to the Cortex-M process stack. This stack is +# the stack used by the main() thread. +ifeq ($(USE_PROCESS_STACKSIZE),) + USE_PROCESS_STACKSIZE = 0x0600 +endif + +# Stack size to the allocated to the Cortex-M main/exceptions stack. This +# stack is used for processing interrupts and exceptions. +ifeq ($(USE_EXCEPTIONS_STACKSIZE),) + USE_EXCEPTIONS_STACKSIZE = 0x1000 +endif # Enables the use of FPU on Cortex-M4 (no, softfp, hard). ifeq ($(USE_FPU),) - USE_FPU = no + USE_FPU = softfp endif # @@ -79,28 +93,33 @@ endif # Define project name here PROJECT = rusefi +PROJECT_DIR = . # Imported source files and paths -CHIBIOS = chibios -#include $(CHIBIOS)/test/test.mk +CHIBIOS = ChibiOS3 +CHIBIOS_CONTRIB = ChibiOS-Contrib -#PROJECT_BOARD = OLIMEX_STM32_E407 ifneq ($(PROJECT_BOARD),OLIMEX_STM32_E407) PROJECT_BOARD = ST_STM32F4 endif DDEFS += -D$(PROJECT_BOARD) - -# Imported source files and paths -include $(CHIBIOS)/os/hal/platforms/STM32F4xx/platform.mk -include $(CHIBIOS)/os/hal/hal.mk -include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F4xx/port.mk -include $(CHIBIOS)/os/kernel/kernel.mk -#include $(CHIBIOS)/os/various/cpp_wrappers/kernel.mk +# Startup files. +include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk +# HAL-OSAL files (optional). +include $(CHIBIOS_CONTRIB)/os/hal/hal.mk +include $(CHIBIOS_CONTRIB)/os/hal/ports/STM32/STM32F4xx/platform.mk +include $(CHIBIOS)/os/hal/osal/rt/osal.mk +# RTOS files (optional). +include $(CHIBIOS)/os/rt/rt.mk +include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk include $(CHIBIOS)/os/various/fatfs_bindings/fatfs.mk +include $(CHIBIOS)/os/various/cpp_wrappers/chcpp.mk + include console/binary/tunerstudio.mk -include ext/ext.mk +include $(PROJECT_DIR)/ext/fatfs.mk + include $(PROJECT_DIR)/hw_layer/hw_layer.mk include $(PROJECT_DIR)/hw_layer/sensors/sensors.mk include $(PROJECT_DIR)/hw_layer/mass_storage/mass_storage.mk @@ -118,31 +137,32 @@ include $(PROJECT_DIR)/controllers/system/system.mk include $(PROJECT_DIR)/controllers/trigger/trigger.mk include $(PROJECT_DIR)/console/console.mk - # Define linker script file here LDSCRIPT= config/stm32f4ems/STM32F407xG_CCM.ld # C sources that can be compiled in ARM or THUMB mode depending on the global # setting. -CSRC = $(PORTSRC) \ +CSRC = $(STARTUPSRC) \ $(KERNSRC) \ - chibios/os/various/syscalls.c \ - chibios/os/various/chprintf.c \ - chibios/os/various/memstreams.c \ - chibios/os/various/chrtclib.c \ + $(PORTSRC) \ + $(OSALSRC) \ + $(HALSRC) \ + $(PLATFORMSRC) \ + $(BOARDSRC) \ + $(CHIBIOS)/os/various/syscalls.c \ + $(CHIBIOS)/os/hal/lib/streams/memstreams.c \ + $(CHIBIOS)/os/hal/lib/streams/chprintf.c \ + $(CHIBIOS)/os/various/shell.c \ ${HW_MASS_STORAGE_SRC_C} \ $(UTILSRC) \ $(ENGINES_SRC) \ $(CONSOLESRC) \ - $(HALSRC) \ $(DEV_SRC) \ $(HW_LAYER_EMS) \ $(CONTROLLERSSRC) \ $(CONTROLLERS_ALGO_SRC) \ $(CONTROLLERS_CORE_SRC) \ $(CONTROLLERS_SENSORS_SRC) \ - $(PLATFORMSRC) \ - $(BOARDSRC) \ $(FATFSSRC) \ $(SYSTEMSRC) @@ -188,13 +208,22 @@ TCSRC = TCPPSRC = # List ASM source files here -ASMSRC = $(PORTASM) +# List ASM source files here +ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) -INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \ - $(HALINC) $(PLATFORMINC) $(BOARDINC) \ - $(CHCPPINC) \ - $(CHIBIOS)/os/various \ - $(CHIBIOS)/os/various/devices_lib/accel \ +INCDIR = $(PORTINC) \ + $(OSALINC) \ + $(KERNINC) \ + $(TESTINC) \ + $(STARTUPINC) \ + $(HALINC) \ + $(PLATFORMINC) \ + $(BOARDINC) \ + $(CHCPPINC) \ + $(CHIBIOS)/os/hal/lib/streams \ + $(CHIBIOS)/os/various \ + $(CHIBIOS)/os/various/devices_lib/accel \ + $(CHIBIOS_CONTRIB)/os/various \ config/stm32f4ems \ config/engines \ config \ @@ -247,6 +276,7 @@ LD = $(TRGT)gcc #LD = $(TRGT)g++ CP = $(TRGT)objcopy AS = $(TRGT)gcc -x assembler-with-cpp +AR = $(TRGT)ar OD = $(TRGT)objdump SZ = $(TRGT)size HEX = $(CP) -O ihex @@ -268,29 +298,6 @@ CPPWARN = -Wall -Wextra # Compiler settings ############################################################################## -############################################################################## -# Start of default section -# - -# List all default C defines here, like -D_DEBUG=1 -DDEFS = - -# List all default ASM defines here, like -D_DEBUG=1 -DADEFS = - -# List all default directories to look for include files here -DINCDIR = - -# List the default directory to look for the libraries here -DLIBDIR = - -# List all default libraries here -DLIBS = - -# -# End of default section -############################################################################## - ############################################################################## # Start of user section # @@ -314,5 +321,5 @@ ULIBS = -lm # End of user defines ############################################################################## -RULESPATH = $(CHIBIOS)/os/ports/GCC/ARMCMx +RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC include $(RULESPATH)/rules.mk diff --git a/firmware/config/boards/ST_STM32F4/board.c b/firmware/config/boards/ST_STM32F4/board.c index 087ff3f6a2..4b26d39f8a 100644 --- a/firmware/config/boards/ST_STM32F4/board.c +++ b/firmware/config/boards/ST_STM32F4/board.c @@ -1,5 +1,5 @@ /* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,11 @@ limitations under the License. */ -#include "ch.h" +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + #include "hal.h" #if HAL_USE_PAL || defined(__DOXYGEN__) @@ -23,26 +27,43 @@ * @details Digital I/O ports static configuration as defined in @p board.h. * This variable is used by the HAL when initializing the PAL driver. */ -const PALConfig pal_default_config = -{ +const PALConfig pal_default_config = { +#if STM32_HAS_GPIOA {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, +#endif +#if STM32_HAS_GPIOB {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH}, +#endif +#if STM32_HAS_GPIOC {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH}, +#endif +#if STM32_HAS_GPIOD {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH}, +#endif +#if STM32_HAS_GPIOE {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH}, +#endif +#if STM32_HAS_GPIOF {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH}, +#endif +#if STM32_HAS_GPIOG {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH}, +#endif +#if STM32_HAS_GPIOH {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH}, +#endif +#if STM32_HAS_GPIOI {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH} +#endif }; #endif @@ -60,21 +81,21 @@ void __early_init(void) { /** * @brief SDC card detection. */ -bool_t sdc_lld_is_card_inserted(SDCDriver *sdcp) { +bool sdc_lld_is_card_inserted(SDCDriver *sdcp) { (void)sdcp; /* TODO: Fill the implementation.*/ - return TRUE; + return true; } /** * @brief SDC card write protection detection. */ -bool_t sdc_lld_is_write_protected(SDCDriver *sdcp) { +bool sdc_lld_is_write_protected(SDCDriver *sdcp) { (void)sdcp; /* TODO: Fill the implementation.*/ - return FALSE; + return false; } #endif /* HAL_USE_SDC */ @@ -82,21 +103,21 @@ bool_t sdc_lld_is_write_protected(SDCDriver *sdcp) { /** * @brief MMC_SPI card detection. */ -bool_t mmc_lld_is_card_inserted(MMCDriver *mmcp) { +bool mmc_lld_is_card_inserted(MMCDriver *mmcp) { (void)mmcp; /* TODO: Fill the implementation.*/ - return TRUE; + return true; } /** * @brief MMC_SPI card write protection detection. */ -bool_t mmc_lld_is_write_protected(MMCDriver *mmcp) { +bool mmc_lld_is_write_protected(MMCDriver *mmcp) { (void)mmcp; /* TODO: Fill the implementation.*/ - return FALSE; + return false; } #endif diff --git a/firmware/config/boards/ST_STM32F4/board.h b/firmware/config/boards/ST_STM32F4/board.h index c56d40a7dd..270c90873d 100644 --- a/firmware/config/boards/ST_STM32F4/board.h +++ b/firmware/config/boards/ST_STM32F4/board.h @@ -1,5 +1,5 @@ /* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,8 +14,14 @@ limitations under the License. */ -#ifndef _BOARD_H_ -#define _BOARD_H_ +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#ifndef BOARD_H +#define BOARD_H + /* * Setup for STMicroelectronics STM32F4-Discovery board. @@ -25,32 +31,33 @@ * Board identifier. */ #define BOARD_ST_STM32F4_DISCOVERY -#define BOARD_NAME "STMicroelectronics STM32F4-Discovery" - -#define STM32_LSECLK 32768 +#define BOARD_NAME "STM32F4-Discovery for RusEFI" /* * Board oscillators-related settings. * NOTE: LSE not fitted. */ #if !defined(STM32_LSECLK) -#define STM32_LSECLK 0 +#define STM32_LSECLK 32768U #endif #if !defined(STM32_HSECLK) -#define STM32_HSECLK 8000000 +#define STM32_HSECLK 8000000U #endif /* * Board voltages. * Required for performance limits calculation. */ -#define STM32_VDD 300 +#define STM32_VDD 300U /* * MCU type as defined in the ST header. + * this declaration would cause stm32_registry.h to define STM32F40_41xxx and STM32F4XX automatically + * + * See also STM32F4xx_MCUCONF is defined in mcuconf.h */ -#define STM32F40_41xxx +#define STM32F407xx /* * IO pins assignments. @@ -208,27 +215,70 @@ #define GPIOI_PIN14 14 #define GPIOI_PIN15 15 +/* + * IO lines assignments. + */ +#define LINE_BUTTON PAL_LINE(GPIOA, 0U) +#define LINE_LRCK PAL_LINE(GPIOA, 4U) +#define LINE_SPC PAL_LINE(GPIOA, 5U) +#define LINE_SDO PAL_LINE(GPIOA, 6U) +#define LINE_SDI PAL_LINE(GPIOA, 7U) +#define LINE_VBUS_FS PAL_LINE(GPIOA, 9U) +#define LINE_OTG_FS_ID PAL_LINE(GPIOA, 10U) +#define LINE_OTG_FS_DM PAL_LINE(GPIOA, 11U) +#define LINE_OTG_FS_DP PAL_LINE(GPIOA, 12U) +#define LINE_SWDIO PAL_LINE(GPIOA, 13U) +#define LINE_SWCLK PAL_LINE(GPIOA, 14U) + +#define LINE_SWO PAL_LINE(GPIOB, 3U) +#define LINE_SCL PAL_LINE(GPIOB, 6U) +#define LINE_SDA PAL_LINE(GPIOB, 9U) +#define LINE_CLK_IN PAL_LINE(GPIOB, 10U) + +#define LINE_OTG_FS_POWER_ON PAL_LINE(GPIOC, 0U) +#define LINE_PDM_OUT PAL_LINE(GPIOC, 3U) +#define LINE_MCLK PAL_LINE(GPIOC, 7U) +#define LINE_SCLK PAL_LINE(GPIOC, 10U) +#define LINE_SDIN PAL_LINE(GPIOC, 12U) + +#define LINE_RESET PAL_LINE(GPIOD, 4U) +#define LINE_OVER_CURRENT PAL_LINE(GPIOD, 5U) +#define LINE_LED4 PAL_LINE(GPIOD, 12U) +#define LINE_LED3 PAL_LINE(GPIOD, 13U) +#define LINE_LED5 PAL_LINE(GPIOD, 14U) +#define LINE_LED6 PAL_LINE(GPIOD, 15U) + +#define LINE_INT1 PAL_LINE(GPIOE, 0U) +#define LINE_INT2 PAL_LINE(GPIOE, 1U) +#define LINE_CS_SPI PAL_LINE(GPIOE, 3U) + + + +#define LINE_OSC_IN PAL_LINE(GPIOH, 0U) +#define LINE_OSC_OUT PAL_LINE(GPIOH, 1U) + + /* * I/O ports initial setup, this configuration is established soon after reset * in the initialization code. * Please refer to the STM32 Reference Manual for details. */ -#define PIN_MODE_INPUT(n) (0U << ((n) * 2)) -#define PIN_MODE_OUTPUT(n) (1U << ((n) * 2)) -#define PIN_MODE_ALTERNATE(n) (2U << ((n) * 2)) -#define PIN_MODE_ANALOG(n) (3U << ((n) * 2)) +#define PIN_MODE_INPUT(n) (0U << ((n) * 2U)) +#define PIN_MODE_OUTPUT(n) (1U << ((n) * 2U)) +#define PIN_MODE_ALTERNATE(n) (2U << ((n) * 2U)) +#define PIN_MODE_ANALOG(n) (3U << ((n) * 2U)) #define PIN_ODR_LOW(n) (0U << (n)) #define PIN_ODR_HIGH(n) (1U << (n)) #define PIN_OTYPE_PUSHPULL(n) (0U << (n)) #define PIN_OTYPE_OPENDRAIN(n) (1U << (n)) -#define PIN_OSPEED_2M(n) (0U << ((n) * 2)) -#define PIN_OSPEED_25M(n) (1U << ((n) * 2)) -#define PIN_OSPEED_50M(n) (2U << ((n) * 2)) -#define PIN_OSPEED_100M(n) (3U << ((n) * 2)) -#define PIN_PUPDR_FLOATING(n) (0U << ((n) * 2)) -#define PIN_PUPDR_PULLUP(n) (1U << ((n) * 2)) -#define PIN_PUPDR_PULLDOWN(n) (2U << ((n) * 2)) -#define PIN_AFIO_AF(n, v) ((v##U) << ((n % 8) * 4)) +#define PIN_OSPEED_VERYLOW(n) (0U << ((n) * 2U)) +#define PIN_OSPEED_LOW(n) (1U << ((n) * 2U)) +#define PIN_OSPEED_MEDIUM(n) (2U << ((n) * 2U)) +#define PIN_OSPEED_HIGH(n) (3U << ((n) * 2U)) +#define PIN_PUPDR_FLOATING(n) (0U << ((n) * 2U)) +#define PIN_PUPDR_PULLUP(n) (1U << ((n) * 2U)) +#define PIN_PUPDR_PULLDOWN(n) (2U << ((n) * 2U)) +#define PIN_AFIO_AF(n, v) ((v) << (((n) % 8U) * 4U)) /* * GPIOA setup: @@ -282,22 +332,22 @@ PIN_OTYPE_PUSHPULL(GPIOA_SWDIO) | \ PIN_OTYPE_PUSHPULL(GPIOA_SWCLK) | \ PIN_OTYPE_PUSHPULL(GPIOA_PIN15)) -#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_100M(GPIOA_BUTTON) | \ - PIN_OSPEED_100M(GPIOA_PIN1) | \ - PIN_OSPEED_100M(GPIOA_PIN2) | \ - PIN_OSPEED_100M(GPIOA_PIN3) | \ - PIN_OSPEED_100M(GPIOA_LRCK) | \ - PIN_OSPEED_50M(GPIOA_SPC) | \ - PIN_OSPEED_50M(GPIOA_SDO) | \ - PIN_OSPEED_50M(GPIOA_SDI) | \ - PIN_OSPEED_100M(GPIOA_PIN8) | \ - PIN_OSPEED_100M(GPIOA_VBUS_FS) | \ - PIN_OSPEED_100M(GPIOA_OTG_FS_ID) | \ - PIN_OSPEED_100M(GPIOA_OTG_FS_DM) | \ - PIN_OSPEED_100M(GPIOA_OTG_FS_DP) | \ - PIN_OSPEED_100M(GPIOA_SWDIO) | \ - PIN_OSPEED_100M(GPIOA_SWCLK) | \ - PIN_OSPEED_100M(GPIOA_PIN15)) +#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_HIGH(GPIOA_BUTTON) | \ + PIN_OSPEED_HIGH(GPIOA_PIN1) | \ + PIN_OSPEED_HIGH(GPIOA_PIN2) | \ + PIN_OSPEED_HIGH(GPIOA_PIN3) | \ + PIN_OSPEED_HIGH(GPIOA_LRCK) | \ + PIN_OSPEED_MEDIUM(GPIOA_SPC) | \ + PIN_OSPEED_MEDIUM(GPIOA_SDO) | \ + PIN_OSPEED_MEDIUM(GPIOA_SDI) | \ + PIN_OSPEED_HIGH(GPIOA_PIN8) | \ + PIN_OSPEED_HIGH(GPIOA_VBUS_FS) | \ + PIN_OSPEED_HIGH(GPIOA_OTG_FS_ID) | \ + PIN_OSPEED_HIGH(GPIOA_OTG_FS_DM) | \ + PIN_OSPEED_HIGH(GPIOA_OTG_FS_DP) | \ + PIN_OSPEED_HIGH(GPIOA_SWDIO) | \ + PIN_OSPEED_HIGH(GPIOA_SWCLK) | \ + PIN_OSPEED_HIGH(GPIOA_PIN15)) #define VAL_GPIOA_PUPDR (PIN_PUPDR_FLOATING(GPIOA_BUTTON) | \ PIN_PUPDR_PULLUP(GPIOA_PIN1) | \ PIN_PUPDR_PULLUP(GPIOA_PIN2) | \ @@ -330,22 +380,22 @@ PIN_ODR_HIGH(GPIOA_SWDIO) | \ PIN_ODR_HIGH(GPIOA_SWCLK) | \ PIN_ODR_HIGH(GPIOA_PIN15)) -#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_BUTTON, 0) | \ - PIN_AFIO_AF(GPIOA_PIN1, 0) | \ - PIN_AFIO_AF(GPIOA_PIN2, 0) | \ - PIN_AFIO_AF(GPIOA_PIN3, 0) | \ - PIN_AFIO_AF(GPIOA_LRCK, 6) | \ - PIN_AFIO_AF(GPIOA_SPC, 5) | \ - PIN_AFIO_AF(GPIOA_SDO, 5) | \ - PIN_AFIO_AF(GPIOA_SDI, 5)) -#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_PIN8, 0) | \ - PIN_AFIO_AF(GPIOA_VBUS_FS, 0) | \ - PIN_AFIO_AF(GPIOA_OTG_FS_ID, 10) | \ - PIN_AFIO_AF(GPIOA_OTG_FS_DM, 10) | \ - PIN_AFIO_AF(GPIOA_OTG_FS_DP, 10) | \ - PIN_AFIO_AF(GPIOA_SWDIO, 0) | \ - PIN_AFIO_AF(GPIOA_SWCLK, 0) | \ - PIN_AFIO_AF(GPIOA_PIN15, 0)) +#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_BUTTON, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOA_LRCK, 6U) | \ + PIN_AFIO_AF(GPIOA_SPC, 5U) | \ + PIN_AFIO_AF(GPIOA_SDO, 5U) | \ + PIN_AFIO_AF(GPIOA_SDI, 5U)) +#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOA_VBUS_FS, 0U) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_ID, 10U) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_DM, 10U) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_DP, 10U) | \ + PIN_AFIO_AF(GPIOA_SWDIO, 0U) | \ + PIN_AFIO_AF(GPIOA_SWCLK, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN15, 0U)) /* * GPIOB setup: @@ -376,8 +426,8 @@ PIN_MODE_ALTERNATE(GPIOB_SCL) | \ PIN_MODE_INPUT(GPIOB_PIN7) | \ PIN_MODE_INPUT(GPIOB_PIN8) | \ - PIN_MODE_INPUT(GPIOB_PIN9) | \ - PIN_MODE_INPUT(GPIOB_PIN10) | \ + PIN_MODE_INPUT(GPIOB_PIN9) | \ + PIN_MODE_INPUT(GPIOB_PIN10) | \ PIN_MODE_INPUT(GPIOB_PIN11) | \ PIN_MODE_INPUT(GPIOB_PIN12) | \ PIN_MODE_INPUT(GPIOB_PIN13) | \ @@ -389,7 +439,7 @@ PIN_OTYPE_PUSHPULL(GPIOB_SWO) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN4) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN5) | \ - PIN_OTYPE_PUSHPULL(GPIOB_SCL) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_SCL) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN7) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN8) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN9) | \ @@ -399,28 +449,28 @@ PIN_OTYPE_PUSHPULL(GPIOB_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOB_PIN15)) -#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_100M(GPIOB_PIN0) | \ - PIN_OSPEED_100M(GPIOB_PIN1) | \ - PIN_OSPEED_100M(GPIOB_PIN2) | \ - PIN_OSPEED_100M(GPIOB_SWO) | \ - PIN_OSPEED_100M(GPIOB_PIN4) | \ - PIN_OSPEED_100M(GPIOB_PIN5) | \ - PIN_OSPEED_100M(GPIOB_SCL) | \ - PIN_OSPEED_100M(GPIOB_PIN7) | \ - PIN_OSPEED_100M(GPIOB_PIN8) | \ - PIN_OSPEED_100M(GPIOB_PIN9) | \ - PIN_OSPEED_100M(GPIOB_PIN10) | \ - PIN_OSPEED_100M(GPIOB_PIN11) | \ - PIN_OSPEED_100M(GPIOB_PIN12) | \ - PIN_OSPEED_100M(GPIOB_PIN13) | \ - PIN_OSPEED_100M(GPIOB_PIN14) | \ - PIN_OSPEED_100M(GPIOB_PIN15)) -#define VAL_GPIOB_PUPDR (PIN_OTYPE_PUSHPULL(GPIOB_PIN0) | \ - PIN_OTYPE_PUSHPULL(GPIOB_PIN1) | \ - PIN_OTYPE_PUSHPULL(GPIOB_PIN2) | \ +#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_HIGH(GPIOB_PIN0) | \ + PIN_OSPEED_HIGH(GPIOB_PIN1) | \ + PIN_OSPEED_HIGH(GPIOB_PIN2) | \ + PIN_OSPEED_HIGH(GPIOB_SWO) | \ + PIN_OSPEED_HIGH(GPIOB_PIN4) | \ + PIN_OSPEED_HIGH(GPIOB_PIN5) | \ + PIN_OSPEED_HIGH(GPIOB_SCL) | \ + PIN_OSPEED_HIGH(GPIOB_PIN7) | \ + PIN_OSPEED_HIGH(GPIOB_PIN8) | \ + PIN_OSPEED_HIGH(GPIOB_PIN9) | \ + PIN_OSPEED_HIGH(GPIOB_PIN10) | \ + PIN_OSPEED_HIGH(GPIOB_PIN11) | \ + PIN_OSPEED_HIGH(GPIOB_PIN12) | \ + PIN_OSPEED_HIGH(GPIOB_PIN13) | \ + PIN_OSPEED_HIGH(GPIOB_PIN14) | \ + PIN_OSPEED_HIGH(GPIOB_PIN15)) +#define VAL_GPIOB_PUPDR (PIN_PUPDR_PULLUP(GPIOB_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN2) | \ PIN_PUPDR_FLOATING(GPIOB_SWO) | \ - PIN_PUPDR_PULLDOWN(GPIOB_PIN4) | \ - PIN_PUPDR_PULLDOWN(GPIOB_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN5) | \ PIN_PUPDR_FLOATING(GPIOB_SCL) | \ PIN_PUPDR_PULLDOWN(GPIOB_PIN7) | \ PIN_PUPDR_PULLDOWN(GPIOB_PIN8) | \ @@ -447,22 +497,22 @@ PIN_ODR_HIGH(GPIOB_PIN13) | \ PIN_ODR_HIGH(GPIOB_PIN14) | \ PIN_ODR_HIGH(GPIOB_PIN15)) -#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_PIN0, 0) | \ - PIN_AFIO_AF(GPIOB_PIN1, 0) | \ - PIN_AFIO_AF(GPIOB_PIN2, 0) | \ - PIN_AFIO_AF(GPIOB_SWO, 0) | \ - PIN_AFIO_AF(GPIOB_PIN4, 0) | \ - PIN_AFIO_AF(GPIOB_PIN5, 0) | \ - PIN_AFIO_AF(GPIOB_SCL, 4) | \ - PIN_AFIO_AF(GPIOB_PIN7, 0)) -#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_PIN8, 0) | \ - PIN_AFIO_AF(GPIOB_PIN9, 4) | \ - PIN_AFIO_AF(GPIOB_PIN10, 0) | \ - PIN_AFIO_AF(GPIOB_PIN11, 0) | \ - PIN_AFIO_AF(GPIOB_PIN12, 0) | \ - PIN_AFIO_AF(GPIOB_PIN13, 0) | \ - PIN_AFIO_AF(GPIOB_PIN14, 0) | \ - PIN_AFIO_AF(GPIOB_PIN15, 0)) +#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOB_SWO, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOB_SCL, 4U) | \ + PIN_AFIO_AF(GPIOB_PIN7, 0U)) +#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN15, 0U)) /* * GPIOC setup: @@ -512,26 +562,26 @@ PIN_OTYPE_PUSHPULL(GPIOC_PIN9) | \ PIN_OTYPE_PUSHPULL(GPIOC_PIN10) | \ PIN_OTYPE_PUSHPULL(GPIOC_PIN11) | \ - PIN_OTYPE_PUSHPULL(GPIOC_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN10) | \ PIN_OTYPE_PUSHPULL(GPIOC_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOC_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOC_PIN15)) -#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_100M(GPIOC_OTG_FS_POWER_ON) |\ - PIN_OSPEED_100M(GPIOC_PIN1) | \ - PIN_OSPEED_100M(GPIOC_PIN2) | \ - PIN_OSPEED_100M(GPIOC_PIN3) | \ - PIN_OSPEED_100M(GPIOC_PIN4) | \ - PIN_OSPEED_100M(GPIOC_PIN5) | \ - PIN_OSPEED_100M(GPIOC_PIN6) | \ - PIN_OSPEED_100M(GPIOC_PIN7) | \ - PIN_OSPEED_100M(GPIOC_PIN8) | \ - PIN_OSPEED_100M(GPIOC_PIN9) | \ - PIN_OSPEED_100M(GPIOC_PIN10) | \ - PIN_OSPEED_100M(GPIOC_PIN11) | \ - PIN_OSPEED_100M(GPIOC_PIN12) | \ - PIN_OSPEED_100M(GPIOC_PIN13) | \ - PIN_OSPEED_100M(GPIOC_PIN14) | \ - PIN_OSPEED_100M(GPIOC_PIN15)) +#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_HIGH(GPIOC_OTG_FS_POWER_ON) |\ + PIN_OSPEED_HIGH(GPIOC_PIN1) | \ + PIN_OSPEED_HIGH(GPIOC_PIN2) | \ + PIN_OSPEED_HIGH(GPIOC_PIN3) | \ + PIN_OSPEED_HIGH(GPIOC_PIN4) | \ + PIN_OSPEED_HIGH(GPIOC_PIN5) | \ + PIN_OSPEED_HIGH(GPIOC_PIN6) | \ + PIN_OSPEED_HIGH(GPIOC_PIN7) | \ + PIN_OSPEED_HIGH(GPIOC_PIN8) | \ + PIN_OSPEED_HIGH(GPIOC_PIN9) | \ + PIN_OSPEED_HIGH(GPIOC_PIN10) | \ + PIN_OSPEED_HIGH(GPIOC_PIN11) | \ + PIN_OSPEED_HIGH(GPIOC_PIN12) | \ + PIN_OSPEED_HIGH(GPIOC_PIN13) | \ + PIN_OSPEED_HIGH(GPIOC_PIN14) | \ + PIN_OSPEED_HIGH(GPIOC_PIN15)) #define VAL_GPIOC_PUPDR (PIN_PUPDR_FLOATING(GPIOC_OTG_FS_POWER_ON) |\ PIN_PUPDR_PULLDOWN(GPIOC_PIN1) | \ PIN_PUPDR_PULLDOWN(GPIOC_PIN2) | \ @@ -564,22 +614,22 @@ PIN_ODR_HIGH(GPIOC_PIN13) | \ PIN_ODR_HIGH(GPIOC_PIN14) | \ PIN_ODR_HIGH(GPIOC_PIN15)) -#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_OTG_FS_POWER_ON, 0) |\ - PIN_AFIO_AF(GPIOC_PIN1, 0) | \ - PIN_AFIO_AF(GPIOC_PIN2, 0) | \ - PIN_AFIO_AF(GPIOC_PIN3, 0) | \ - PIN_AFIO_AF(GPIOC_PIN4, 0) | \ - PIN_AFIO_AF(GPIOC_PIN5, 0) | \ - PIN_AFIO_AF(GPIOC_PIN6, 0) | \ - PIN_AFIO_AF(GPIOC_PIN7, 6)) -#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_PIN8, 0) | \ - PIN_AFIO_AF(GPIOC_PIN9, 0) | \ - PIN_AFIO_AF(GPIOC_PIN10, 6) | \ - PIN_AFIO_AF(GPIOC_PIN11, 0) | \ - PIN_AFIO_AF(GPIOC_PIN12, 6) | \ - PIN_AFIO_AF(GPIOC_PIN13, 0) | \ - PIN_AFIO_AF(GPIOC_PIN14, 0) | \ - PIN_AFIO_AF(GPIOC_PIN15, 0)) +#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_OTG_FS_POWER_ON, 0U) |\ + PIN_AFIO_AF(GPIOC_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN7, 0U)) +#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN15, 0U)) /* * GPIOD setup: @@ -633,32 +683,32 @@ PIN_OTYPE_PUSHPULL(GPIOD_LED3) | \ PIN_OTYPE_PUSHPULL(GPIOD_LED5) | \ PIN_OTYPE_PUSHPULL(GPIOD_LED6)) -#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_100M(GPIOD_PIN0) | \ - PIN_OSPEED_100M(GPIOD_PIN1) | \ - PIN_OSPEED_100M(GPIOD_PIN2) | \ - PIN_OSPEED_100M(GPIOD_PIN3) | \ - PIN_OSPEED_100M(GPIOD_RESET) | \ - PIN_OSPEED_100M(GPIOD_OVER_CURRENT) | \ - PIN_OSPEED_100M(GPIOD_PIN6) | \ - PIN_OSPEED_100M(GPIOD_PIN7) | \ - PIN_OSPEED_100M(GPIOD_PIN8) | \ - PIN_OSPEED_100M(GPIOD_PIN9) | \ - PIN_OSPEED_100M(GPIOD_PIN10) | \ - PIN_OSPEED_100M(GPIOD_PIN11) | \ - PIN_OSPEED_100M(GPIOD_LED4) | \ - PIN_OSPEED_100M(GPIOD_LED3) | \ - PIN_OSPEED_100M(GPIOD_LED5) | \ - PIN_OSPEED_100M(GPIOD_LED6)) -#define VAL_GPIOD_PUPDR (PIN_PUPDR_PULLDOWN(GPIOD_PIN0) | \ - PIN_PUPDR_PULLDOWN(GPIOD_PIN1) | \ - PIN_PUPDR_PULLDOWN(GPIOD_PIN2) | \ - PIN_PUPDR_PULLDOWN(GPIOD_PIN3) | \ +#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_HIGH(GPIOD_PIN0) | \ + PIN_OSPEED_HIGH(GPIOD_PIN1) | \ + PIN_OSPEED_HIGH(GPIOD_PIN2) | \ + PIN_OSPEED_HIGH(GPIOD_PIN3) | \ + PIN_OSPEED_HIGH(GPIOD_RESET) | \ + PIN_OSPEED_HIGH(GPIOD_OVER_CURRENT) | \ + PIN_OSPEED_HIGH(GPIOD_PIN6) | \ + PIN_OSPEED_HIGH(GPIOD_PIN7) | \ + PIN_OSPEED_HIGH(GPIOD_PIN8) | \ + PIN_OSPEED_HIGH(GPIOD_PIN9) | \ + PIN_OSPEED_HIGH(GPIOD_PIN10) | \ + PIN_OSPEED_HIGH(GPIOD_PIN11) | \ + PIN_OSPEED_HIGH(GPIOD_LED4) | \ + PIN_OSPEED_HIGH(GPIOD_LED3) | \ + PIN_OSPEED_HIGH(GPIOD_LED5) | \ + PIN_OSPEED_HIGH(GPIOD_LED6)) +#define VAL_GPIOD_PUPDR (PIN_PUPDR_PULLUP(GPIOD_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN3) | \ PIN_PUPDR_FLOATING(GPIOD_RESET) | \ PIN_PUPDR_FLOATING(GPIOD_OVER_CURRENT) |\ - PIN_PUPDR_PULLDOWN(GPIOD_PIN6) | \ - PIN_PUPDR_PULLDOWN(GPIOD_PIN7) | \ - PIN_PUPDR_PULLDOWN(GPIOD_PIN8) | \ - PIN_PUPDR_PULLDOWN(GPIOD_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN9) | \ PIN_PUPDR_PULLUP(GPIOD_PIN10) | \ PIN_PUPDR_PULLUP(GPIOD_PIN11) | \ PIN_PUPDR_FLOATING(GPIOD_LED4) | \ @@ -681,30 +731,30 @@ PIN_ODR_LOW(GPIOD_LED3) | \ PIN_ODR_LOW(GPIOD_LED5) | \ PIN_ODR_LOW(GPIOD_LED6)) -#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0) | \ - PIN_AFIO_AF(GPIOD_PIN1, 0) | \ - PIN_AFIO_AF(GPIOD_PIN2, 0) | \ - PIN_AFIO_AF(GPIOD_PIN3, 0) | \ - PIN_AFIO_AF(GPIOD_RESET, 0) | \ - PIN_AFIO_AF(GPIOD_OVER_CURRENT, 0) | \ - PIN_AFIO_AF(GPIOD_PIN6, 0) | \ - PIN_AFIO_AF(GPIOD_PIN7, 0)) -#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_PIN8, 0) | \ - PIN_AFIO_AF(GPIOD_PIN9, 0) | \ - PIN_AFIO_AF(GPIOD_PIN10, 0) | \ - PIN_AFIO_AF(GPIOD_PIN11, 0) | \ - PIN_AFIO_AF(GPIOD_LED4, 0) | \ - PIN_AFIO_AF(GPIOD_LED3, 0) | \ - PIN_AFIO_AF(GPIOD_LED5, 0) | \ - PIN_AFIO_AF(GPIOD_LED6, 0)) +#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOD_RESET, 0U) | \ + PIN_AFIO_AF(GPIOD_OVER_CURRENT, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN7, 0U)) +#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOD_LED4, 0U) | \ + PIN_AFIO_AF(GPIOD_LED3, 0U) | \ + PIN_AFIO_AF(GPIOD_LED5, 0U) | \ + PIN_AFIO_AF(GPIOD_LED6, 0U)) /* * GPIOE setup: * - * PE0 - PIN0 (input floating). - * PE1 - PIN1 (input floating). + * PE0 - INT1 (input floating). + * PE1 - INT2 (input floating). * PE2 - PIN2 (input floating). - * PE3 - PIN3 (input floating). + * PE3 - CS_SPI (output pushpull maximum). * PE4 - PIN4 (input floating). * PE5 - PIN5 (input floating). * PE6 - PIN6 (input floating). @@ -721,7 +771,7 @@ #define VAL_GPIOE_MODER (PIN_MODE_INPUT(GPIOE_PIN0) | \ PIN_MODE_INPUT(GPIOE_PIN1) | \ PIN_MODE_INPUT(GPIOE_PIN2) | \ - PIN_MODE_OUTPUT(GPIOE_PIN3) | \ + PIN_MODE_INPUT(GPIOE_PIN3) | \ PIN_MODE_INPUT(GPIOE_PIN4) | \ PIN_MODE_INPUT(GPIOE_PIN5) | \ PIN_MODE_INPUT(GPIOE_PIN6) | \ @@ -750,38 +800,38 @@ PIN_OTYPE_PUSHPULL(GPIOE_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOE_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOE_PIN15)) -#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_100M(GPIOE_PIN0) | \ - PIN_OSPEED_100M(GPIOE_PIN1) | \ - PIN_OSPEED_100M(GPIOE_PIN2) | \ - PIN_OSPEED_100M(GPIOE_PIN3) | \ - PIN_OSPEED_100M(GPIOE_PIN4) | \ - PIN_OSPEED_100M(GPIOE_PIN5) | \ - PIN_OSPEED_100M(GPIOE_PIN6) | \ - PIN_OSPEED_100M(GPIOE_PIN7) | \ - PIN_OSPEED_100M(GPIOE_PIN8) | \ - PIN_OSPEED_100M(GPIOE_PIN9) | \ - PIN_OSPEED_100M(GPIOE_PIN10) | \ - PIN_OSPEED_100M(GPIOE_PIN11) | \ - PIN_OSPEED_100M(GPIOE_PIN12) | \ - PIN_OSPEED_100M(GPIOE_PIN13) | \ - PIN_OSPEED_100M(GPIOE_PIN14) | \ - PIN_OSPEED_100M(GPIOE_PIN15)) -#define VAL_GPIOE_PUPDR (PIN_PUPDR_PULLDOWN(GPIOE_PIN0) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN1) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN2) | \ - PIN_PUPDR_FLOATING(GPIOE_PIN3) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN4) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN5) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN6) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN7) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN8) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN9) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN10) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN11) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN12) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN13) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN14) | \ - PIN_PUPDR_PULLDOWN(GPIOE_PIN15)) +#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_HIGH(GPIOE_PIN0) | \ + PIN_OSPEED_HIGH(GPIOE_PIN1) | \ + PIN_OSPEED_HIGH(GPIOE_PIN2) | \ + PIN_OSPEED_HIGH(GPIOE_PIN3) | \ + PIN_OSPEED_HIGH(GPIOE_PIN4) | \ + PIN_OSPEED_HIGH(GPIOE_PIN5) | \ + PIN_OSPEED_HIGH(GPIOE_PIN6) | \ + PIN_OSPEED_HIGH(GPIOE_PIN7) | \ + PIN_OSPEED_HIGH(GPIOE_PIN8) | \ + PIN_OSPEED_HIGH(GPIOE_PIN9) | \ + PIN_OSPEED_HIGH(GPIOE_PIN10) | \ + PIN_OSPEED_HIGH(GPIOE_PIN11) | \ + PIN_OSPEED_HIGH(GPIOE_PIN12) | \ + PIN_OSPEED_HIGH(GPIOE_PIN13) | \ + PIN_OSPEED_HIGH(GPIOE_PIN14) | \ + PIN_OSPEED_HIGH(GPIOE_PIN15)) +#define VAL_GPIOE_PUPDR (PIN_PUPDR_FLOATING(GPIOE_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN15)) #define VAL_GPIOE_ODR (PIN_ODR_HIGH(GPIOE_PIN0) | \ PIN_ODR_HIGH(GPIOE_PIN1) | \ PIN_ODR_HIGH(GPIOE_PIN2) | \ @@ -798,22 +848,22 @@ PIN_ODR_HIGH(GPIOE_PIN13) | \ PIN_ODR_HIGH(GPIOE_PIN14) | \ PIN_ODR_HIGH(GPIOE_PIN15)) -#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_PIN0, 0) | \ - PIN_AFIO_AF(GPIOE_PIN1, 0) | \ - PIN_AFIO_AF(GPIOE_PIN2, 0) | \ - PIN_AFIO_AF(GPIOE_PIN3, 0) | \ - PIN_AFIO_AF(GPIOE_PIN4, 0) | \ - PIN_AFIO_AF(GPIOE_PIN5, 0) | \ - PIN_AFIO_AF(GPIOE_PIN6, 0) | \ - PIN_AFIO_AF(GPIOE_PIN7, 0)) -#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_PIN8, 0) | \ - PIN_AFIO_AF(GPIOE_PIN9, 0) | \ - PIN_AFIO_AF(GPIOE_PIN10, 0) | \ - PIN_AFIO_AF(GPIOE_PIN11, 0) | \ - PIN_AFIO_AF(GPIOE_PIN12, 0) | \ - PIN_AFIO_AF(GPIOE_PIN13, 0) | \ - PIN_AFIO_AF(GPIOE_PIN14, 0) | \ - PIN_AFIO_AF(GPIOE_PIN15, 0)) +#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN7, 0U)) +#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN15, 0U)) /* * GPIOF setup: @@ -867,22 +917,22 @@ PIN_OTYPE_PUSHPULL(GPIOF_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOF_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOF_PIN15)) -#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_100M(GPIOF_PIN0) | \ - PIN_OSPEED_100M(GPIOF_PIN1) | \ - PIN_OSPEED_100M(GPIOF_PIN2) | \ - PIN_OSPEED_100M(GPIOF_PIN3) | \ - PIN_OSPEED_100M(GPIOF_PIN4) | \ - PIN_OSPEED_100M(GPIOF_PIN5) | \ - PIN_OSPEED_100M(GPIOF_PIN6) | \ - PIN_OSPEED_100M(GPIOF_PIN7) | \ - PIN_OSPEED_100M(GPIOF_PIN8) | \ - PIN_OSPEED_100M(GPIOF_PIN9) | \ - PIN_OSPEED_100M(GPIOF_PIN10) | \ - PIN_OSPEED_100M(GPIOF_PIN11) | \ - PIN_OSPEED_100M(GPIOF_PIN12) | \ - PIN_OSPEED_100M(GPIOF_PIN13) | \ - PIN_OSPEED_100M(GPIOF_PIN14) | \ - PIN_OSPEED_100M(GPIOF_PIN15)) +#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_HIGH(GPIOF_PIN0) | \ + PIN_OSPEED_HIGH(GPIOF_PIN1) | \ + PIN_OSPEED_HIGH(GPIOF_PIN2) | \ + PIN_OSPEED_HIGH(GPIOF_PIN3) | \ + PIN_OSPEED_HIGH(GPIOF_PIN4) | \ + PIN_OSPEED_HIGH(GPIOF_PIN5) | \ + PIN_OSPEED_HIGH(GPIOF_PIN6) | \ + PIN_OSPEED_HIGH(GPIOF_PIN7) | \ + PIN_OSPEED_HIGH(GPIOF_PIN8) | \ + PIN_OSPEED_HIGH(GPIOF_PIN9) | \ + PIN_OSPEED_HIGH(GPIOF_PIN10) | \ + PIN_OSPEED_HIGH(GPIOF_PIN11) | \ + PIN_OSPEED_HIGH(GPIOF_PIN12) | \ + PIN_OSPEED_HIGH(GPIOF_PIN13) | \ + PIN_OSPEED_HIGH(GPIOF_PIN14) | \ + PIN_OSPEED_HIGH(GPIOF_PIN15)) #define VAL_GPIOF_PUPDR (PIN_PUPDR_FLOATING(GPIOF_PIN0) | \ PIN_PUPDR_FLOATING(GPIOF_PIN1) | \ PIN_PUPDR_FLOATING(GPIOF_PIN2) | \ @@ -915,22 +965,22 @@ PIN_ODR_HIGH(GPIOF_PIN13) | \ PIN_ODR_HIGH(GPIOF_PIN14) | \ PIN_ODR_HIGH(GPIOF_PIN15)) -#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_PIN0, 0) | \ - PIN_AFIO_AF(GPIOF_PIN1, 0) | \ - PIN_AFIO_AF(GPIOF_PIN2, 0) | \ - PIN_AFIO_AF(GPIOF_PIN3, 0) | \ - PIN_AFIO_AF(GPIOF_PIN4, 0) | \ - PIN_AFIO_AF(GPIOF_PIN5, 0) | \ - PIN_AFIO_AF(GPIOF_PIN6, 0) | \ - PIN_AFIO_AF(GPIOF_PIN7, 0)) -#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0) | \ - PIN_AFIO_AF(GPIOF_PIN9, 0) | \ - PIN_AFIO_AF(GPIOF_PIN10, 0) | \ - PIN_AFIO_AF(GPIOF_PIN11, 0) | \ - PIN_AFIO_AF(GPIOF_PIN12, 0) | \ - PIN_AFIO_AF(GPIOF_PIN13, 0) | \ - PIN_AFIO_AF(GPIOF_PIN14, 0) | \ - PIN_AFIO_AF(GPIOF_PIN15, 0)) +#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN7, 0U)) +#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN15, 0U)) /* * GPIOG setup: @@ -984,22 +1034,22 @@ PIN_OTYPE_PUSHPULL(GPIOG_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOG_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOG_PIN15)) -#define VAL_GPIOG_OSPEEDR (PIN_OSPEED_100M(GPIOG_PIN0) | \ - PIN_OSPEED_100M(GPIOG_PIN1) | \ - PIN_OSPEED_100M(GPIOG_PIN2) | \ - PIN_OSPEED_100M(GPIOG_PIN3) | \ - PIN_OSPEED_100M(GPIOG_PIN4) | \ - PIN_OSPEED_100M(GPIOG_PIN5) | \ - PIN_OSPEED_100M(GPIOG_PIN6) | \ - PIN_OSPEED_100M(GPIOG_PIN7) | \ - PIN_OSPEED_100M(GPIOG_PIN8) | \ - PIN_OSPEED_100M(GPIOG_PIN9) | \ - PIN_OSPEED_100M(GPIOG_PIN10) | \ - PIN_OSPEED_100M(GPIOG_PIN11) | \ - PIN_OSPEED_100M(GPIOG_PIN12) | \ - PIN_OSPEED_100M(GPIOG_PIN13) | \ - PIN_OSPEED_100M(GPIOG_PIN14) | \ - PIN_OSPEED_100M(GPIOG_PIN15)) +#define VAL_GPIOG_OSPEEDR (PIN_OSPEED_HIGH(GPIOG_PIN0) | \ + PIN_OSPEED_HIGH(GPIOG_PIN1) | \ + PIN_OSPEED_HIGH(GPIOG_PIN2) | \ + PIN_OSPEED_HIGH(GPIOG_PIN3) | \ + PIN_OSPEED_HIGH(GPIOG_PIN4) | \ + PIN_OSPEED_HIGH(GPIOG_PIN5) | \ + PIN_OSPEED_HIGH(GPIOG_PIN6) | \ + PIN_OSPEED_HIGH(GPIOG_PIN7) | \ + PIN_OSPEED_HIGH(GPIOG_PIN8) | \ + PIN_OSPEED_HIGH(GPIOG_PIN9) | \ + PIN_OSPEED_HIGH(GPIOG_PIN10) | \ + PIN_OSPEED_HIGH(GPIOG_PIN11) | \ + PIN_OSPEED_HIGH(GPIOG_PIN12) | \ + PIN_OSPEED_HIGH(GPIOG_PIN13) | \ + PIN_OSPEED_HIGH(GPIOG_PIN14) | \ + PIN_OSPEED_HIGH(GPIOG_PIN15)) #define VAL_GPIOG_PUPDR (PIN_PUPDR_FLOATING(GPIOG_PIN0) | \ PIN_PUPDR_FLOATING(GPIOG_PIN1) | \ PIN_PUPDR_FLOATING(GPIOG_PIN2) | \ @@ -1032,22 +1082,22 @@ PIN_ODR_HIGH(GPIOG_PIN13) | \ PIN_ODR_HIGH(GPIOG_PIN14) | \ PIN_ODR_HIGH(GPIOG_PIN15)) -#define VAL_GPIOG_AFRL (PIN_AFIO_AF(GPIOG_PIN0, 0) | \ - PIN_AFIO_AF(GPIOG_PIN1, 0) | \ - PIN_AFIO_AF(GPIOG_PIN2, 0) | \ - PIN_AFIO_AF(GPIOG_PIN3, 0) | \ - PIN_AFIO_AF(GPIOG_PIN4, 0) | \ - PIN_AFIO_AF(GPIOG_PIN5, 0) | \ - PIN_AFIO_AF(GPIOG_PIN6, 0) | \ - PIN_AFIO_AF(GPIOG_PIN7, 0)) -#define VAL_GPIOG_AFRH (PIN_AFIO_AF(GPIOG_PIN8, 0) | \ - PIN_AFIO_AF(GPIOG_PIN9, 0) | \ - PIN_AFIO_AF(GPIOG_PIN10, 0) | \ - PIN_AFIO_AF(GPIOG_PIN11, 0) | \ - PIN_AFIO_AF(GPIOG_PIN12, 0) | \ - PIN_AFIO_AF(GPIOG_PIN13, 0) | \ - PIN_AFIO_AF(GPIOG_PIN14, 0) | \ - PIN_AFIO_AF(GPIOG_PIN15, 0)) +#define VAL_GPIOG_AFRL (PIN_AFIO_AF(GPIOG_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN7, 0U)) +#define VAL_GPIOG_AFRH (PIN_AFIO_AF(GPIOG_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN15, 0U)) /* * GPIOH setup: @@ -1101,22 +1151,22 @@ PIN_OTYPE_PUSHPULL(GPIOH_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOH_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOH_PIN15)) -#define VAL_GPIOH_OSPEEDR (PIN_OSPEED_100M(GPIOH_OSC_IN) | \ - PIN_OSPEED_100M(GPIOH_OSC_OUT) | \ - PIN_OSPEED_100M(GPIOH_PIN2) | \ - PIN_OSPEED_100M(GPIOH_PIN3) | \ - PIN_OSPEED_100M(GPIOH_PIN4) | \ - PIN_OSPEED_100M(GPIOH_PIN5) | \ - PIN_OSPEED_100M(GPIOH_PIN6) | \ - PIN_OSPEED_100M(GPIOH_PIN7) | \ - PIN_OSPEED_100M(GPIOH_PIN8) | \ - PIN_OSPEED_100M(GPIOH_PIN9) | \ - PIN_OSPEED_100M(GPIOH_PIN10) | \ - PIN_OSPEED_100M(GPIOH_PIN11) | \ - PIN_OSPEED_100M(GPIOH_PIN12) | \ - PIN_OSPEED_100M(GPIOH_PIN13) | \ - PIN_OSPEED_100M(GPIOH_PIN14) | \ - PIN_OSPEED_100M(GPIOH_PIN15)) +#define VAL_GPIOH_OSPEEDR (PIN_OSPEED_HIGH(GPIOH_OSC_IN) | \ + PIN_OSPEED_HIGH(GPIOH_OSC_OUT) | \ + PIN_OSPEED_HIGH(GPIOH_PIN2) | \ + PIN_OSPEED_HIGH(GPIOH_PIN3) | \ + PIN_OSPEED_HIGH(GPIOH_PIN4) | \ + PIN_OSPEED_HIGH(GPIOH_PIN5) | \ + PIN_OSPEED_HIGH(GPIOH_PIN6) | \ + PIN_OSPEED_HIGH(GPIOH_PIN7) | \ + PIN_OSPEED_HIGH(GPIOH_PIN8) | \ + PIN_OSPEED_HIGH(GPIOH_PIN9) | \ + PIN_OSPEED_HIGH(GPIOH_PIN10) | \ + PIN_OSPEED_HIGH(GPIOH_PIN11) | \ + PIN_OSPEED_HIGH(GPIOH_PIN12) | \ + PIN_OSPEED_HIGH(GPIOH_PIN13) | \ + PIN_OSPEED_HIGH(GPIOH_PIN14) | \ + PIN_OSPEED_HIGH(GPIOH_PIN15)) #define VAL_GPIOH_PUPDR (PIN_PUPDR_FLOATING(GPIOH_OSC_IN) | \ PIN_PUPDR_FLOATING(GPIOH_OSC_OUT) | \ PIN_PUPDR_FLOATING(GPIOH_PIN2) | \ @@ -1149,22 +1199,22 @@ PIN_ODR_HIGH(GPIOH_PIN13) | \ PIN_ODR_HIGH(GPIOH_PIN14) | \ PIN_ODR_HIGH(GPIOH_PIN15)) -#define VAL_GPIOH_AFRL (PIN_AFIO_AF(GPIOH_OSC_IN, 0) | \ - PIN_AFIO_AF(GPIOH_OSC_OUT, 0) | \ - PIN_AFIO_AF(GPIOH_PIN2, 0) | \ - PIN_AFIO_AF(GPIOH_PIN3, 0) | \ - PIN_AFIO_AF(GPIOH_PIN4, 0) | \ - PIN_AFIO_AF(GPIOH_PIN5, 0) | \ - PIN_AFIO_AF(GPIOH_PIN6, 0) | \ - PIN_AFIO_AF(GPIOH_PIN7, 0)) -#define VAL_GPIOH_AFRH (PIN_AFIO_AF(GPIOH_PIN8, 0) | \ - PIN_AFIO_AF(GPIOH_PIN9, 0) | \ - PIN_AFIO_AF(GPIOH_PIN10, 0) | \ - PIN_AFIO_AF(GPIOH_PIN11, 0) | \ - PIN_AFIO_AF(GPIOH_PIN12, 0) | \ - PIN_AFIO_AF(GPIOH_PIN13, 0) | \ - PIN_AFIO_AF(GPIOH_PIN14, 0) | \ - PIN_AFIO_AF(GPIOH_PIN15, 0)) +#define VAL_GPIOH_AFRL (PIN_AFIO_AF(GPIOH_OSC_IN, 0U) | \ + PIN_AFIO_AF(GPIOH_OSC_OUT, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN7, 0U)) +#define VAL_GPIOH_AFRH (PIN_AFIO_AF(GPIOH_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN15, 0U)) /* * GPIOI setup: @@ -1218,22 +1268,22 @@ PIN_OTYPE_PUSHPULL(GPIOI_PIN13) | \ PIN_OTYPE_PUSHPULL(GPIOI_PIN14) | \ PIN_OTYPE_PUSHPULL(GPIOI_PIN15)) -#define VAL_GPIOI_OSPEEDR (PIN_OSPEED_100M(GPIOI_PIN0) | \ - PIN_OSPEED_100M(GPIOI_PIN1) | \ - PIN_OSPEED_100M(GPIOI_PIN2) | \ - PIN_OSPEED_100M(GPIOI_PIN3) | \ - PIN_OSPEED_100M(GPIOI_PIN4) | \ - PIN_OSPEED_100M(GPIOI_PIN5) | \ - PIN_OSPEED_100M(GPIOI_PIN6) | \ - PIN_OSPEED_100M(GPIOI_PIN7) | \ - PIN_OSPEED_100M(GPIOI_PIN8) | \ - PIN_OSPEED_100M(GPIOI_PIN9) | \ - PIN_OSPEED_100M(GPIOI_PIN10) | \ - PIN_OSPEED_100M(GPIOI_PIN11) | \ - PIN_OSPEED_100M(GPIOI_PIN12) | \ - PIN_OSPEED_100M(GPIOI_PIN13) | \ - PIN_OSPEED_100M(GPIOI_PIN14) | \ - PIN_OSPEED_100M(GPIOI_PIN15)) +#define VAL_GPIOI_OSPEEDR (PIN_OSPEED_HIGH(GPIOI_PIN0) | \ + PIN_OSPEED_HIGH(GPIOI_PIN1) | \ + PIN_OSPEED_HIGH(GPIOI_PIN2) | \ + PIN_OSPEED_HIGH(GPIOI_PIN3) | \ + PIN_OSPEED_HIGH(GPIOI_PIN4) | \ + PIN_OSPEED_HIGH(GPIOI_PIN5) | \ + PIN_OSPEED_HIGH(GPIOI_PIN6) | \ + PIN_OSPEED_HIGH(GPIOI_PIN7) | \ + PIN_OSPEED_HIGH(GPIOI_PIN8) | \ + PIN_OSPEED_HIGH(GPIOI_PIN9) | \ + PIN_OSPEED_HIGH(GPIOI_PIN10) | \ + PIN_OSPEED_HIGH(GPIOI_PIN11) | \ + PIN_OSPEED_HIGH(GPIOI_PIN12) | \ + PIN_OSPEED_HIGH(GPIOI_PIN13) | \ + PIN_OSPEED_HIGH(GPIOI_PIN14) | \ + PIN_OSPEED_HIGH(GPIOI_PIN15)) #define VAL_GPIOI_PUPDR (PIN_PUPDR_FLOATING(GPIOI_PIN0) | \ PIN_PUPDR_FLOATING(GPIOI_PIN1) | \ PIN_PUPDR_FLOATING(GPIOI_PIN2) | \ @@ -1266,22 +1316,22 @@ PIN_ODR_HIGH(GPIOI_PIN13) | \ PIN_ODR_HIGH(GPIOI_PIN14) | \ PIN_ODR_HIGH(GPIOI_PIN15)) -#define VAL_GPIOI_AFRL (PIN_AFIO_AF(GPIOI_PIN0, 0) | \ - PIN_AFIO_AF(GPIOI_PIN1, 0) | \ - PIN_AFIO_AF(GPIOI_PIN2, 0) | \ - PIN_AFIO_AF(GPIOI_PIN3, 0) | \ - PIN_AFIO_AF(GPIOI_PIN4, 0) | \ - PIN_AFIO_AF(GPIOI_PIN5, 0) | \ - PIN_AFIO_AF(GPIOI_PIN6, 0) | \ - PIN_AFIO_AF(GPIOI_PIN7, 0)) -#define VAL_GPIOI_AFRH (PIN_AFIO_AF(GPIOI_PIN8, 0) | \ - PIN_AFIO_AF(GPIOI_PIN9, 0) | \ - PIN_AFIO_AF(GPIOI_PIN10, 0) | \ - PIN_AFIO_AF(GPIOI_PIN11, 0) | \ - PIN_AFIO_AF(GPIOI_PIN12, 0) | \ - PIN_AFIO_AF(GPIOI_PIN13, 0) | \ - PIN_AFIO_AF(GPIOI_PIN14, 0) | \ - PIN_AFIO_AF(GPIOI_PIN15, 0)) +#define VAL_GPIOI_AFRL (PIN_AFIO_AF(GPIOI_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN7, 0U)) +#define VAL_GPIOI_AFRH (PIN_AFIO_AF(GPIOI_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN15, 0U)) #if !defined(_FROM_ASM_) @@ -1294,4 +1344,4 @@ extern "C" { #endif #endif /* _FROM_ASM_ */ -#endif /* _BOARD_H_ */ +#endif /* BOARD_H */ diff --git a/firmware/config/stm32f4ems/STM32F407xG_CCM.ld b/firmware/config/stm32f4ems/STM32F407xG_CCM.ld index 1dbaf479a9..d1a5fc1ffa 100644 --- a/firmware/config/stm32f4ems/STM32F407xG_CCM.ld +++ b/firmware/config/stm32f4ems/STM32F407xG_CCM.ld @@ -1,186 +1,51 @@ /* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, - 2011,2012,2013 Giovanni Di Sirio. + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - This file is part of ChibiOS/RT. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - ChibiOS/RT 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 3 of the License, or - (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 - ChibiOS/RT 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 . - - --- - - A special exception to the GPL can be applied should you wish to distribute - a combined work that includes ChibiOS/RT, without being obliged to provide - the source code for any proprietary components. See the file exception.txt - for full details of how and when the exception can be applied. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ /* - * ST32F407xG memory setup. + * STM32F407xG memory setup. + * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0. */ -__main_stack_size__ = 0x1000; -__process_stack_size__ = 0x0600; - MEMORY { flash : org = 0x08000000, len = 896k - ram : org = 0x20000000, len = 112k - ethram : org = 0x2001C000, len = 16k - ccmram : org = 0x10000000, len = 64k + ram0 : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */ + ram1 : org = 0x20000000, len = 112k /* SRAM1 */ + ram2 : org = 0x2001C000, len = 16k /* SRAM2 */ + ram3 : org = 0x00000000, len = 0 + ram4 : org = 0x10000000, len = 64k /* CCM SRAM */ + ram5 : org = 0x40024000, len = 4k /* BCKP SRAM */ + ram6 : org = 0x00000000, len = 0 + ram7 : org = 0x00000000, len = 0 } -__ram_start__ = ORIGIN(ram); -__ram_size__ = LENGTH(ram); -__ram_end__ = __ram_start__ + __ram_size__; +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts*/ +REGION_ALIAS("MAIN_STACK_RAM", ram0); -ENTRY(ResetHandler) +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram0); -SECTIONS -{ - . = 0; - _text = .; +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); - startup : ALIGN(16) SUBALIGN(16) - { - KEEP(*(vectors)) - } > flash +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); - constructors : ALIGN(4) SUBALIGN(4) - { - PROVIDE(__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE(__init_array_end = .); - } > flash +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); - destructors : ALIGN(4) SUBALIGN(4) - { - PROVIDE(__fini_array_start = .); - KEEP(*(.fini_array)) - KEEP(*(SORT(.fini_array.*))) - PROVIDE(__fini_array_end = .); - } > flash - - .text : ALIGN(16) SUBALIGN(16) - { - *(.text.startup.*) - *(.text) - *(.text.*) - *(.rodata) - *(.rodata.*) - *(.glue_7t) - *(.glue_7) - *(.gcc*) - } > flash - - .ARM.extab : - { - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > flash - - .ARM.exidx : { - PROVIDE(__exidx_start = .); - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - PROVIDE(__exidx_end = .); - } > flash - - .eh_frame_hdr : - { - *(.eh_frame_hdr) - } > flash - - .eh_frame : ONLY_IF_RO - { - *(.eh_frame) - } > flash - - .textalign : ONLY_IF_RO - { - . = ALIGN(8); - } > flash - - _etext = .; - _textdata = _etext; - - .stacks : - { - . = ALIGN(8); - __main_stack_base__ = .; - . += __main_stack_size__; - . = ALIGN(8); - __main_stack_end__ = .; - __process_stack_base__ = .; - __main_thread_stack_base__ = .; - . += __process_stack_size__; - . = ALIGN(8); - __process_stack_end__ = .; - __main_thread_stack_end__ = .; - } > ram - - .ccm (NOLOAD) : - { - PROVIDE(_cmm_start = .); - . = ALIGN(4); - *(.bss.mainthread.*) - . = ALIGN(4); - *(.bss._idle_thread_wa) - . = ALIGN(4); - *(.bss.rlist) - . = ALIGN(4); - *(.bss.vtlist) - . = ALIGN(4); - *(.bss.endmem) - . = ALIGN(4); - *(.bss.nextmem) - . = ALIGN(4); - *(.bss.default_heap) - . = ALIGN(4); - *(.ccm) - . = ALIGN(4); - *(.ccm.*) - . = ALIGN(4); - PROVIDE(_cmm_end = .); - } > ccmram - - .data : - { - . = ALIGN(4); - PROVIDE(_data = .); - *(.data) - . = ALIGN(4); - *(.data.*) - . = ALIGN(4); - *(.ramtext) - . = ALIGN(4); - PROVIDE(_edata = .); - } > ram AT > flash - - .bss : - { - . = ALIGN(4); - PROVIDE(_bss_start = .); - *(.bss) - . = ALIGN(4); - *(.bss.*) - . = ALIGN(4); - *(COMMON) - . = ALIGN(4); - PROVIDE(_bss_end = .); - } > ram -} - -PROVIDE(end = .); -_end = .; - -__heap_base__ = _end; -__heap_end__ = __ram_end__; +INCLUDE rules.ld diff --git a/firmware/config/stm32f4ems/chconf.h b/firmware/config/stm32f4ems/chconf.h index f9c1374828..d608f3345a 100644 --- a/firmware/config/stm32f4ems/chconf.h +++ b/firmware/config/stm32f4ems/chconf.h @@ -1,28 +1,17 @@ /* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, - 2011,2012 Giovanni Di Sirio. + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - This file is part of ChibiOS/RT. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - ChibiOS/RT 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 3 of the License, or - (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 - ChibiOS/RT 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 . - - --- - - A special exception to the GPL can be applied should you wish to distribute - a combined work that includes ChibiOS/RT, without being obliged to provide - the source code for any proprietary components. See the file exception.txt - for full details of how and when the exception can be applied. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ /** @@ -39,20 +28,12 @@ #ifndef _CHCONF_H_ #define _CHCONF_H_ -#define chDbgCheck(c, func) { \ - if (!(c)) \ - chDbgPanic3(__QUOTE_THIS(func)"()", __FILE__, __LINE__); \ -} - -#define CORTEX_PRIORITY_SYSTICK 6 - +#define COMMON_IRQ_PRIORITY 6 +#define CORTEX_PRIORITY_SYSTICK COMMON_IRQ_PRIORITY #define PORT_IDLE_THREAD_STACK_SIZE 1024 - +#define PORT_INT_REQUIRED_STACK 768 #define CHPRINTF_USE_FLOAT TRUE -#define EFI_CLOCK_LOCKS FALSE - - #if EFI_CLOCK_LOCKS #ifdef __cplusplus extern "C" @@ -70,15 +51,37 @@ extern "C" #define ON_UNLOCK_HOOK #endif /* EFI_CLOCK_LOCKS */ +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ /** - * number of ticks per second - * - * 8000 rpm equals 133Hz of crankshaft - * that's 266Hz camshaft - * for timing measures we need 95760 Hz precision + * @brief System time counter resolution. + * @note Allowed values are 16 or 32 bits. */ -#define CH_FREQUENCY 1000 +#define CH_CFG_ST_RESOLUTION 32 + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#define CH_CFG_ST_FREQUENCY 1000 + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#define CH_CFG_ST_TIMEDELTA 0 + +/** @} */ /*===========================================================================*/ /** @@ -87,15 +90,6 @@ extern "C" */ /*===========================================================================*/ -/** - * @brief System tick frequency. - * @details Frequency of the system timer that drives the system ticks. This - * setting also defines the system tick time unit. - */ -#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__) -#define CH_FREQUENCY 1000 -#endif - /** * @brief Round robin interval. * @details This constant is the number of system ticks allowed for the @@ -103,13 +97,12 @@ extern "C" * disables the preemption for threads with equal priority and the * round robin becomes cooperative. Note that higher priority * threads can still preempt, the kernel is always preemptive. - * * @note Disabling the round robin preemption makes the kernel more compact * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. */ -#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__) -#define CH_TIME_QUANTUM 20 -#endif +#define CH_CFG_TIME_QUANTUM 20 /** * @brief Managed RAM size. @@ -120,29 +113,18 @@ extern "C" * * @note In order to let the OS manage the whole RAM the linker script must * provide the @p __heap_base__ and @p __heap_end__ symbols. - * @note Requires @p CH_USE_MEMCORE. + * @note Requires @p CH_CFG_USE_MEMCORE. */ -#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__) -// memory pool is used by ff.c which is used for file logging -#define CH_MEMCORE_SIZE 2048 -#endif +#define CH_CFG_MEMCORE_SIZE 2048 /** * @brief Idle thread automatic spawn suppression. * @details When this option is activated the function @p chSysInit() - * does not spawn the idle thread automatically. The application has - * then the responsibility to do one of the following: - * - Spawn a custom idle thread at priority @p IDLEPRIO. - * - Change the main() thread priority to @p IDLEPRIO then enter - * an endless loop. In this scenario the @p main() thread acts as - * the idle thread. - * . - * @note Unless an idle thread is spawned the @p main() thread must not - * enter a sleep state. + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. */ -#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__) -#define CH_NO_IDLE_THREAD FALSE -#endif +#define CH_CFG_NO_IDLE_THREAD FALSE /** @} */ @@ -161,9 +143,7 @@ extern "C" * @note This is not related to the compiler optimization options. * @note The default is @p TRUE. */ -#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__) -#define CH_OPTIMIZE_SPEED TRUE -#endif +#define CH_CFG_OPTIMIZE_SPEED TRUE /** @} */ @@ -174,15 +154,22 @@ extern "C" */ /*===========================================================================*/ +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_TM TRUE + /** * @brief Threads registry APIs. * @details If enabled then the registry APIs are included in the kernel. * * @note The default is @p TRUE. */ -#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__) -#define CH_USE_REGISTRY TRUE -#endif +#define CH_CFG_USE_REGISTRY TRUE /** * @brief Threads synchronization APIs. @@ -191,9 +178,7 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__) -#define CH_USE_WAITEXIT FALSE -#endif +#define CH_CFG_USE_WAITEXIT TRUE /** * @brief Semaphores APIs. @@ -201,33 +186,18 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__) -#define CH_USE_SEMAPHORES TRUE -#endif +#define CH_CFG_USE_SEMAPHORES TRUE /** * @brief Semaphores queuing mode. * @details If enabled then the threads are enqueued on semaphores by * priority rather than in FIFO order. * - * @note The default is @p FALSE. Enable this if you have special requirements. - * @note Requires @p CH_USE_SEMAPHORES. + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. */ -#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__) -#define CH_USE_SEMAPHORES_PRIORITY FALSE -#endif - -/** - * @brief Atomic semaphore API. - * @details If enabled then the semaphores the @p chSemSignalWait() API - * is included in the kernel. - * - * @note The default is @p TRUE. - * @note Requires @p CH_USE_SEMAPHORES. - */ -#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__) -#define CH_USE_SEMSW FALSE -#endif +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE /** * @brief Mutexes APIs. @@ -235,9 +205,17 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__) -#define CH_USE_MUTEXES TRUE -#endif +#define CH_CFG_USE_MUTEXES TRUE + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE /** * @brief Conditional Variables APIs. @@ -245,11 +223,9 @@ extern "C" * in the kernel. * * @note The default is @p TRUE. - * @note Requires @p CH_USE_MUTEXES. + * @note Requires @p CH_CFG_USE_MUTEXES. */ -#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__) -#define CH_USE_CONDVARS FALSE -#endif +#define CH_CFG_USE_CONDVARS TRUE /** * @brief Conditional Variables APIs with timeout. @@ -257,11 +233,9 @@ extern "C" * specification are included in the kernel. * * @note The default is @p TRUE. - * @note Requires @p CH_USE_CONDVARS. + * @note Requires @p CH_CFG_USE_CONDVARS. */ -#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__) -#define CH_USE_CONDVARS_TIMEOUT FALSE -#endif +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE /** * @brief Events Flags APIs. @@ -269,9 +243,7 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__) -#define CH_USE_EVENTS TRUE -#endif +#define CH_CFG_USE_EVENTS TRUE /** * @brief Events Flags APIs with timeout. @@ -279,11 +251,9 @@ extern "C" * are included in the kernel. * * @note The default is @p TRUE. - * @note Requires @p CH_USE_EVENTS. + * @note Requires @p CH_CFG_USE_EVENTS. */ -#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__) -#define CH_USE_EVENTS_TIMEOUT TRUE -#endif +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE /** * @brief Synchronous Messages APIs. @@ -292,21 +262,18 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__) -#define CH_USE_MESSAGES TRUE -#endif +#define CH_CFG_USE_MESSAGES TRUE /** * @brief Synchronous Messages queuing mode. * @details If enabled then messages are served by priority rather than in * FIFO order. * - * @note The default is @p FALSE. Enable this if you have special requirements. - * @note Requires @p CH_USE_MESSAGES. + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. */ -#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__) -#define CH_USE_MESSAGES_PRIORITY FALSE -#endif +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE /** * @brief Mailboxes APIs. @@ -314,11 +281,9 @@ extern "C" * included in the kernel. * * @note The default is @p TRUE. - * @note Requires @p CH_USE_SEMAPHORES. + * @note Requires @p CH_CFG_USE_SEMAPHORES. */ -#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__) -#define CH_USE_MAILBOXES TRUE -#endif +#define CH_CFG_USE_MAILBOXES TRUE /** * @brief I/O Queues APIs. @@ -326,9 +291,7 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__) -#define CH_USE_QUEUES TRUE -#endif +#define CH_CFG_USE_QUEUES TRUE /** * @brief Core Memory Manager APIs. @@ -337,9 +300,7 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__) -#define CH_USE_MEMCORE TRUE -#endif +#define CH_CFG_USE_MEMCORE TRUE /** * @brief Heap Allocator APIs. @@ -347,27 +308,11 @@ extern "C" * in the kernel. * * @note The default is @p TRUE. - * @note Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or - * @p CH_USE_SEMAPHORES. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. * @note Mutexes are recommended. */ -#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__) -#define CH_USE_HEAP TRUE -#endif - -/** - * @brief C-runtime allocator. - * @details If enabled the the heap allocator APIs just wrap the C-runtime - * @p malloc() and @p free() functions. - * - * @note The default is @p FALSE. - * @note Requires @p CH_USE_HEAP. - * @note The C-runtime may or may not require @p CH_USE_MEMCORE, see the - * appropriate documentation. - */ -#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__) -#define CH_USE_MALLOC_HEAP FALSE -#endif +#define CH_CFG_USE_HEAP TRUE /** * @brief Memory Pools Allocator APIs. @@ -376,9 +321,7 @@ extern "C" * * @note The default is @p TRUE. */ -#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__) -#define CH_USE_MEMPOOLS TRUE -#endif +#define CH_CFG_USE_MEMPOOLS TRUE /** * @brief Dynamic Threads APIs. @@ -386,12 +329,10 @@ extern "C" * in the kernel. * * @note The default is @p TRUE. - * @note Requires @p CH_USE_WAITEXIT. - * @note Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. */ -#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__) -#define CH_USE_DYNAMIC FALSE -#endif +#define CH_CFG_USE_DYNAMIC FALSE /** @} */ @@ -402,6 +343,13 @@ extern "C" */ /*===========================================================================*/ +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_STATISTICS TRUE + /** * @brief Debug option, system state check. * @details If enabled the correct call protocol for system APIs is checked @@ -409,9 +357,7 @@ extern "C" * * @note The default is @p FALSE. */ -#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__) -#define CH_DBG_SYSTEM_STATE_CHECK TRUE -#endif +#define CH_DBG_SYSTEM_STATE_CHECK TRUE /** * @brief Debug option, parameters checks. @@ -420,9 +366,7 @@ extern "C" * * @note The default is @p FALSE. */ -#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_CHECKS TRUE -#endif +#define CH_DBG_ENABLE_CHECKS TRUE /** * @brief Debug option, consistency checks. @@ -432,9 +376,7 @@ extern "C" * * @note The default is @p FALSE. */ -#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_ASSERTS TRUE -#endif +#define CH_DBG_ENABLE_ASSERTS TRUE /** * @brief Debug option, trace buffer. @@ -443,9 +385,7 @@ extern "C" * * @note The default is @p FALSE. */ -#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_TRACE TRUE -#endif +#define CH_DBG_ENABLE_TRACE TRUE /** * @brief Debug option, stack checks. @@ -457,9 +397,7 @@ extern "C" * @note The default failure mode is to halt the system with the global * @p panic_msg variable set to @p NULL. */ -#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_STACK_CHECK TRUE -#endif +#define CH_DBG_ENABLE_STACK_CHECK TRUE /** * @brief Debug option, stacks initialization. @@ -469,22 +407,18 @@ extern "C" * * @note The default is @p FALSE. */ -#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__) -#define CH_DBG_FILL_THREADS TRUE -#endif +#define CH_DBG_FILL_THREADS TRUE /** * @brief Debug option, threads profiling. - * @details If enabled then a field is added to the @p Thread structure that + * @details If enabled then a field is added to the @p thread_t structure that * counts the system ticks occurred while executing the thread. * - * @note The default is @p TRUE. - * @note This debug option is defaulted to TRUE because it is required by - * some test cases into the test suite. + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. */ -#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) -#define CH_DBG_THREADS_PROFILING TRUE -#endif +#define CH_DBG_THREADS_PROFILING FALSE /** @} */ @@ -497,14 +431,12 @@ extern "C" /** * @brief Threads descriptor structure extension. - * @details User fields added to the end of the @p Thread structure. + * @details User fields added to the end of the @p thread_t structure. */ -#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__) -#define THREAD_EXT_FIELDS \ - void *activeStack; \ - int remainingStack; \ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + void *activeStack; \ + int remainingStack; \ /* Add threads custom fields here.*/ -#endif /** * @brief Threads initialization hook. @@ -513,11 +445,9 @@ extern "C" * @note It is invoked from within @p chThdInit() and implicitly from all * the threads creation APIs. */ -#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) -#define THREAD_EXT_INIT_HOOK(tp) { \ +#define CH_CFG_THREAD_INIT_HOOK(tp) { \ /* Add threads initialization code here.*/ \ } -#endif /** * @brief Threads finalization hook. @@ -527,61 +457,62 @@ extern "C" * @note It is also invoked when the threads simply return in order to * terminate. */ -#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__) -#define THREAD_EXT_EXIT_HOOK(tp) { \ +#define CH_CFG_THREAD_EXIT_HOOK(tp) { \ /* Add threads finalization code here.*/ \ } -#endif /** * @brief Context switch hook. * @details This hook is invoked just before switching between threads. */ -#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__) -#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \ - /* System halt code here.*/ \ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* Context switch code here.*/ \ +} + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() { \ +} + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() { \ } -#endif /** * @brief Idle Loop hook. * @details This hook is continuously invoked by the idle thread loop. */ -#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__) -#define IDLE_LOOP_HOOK() { \ +#define CH_CFG_IDLE_LOOP_HOOK() { \ /* Idle loop code here.*/ \ } -#endif /** * @brief System tick event hook. * @details This hook is invoked in the system tick handler immediately * after processing the virtual timers queue. */ -#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__) -#define SYSTEM_TICK_EVENT_HOOK() { \ +#define CH_CFG_SYSTEM_TICK_HOOK() { \ /* System tick event code here.*/ \ } -#endif /** * @brief System halt hook. * @details This hook is invoked in case to a system halting error before * the system is halted. */ -#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) -#if CH_DBG_ENABLED - -#define SYSTEM_HALT_HOOK() { \ - print("FATAL %s\r\n", dbg_panic_msg); \ - chThdSleepMilliseconds(100); \ -/* System halt code here.*/ \ - +#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \ + /* System halt code here.*/ \ + chDbgPanic3(reason, __FILE__, __LINE__); \ } -#endif - -#endif - /** @} */ @@ -589,7 +520,24 @@ extern "C" /* Port-specific settings (override port settings defaulted in chcore.h). */ /*===========================================================================*/ -#define CORTEX_USE_FPU TRUE +#ifndef __ASSEMBLER__ +#if !CH_DBG_SYSTEM_STATE_CHECK +#define dbg_enter_lock() {ch.dbg.lock_cnt = 1;ON_LOCK_HOOK;} +#define dbg_leave_lock() {ON_UNLOCK_HOOK;ch.dbg.lock_cnt = 0;} +#endif + +void chDbgPanic3(const char *msg, const char * file, int line); +#endif + +/** + * declared as a macro so that this code does not use stack + * so that it would not crash the error handler in case of stack issues + */ +#if CH_DBG_SYSTEM_STATE_CHECK +#define hasFatalError() (ch.dbg.panic_msg != NULL) +#else +#define hasFatalError() (FALSE) +#endif #endif /* _CHCONF_H_ */ diff --git a/firmware/config/stm32f4ems/halconf.h b/firmware/config/stm32f4ems/halconf.h index 97e7abd8a8..5cd540aff1 100644 --- a/firmware/config/stm32f4ems/halconf.h +++ b/firmware/config/stm32f4ems/halconf.h @@ -1,28 +1,17 @@ /* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, - 2011,2012 Giovanni Di Sirio. + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - This file is part of ChibiOS/RT. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - ChibiOS/RT 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 3 of the License, or - (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 - ChibiOS/RT 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 . - - --- - - A special exception to the GPL can be applied should you wish to distribute - a combined work that includes ChibiOS/RT, without being obliged to provide - the source code for any proprietary components. See the file exception.txt - for full details of how and when the exception can be applied. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ /** @@ -41,13 +30,6 @@ #include "mcuconf.h" -/** - * @brief Enables the TM subsystem. - */ -#if !defined(HAL_USE_TM) || defined(__DOXYGEN__) -#define HAL_USE_TM FALSE -#endif - /** * @brief Enables the PAL subsystem. */ @@ -69,6 +51,13 @@ #define HAL_USE_CAN TRUE #endif +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC FALSE +#endif + /** * @brief Enables the EXT subsystem. */ @@ -90,6 +79,13 @@ #define HAL_USE_I2C TRUE #endif +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + /** * @brief Enables the ICU subsystem. */ @@ -167,6 +163,13 @@ #define HAL_USE_USB TRUE #endif +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + /*===========================================================================*/ /* ADC driver related settings. */ /*===========================================================================*/ @@ -213,6 +216,13 @@ /* MAC driver related settings. */ /*===========================================================================*/ +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + /** * @brief Enables an event sources for incoming packets. */ @@ -224,13 +234,6 @@ /* MMC_SPI driver related settings. */ /*===========================================================================*/ -/** - * @brief Block size for MMC transfers. - */ -#if !defined(MMC_SECTOR_SIZE) || defined(__DOXYGEN__) -#define MMC_SECTOR_SIZE 512 -#endif - /** * @brief Delays insertions. * @details If enabled this options inserts delays into the MMC waiting @@ -243,32 +246,6 @@ #define MMC_NICE_WAITING TRUE #endif -/** - * @brief Number of positive insertion queries before generating the - * insertion event. - */ -#if !defined(MMC_POLLING_INTERVAL) || defined(__DOXYGEN__) -#define MMC_POLLING_INTERVAL 10 -#endif - -/** - * @brief Interval, in milliseconds, between insertion queries. - */ -#if !defined(MMC_POLLING_DELAY) || defined(__DOXYGEN__) -#define MMC_POLLING_DELAY 10 -#endif - -/** - * @brief Uses the SPI polled API for small data transfers. - * @details Polled transfers usually improve performance because it - * saves two context switches and interrupt servicing. Note - * that this option has no effect on large transfers which - * are always performed using DMAs/IRQs. - */ -#if !defined(MMC_USE_SPI_POLLING) || defined(__DOXYGEN__) -#define MMC_USE_SPI_POLLING TRUE -#endif - /*===========================================================================*/ /* SDC driver related settings. */ /*===========================================================================*/ @@ -317,13 +294,36 @@ * @brief Serial buffers size. * @details Configuration parameter, you can change the depth of the queue * buffers depending on the requirements of your application. - * @note The default is 64 bytes for both the transmission and receive + * @note The default is 16 bytes for both the transmission and receive * buffers. */ #if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) #define SERIAL_BUFFERS_SIZE 16 #endif +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. + * @note The default is 256 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 256 +#endif + +/** + * @brief Serial over USB number of buffers. + * @note The default is 2 buffers. + */ +#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_NUMBER 2 +#endif + /*===========================================================================*/ /* SPI driver related settings. */ /*===========================================================================*/ @@ -344,6 +344,40 @@ #define SPI_USE_MUTUAL_EXCLUSION TRUE #endif +/*===========================================================================*/ +/* UART driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__) +#define UART_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define UART_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* USB driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT TRUE +#endif + +#include "halconf_community.h" + #endif /* _HALCONF_H_ */ /** @} */ diff --git a/firmware/config/stm32f4ems/halconf_community.h b/firmware/config/stm32f4ems/halconf_community.h new file mode 100644 index 0000000000..723221ac20 --- /dev/null +++ b/firmware/config/stm32f4ems/halconf_community.h @@ -0,0 +1,159 @@ +/* + ChibiOS - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _HALCONF_COMMUNITY_H_ +#define _HALCONF_COMMUNITY_H_ + +/** + * @brief Enables the community overlay. + */ +#if !defined(HAL_USE_COMMUNITY) || defined(__DOXYGEN__) +#define HAL_USE_COMMUNITY TRUE +#endif + +/** + * @brief Enables the FSMC subsystem. + */ +#if !defined(HAL_USE_FSMC) || defined(__DOXYGEN__) +#define HAL_USE_FSMC FALSE +#endif + +/** + * @brief Enables the NAND subsystem. + */ +#if !defined(HAL_USE_NAND) || defined(__DOXYGEN__) +#define HAL_USE_NAND FALSE +#endif + +/** + * @brief Enables the 1-wire subsystem. + */ +#if !defined(HAL_USE_ONEWIRE) || defined(__DOXYGEN__) +#define HAL_USE_ONEWIRE FALSE +#endif + +/** + * @brief Enables the EICU subsystem. + */ +#if !defined(HAL_USE_EICU) || defined(__DOXYGEN__) +#define HAL_USE_EICU FALSE +#endif + +/** + * @brief Enables the CRC subsystem. + */ +#if !defined(HAL_USE_CRC) || defined(__DOXYGEN__) +#define HAL_USE_CRC FALSE +#endif + +/** + * @brief Enables the USBH subsystem. + */ +#if !defined(HAL_USE_USBH) || defined(__DOXYGEN__) +#define HAL_USE_USBH FALSE +#endif + +/** + * @brief Enables the EEPROM subsystem. + */ +#if !defined(HAL_USE_EEPROM) || defined(__DOXYGEN__) +#define HAL_USE_EEPROM FALSE +#endif + +/** + * @brief Enables the TIMCAP subsystem. + */ +#if !defined(HAL_USE_TIMCAP) || defined(__DOXYGEN__) +#define HAL_USE_TIMCAP FALSE +#endif + +/** + * @brief Enables the RNG subsystem. + */ +#if !defined(HAL_USE_RNG) || defined(__DOXYGEN__) +#define HAL_USE_RNG FALSE +#endif + +/** + * @brief Enables the USB_MSD subsystem. + */ +#if !defined(HAL_USE_USB_MSD) || defined(__DOXYGEN__) +#define HAL_USE_USB_MSD TRUE +#endif + +/*===========================================================================*/ +/* FSMCNAND driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the @p nandAcquireBus() and @p nanReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(NAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define NAND_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* 1-wire driver related settings. */ +/*===========================================================================*/ +/** + * @brief Enables strong pull up feature. + * @note Disabling this option saves both code and data space. + */ +#define ONEWIRE_USE_STRONG_PULLUP FALSE + +/** + * @brief Enables search ROM feature. + * @note Disabling this option saves both code and data space. + */ +#define ONEWIRE_USE_SEARCH_ROM FALSE + + +/*===========================================================================*/ +/* EEProm driver related settings. */ +/*===========================================================================*/ + +#define EEPROM_USE_EE24XX FALSE +#define EEPROM_USE_EE25XX TRUE + + +#define rccEnableCRC(lp) rccEnableAHB(RCC_AHBENR_CRCEN, lp) +#define rccDisableCRC(lp) rccDisableAHB(RCC_AHBENR_CRCEN, lp) + +/*===========================================================================*/ +/* CRC driver settings. */ +/*===========================================================================*/ + +/** + * @brief Enables DMA engine when performing CRC transactions. + * @note Enabling this option also enables asynchronous API. + */ +#if !defined(CRC_USE_DMA) || defined(__DOXYGEN__) +#define CRC_USE_DMA FALSE +#endif + +/** + * @brief Enables the @p crcAcquireUnit() and @p crcReleaseUnit() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(CRC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define CRC_USE_MUTUAL_EXCLUSION TRUE +#endif + + +#endif /* _HALCONF_COMMUNITY_H_ */ + +/** @} */ diff --git a/firmware/config/stm32f4ems/mcuconf.h b/firmware/config/stm32f4ems/mcuconf.h index 5202f4266b..300751e786 100644 --- a/firmware/config/stm32f4ems/mcuconf.h +++ b/firmware/config/stm32f4ems/mcuconf.h @@ -1,5 +1,5 @@ /* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,6 +14,15 @@ limitations under the License. */ +#ifndef _MCUCONF_H_ +#define _MCUCONF_H_ + +#include "efifeatures.h" +#include "rusefi_enums.h" + +#define SCHEDULING_TIMER_PRIORITY 4 +#define ICU_PRIORITY 3 + /* * STM32F4xx drivers configuration. * The following settings override the default settings present in @@ -30,13 +39,6 @@ #define STM32F4xx_MCUCONF -#include "efifeatures.h" -#include "rusefi_enums.h" - -#define SCHEDULING_TIMER_PRIORITY 4 - -#define ICU_PRIORITY 3 - /* * HAL driver system settings. */ @@ -44,18 +46,11 @@ #define STM32_HSI_ENABLED TRUE #define STM32_LSI_ENABLED TRUE #define STM32_HSE_ENABLED TRUE - -// change this 'FALSE to TRUE if you have the LSE 32768 quarts -#define STM32_LSE_ENABLED TRUE - +#define STM32_LSE_ENABLED FALSE #define STM32_CLOCK48_REQUIRED TRUE #define STM32_SW STM32_SW_PLL #define STM32_PLLSRC STM32_PLLSRC_HSE -#ifdef OLIMEX_STM32_E407 -#define STM32_PLLM_VALUE 12 -#else #define STM32_PLLM_VALUE 8 -#endif #define STM32_PLLN_VALUE 336 #define STM32_PLLP_VALUE 2 #define STM32_PLLQ_VALUE 7 @@ -75,16 +70,16 @@ #define STM32_I2SSRC STM32_I2SSRC_CKIN #define STM32_PLLI2SN_VALUE 192 #define STM32_PLLI2SR_VALUE 5 -//#define STM32_VOS STM32_VOS_HIGH #define STM32_PVD_ENABLE FALSE #define STM32_PLS STM32_PLS_LEV0 +#define STM32_BKPRAM_ENABLE FALSE /* * ADC driver system settings. */ #define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4 -#define STM32_ADC_USE_ADC1 TRUE // slow ADC -#define STM32_ADC_USE_ADC2 TRUE // fast ADC +#define STM32_ADC_USE_ADC1 TRUE +#define STM32_ADC_USE_ADC2 TRUE #define STM32_ADC_USE_ADC3 FALSE #define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) #define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) @@ -105,6 +100,19 @@ #define STM32_CAN_CAN1_IRQ_PRIORITY 11 #define STM32_CAN_CAN2_IRQ_PRIORITY 11 +/* + * DAC driver system settings. + */ +#define STM32_DAC_DUAL_MODE FALSE +#define STM32_DAC_USE_DAC1_CH1 FALSE +#define STM32_DAC_USE_DAC1_CH2 FALSE +#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 +#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 +#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 +#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 +#define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) + /* * EXT driver system settings. */ @@ -157,7 +165,8 @@ #define STM32_I2C_USE_I2C1 TRUE #define STM32_I2C_USE_I2C2 FALSE #define STM32_I2C_USE_I2C3 FALSE -#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_I2C_BUSY_TIMEOUT 50 +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) #define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) #define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) #define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) @@ -169,21 +178,33 @@ #define STM32_I2C_I2C1_DMA_PRIORITY 3 #define STM32_I2C_I2C2_DMA_PRIORITY 3 #define STM32_I2C_I2C3_DMA_PRIORITY 3 -#define STM32_I2C_I2C1_DMA_ERROR_HOOK() chSysHalt() -#define STM32_I2C_I2C2_DMA_ERROR_HOOK() chSysHalt() -#define STM32_I2C_I2C3_DMA_ERROR_HOOK() chSysHalt() +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") + +/* + * I2S driver system settings. + */ +#define STM32_I2S_USE_SPI2 FALSE +#define STM32_I2S_USE_SPI3 FALSE +#define STM32_I2S_SPI2_IRQ_PRIORITY 10 +#define STM32_I2S_SPI3_IRQ_PRIORITY 10 +#define STM32_I2S_SPI2_DMA_PRIORITY 1 +#define STM32_I2S_SPI3_DMA_PRIORITY 1 +#define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") /* * ICU driver system settings. */ -#define STM32_ICU_USE_TIM1 TRUE // wave input -#define STM32_ICU_USE_TIM2 TRUE // primary position sensor -#define STM32_ICU_USE_TIM3 TRUE // secondary position sensor +#define STM32_ICU_USE_TIM1 TRUE +#define STM32_ICU_USE_TIM2 TRUE +#define STM32_ICU_USE_TIM3 TRUE #define STM32_ICU_USE_TIM4 FALSE #define STM32_ICU_USE_TIM5 FALSE #define STM32_ICU_USE_TIM8 FALSE -#define STM32_ICU_USE_TIM9 TRUE // wave input - +#define STM32_ICU_USE_TIM9 TRUE #define STM32_ICU_TIM1_IRQ_PRIORITY ICU_PRIORITY #define STM32_ICU_TIM2_IRQ_PRIORITY ICU_PRIORITY #define STM32_ICU_TIM3_IRQ_PRIORITY ICU_PRIORITY @@ -203,18 +224,17 @@ #define STM32_MAC_ETH1_IRQ_PRIORITY 13 #define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 -#define STM32_PWM_USE_TIM1 FALSE -#define STM32_PWM_USE_TIM2 FALSE -#define STM32_PWM_USE_TIM3 FALSE -#define STM32_PWM_USE_TIM4 TRUE // fast adc -#define STM32_PWM_USE_TIM5 FALSE -#define STM32_PWM_USE_TIM8 TRUE // slow adc -#define STM32_PWM_USE_TIM9 FALSE - /* * PWM driver system settings. */ #define STM32_PWM_USE_ADVANCED FALSE +#define STM32_PWM_USE_TIM1 FALSE +#define STM32_PWM_USE_TIM2 FALSE +#define STM32_PWM_USE_TIM3 FALSE +#define STM32_PWM_USE_TIM4 TRUE +#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM8 TRUE +#define STM32_PWM_USE_TIM9 FALSE #define STM32_PWM_TIM1_IRQ_PRIORITY 7 #define STM32_PWM_TIM2_IRQ_PRIORITY 7 #define STM32_PWM_TIM3_IRQ_PRIORITY 7 @@ -223,6 +243,17 @@ #define STM32_PWM_TIM8_IRQ_PRIORITY 7 #define STM32_PWM_TIM9_IRQ_PRIORITY 7 +/* + * SDC driver system settings. + */ +#define STM32_SDC_SDIO_DMA_PRIORITY 3 +#define STM32_SDC_SDIO_IRQ_PRIORITY 9 +#define STM32_SDC_WRITE_TIMEOUT_MS 250 +#define STM32_SDC_READ_TIMEOUT_MS 25 +#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10 +#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE +#define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) + /* * SERIAL driver system settings. */ @@ -243,8 +274,8 @@ * SPI driver system settings. */ #define STM32_SPI_USE_SPI1 TRUE -#define STM32_SPI_USE_SPI2 TRUE // external ADC -#define STM32_SPI_USE_SPI3 TRUE // potentiometer +#define STM32_SPI_USE_SPI2 TRUE +#define STM32_SPI_USE_SPI3 TRUE #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) #define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) @@ -257,7 +288,13 @@ #define STM32_SPI_SPI1_IRQ_PRIORITY 10 #define STM32_SPI_SPI2_IRQ_PRIORITY 10 #define STM32_SPI_SPI3_IRQ_PRIORITY 10 -#define STM32_SPI_DMA_ERROR_HOOK(spip) chDbgCheck(TRUE, "STM32_SPI_DMA_ERROR_HOOK") +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("STM32_SPI_DMA_ERROR_HOOK") + +/* + * ST driver system settings. + */ +#define STM32_ST_IRQ_PRIORITY 8 +#define STM32_ST_USE_TIMER 2 /* * UART driver system settings. @@ -265,6 +302,8 @@ #define STM32_UART_USE_USART1 FALSE #define STM32_UART_USE_USART2 FALSE #define STM32_UART_USE_USART3 TRUE +#define STM32_UART_USE_UART4 FALSE +#define STM32_UART_USE_UART5 FALSE #define STM32_UART_USE_USART6 FALSE #define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) #define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) @@ -272,17 +311,25 @@ #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) #define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1) #define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) #define STM32_UART_USART1_IRQ_PRIORITY 12 #define STM32_UART_USART2_IRQ_PRIORITY 12 #define STM32_UART_USART3_IRQ_PRIORITY 12 +#define STM32_UART_UART4_IRQ_PRIORITY 12 +#define STM32_UART_UART5_IRQ_PRIORITY 12 #define STM32_UART_USART6_IRQ_PRIORITY 12 #define STM32_UART_USART1_DMA_PRIORITY 0 #define STM32_UART_USART2_DMA_PRIORITY 0 #define STM32_UART_USART3_DMA_PRIORITY 0 +#define STM32_UART_UART4_DMA_PRIORITY 0 +#define STM32_UART_UART5_DMA_PRIORITY 0 #define STM32_UART_USART6_DMA_PRIORITY 0 -#define STM32_UART_DMA_ERROR_HOOK(uartp) chSysHalt() +#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("STM32_UART_DMA_ERROR_HOOK") /* * USB driver system settings. @@ -296,3 +343,10 @@ #define STM32_USB_OTG_THREAD_PRIO LOWPRIO #define STM32_USB_OTG_THREAD_STACK_SIZE 1024 #define STM32_USB_OTGFIFO_FILL_BASEPRI 0 + +/* + * WDG driver system settings. + */ +#define STM32_WDG_USE_IWDG FALSE + +#endif /* _MCUCONF_H_ */ diff --git a/firmware/console/eficonsole.cpp b/firmware/console/eficonsole.cpp index 2cfcf79029..17922b9324 100644 --- a/firmware/console/eficonsole.cpp +++ b/firmware/console/eficonsole.cpp @@ -32,7 +32,7 @@ static LoggingWithStorage logger("console"); static void myfatal(void) { - chDbgCheck(0, "my fatal"); + chDbgCheck(0); } static void myerror(void) { @@ -121,8 +121,8 @@ static void sayHello(void) { */ static void cmd_threads(void) { #if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__) - static const char *states[] = { THD_STATE_NAMES }; - Thread *tp; + static const char *states[] = { CH_STATE_NAMES }; + thread_t *tp; scheduleMsg(&logger, " addr stack prio refs state time"); tp = chRegFirstThread(); diff --git a/firmware/controllers/algo/error_handling.h b/firmware/controllers/algo/error_handling.h index 3f566b2c64..6adc656ff7 100644 --- a/firmware/controllers/algo/error_handling.h +++ b/firmware/controllers/algo/error_handling.h @@ -13,6 +13,7 @@ extern "C" { #endif /* __cplusplus */ +#include "global.h" #include "obd_error_codes.h" #include "efifeatures.h" #include "stdbool.h" @@ -40,18 +41,6 @@ void firmwareError(obd_code_e code, const char *fmt, ...); char *getFirmwareError(void); -/** - * declared as a macro so that this code does not use stack - * so that it would not crash the error handler in case of stack issues - */ -#if CH_DBG_SYSTEM_STATE_CHECK -#define hasFatalError() (dbg_panic_msg != NULL) -#else -#define hasFatalError() (FALSE) -#endif - -void chDbgPanic3(const char *msg, const char * file, int line); - void initErrorHandling(void); char *getWarning(void); diff --git a/firmware/controllers/core/interpolation.cpp b/firmware/controllers/core/interpolation.cpp index 4aa4cfec79..4c87a45074 100644 --- a/firmware/controllers/core/interpolation.cpp +++ b/firmware/controllers/core/interpolation.cpp @@ -7,13 +7,13 @@ * @author Dmitry Sidin, (c) 2015 */ +#include "main.h" #if DEBUG_FUEL #include #endif #include -#include "main.h" #include "efilib2.h" #include "interpolation.h" diff --git a/firmware/controllers/engine_controller.cpp b/firmware/controllers/engine_controller.cpp index a548b135a3..480b9d9ca6 100644 --- a/firmware/controllers/engine_controller.cpp +++ b/firmware/controllers/engine_controller.cpp @@ -149,13 +149,13 @@ efitick_t getTimeNowNt(void) { /** * number of SysClock ticks in one ms */ -#define TICKS_IN_MS (CH_FREQUENCY / 1000) +#define TICKS_IN_MS (CH_CFG_ST_FREQUENCY / 1000) // todo: this overflows pretty fast! efitimems_t currentTimeMillis(void) { // todo: migrate to getTimeNowUs? or not? - return chTimeNow() / TICKS_IN_MS; + return chVTGetSystemTimeX() / TICKS_IN_MS; } // todo: this overflows pretty fast! @@ -205,13 +205,13 @@ static void resetAccel(void) { } static void periodicSlowCallback(Engine *engine) { - efiAssertVoid(getRemainingStack(chThdSelf()) > 64, "lowStckOnEv"); + efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 64, "lowStckOnEv"); #if EFI_PROD_CODE /** * We need to push current value into the 64 bit counter often enough so that we do not miss an overflow */ bool alreadyLocked = lockAnyContext(); - updateAndSet(&halTime.state, hal_lld_get_counter_value()); + updateAndSet(&halTime.state, port_rt_get_counter_value()); if (!alreadyLocked) { unlockAnyContext(); } diff --git a/firmware/controllers/error_handling.cpp b/firmware/controllers/error_handling.cpp index e2f32ff744..3bac9a451b 100644 --- a/firmware/controllers/error_handling.cpp +++ b/firmware/controllers/error_handling.cpp @@ -54,7 +54,7 @@ void chDbgPanic3(const char *msg, const char * file, int line) { dbg_panic_file = file; dbg_panic_line = line; #if CH_DBG_SYSTEM_STATE_CHECK || defined(__DOXYGEN__) - dbg_panic_msg = msg; + ch.dbg.panic_msg = msg; #endif /* CH_DBG_SYSTEM_STATE_CHECK */ #if EFI_PROD_CODE || defined(__DOXYGEN__) @@ -70,8 +70,8 @@ void chDbgPanic3(const char *msg, const char * file, int line) { if (!main_loop_started) { print("fatal %s %s:%d\r\n", msg, file, line); - chThdSleepSeconds(1); - chSysHalt(); +// chThdSleepSeconds(1); + chSysHalt("Main loop did not start"); } } diff --git a/firmware/ext/diskio.h b/firmware/ext/diskio.h index 9573e6ecc7..4d72b910a8 100644 --- a/firmware/ext/diskio.h +++ b/firmware/ext/diskio.h @@ -1,11 +1,16 @@ -/*----------------------------------------------------------------------- -/ Low level disk interface modlue include file +/*-----------------------------------------------------------------------/ +/ Low level disk interface modlue include file (C)ChaN, 2013 / /-----------------------------------------------------------------------*/ -#ifndef _DISKIO +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED -#define _READONLY 0 /* 1: Remove write functions */ -#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */ +#ifdef __cplusplus +extern "C" { +#endif + +#define _USE_WRITE 1 /* 1: Enable disk_write function */ +#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ #include "integer.h" @@ -26,15 +31,12 @@ typedef enum { /*---------------------------------------*/ /* Prototypes for disk control functions */ -int assign_drives (int, int); -DSTATUS disk_initialize (BYTE); -DSTATUS disk_status (BYTE); -DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); -#if _READONLY == 0 -DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); -#endif -DRESULT disk_ioctl (BYTE, BYTE, void*); +DSTATUS disk_initialize (BYTE pdrv); +DSTATUS disk_status (BYTE pdrv); +DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Disk Status Bits (DSTATUS) */ @@ -46,17 +48,18 @@ DRESULT disk_ioctl (BYTE, BYTE, void*); /* Command code for disk_ioctrl fucntion */ -/* Generic command (defined for FatFs) */ +/* Generic command (used by FatFs) */ #define CTRL_SYNC 0 /* Flush disk cache (for write functions) */ #define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */ #define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */ #define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */ -/* Generic command */ +/* Generic command (not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ #define CTRL_LOCK 6 /* Lock/Unlock media removal */ #define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ /* MMC/SDC specific ioctl command */ #define MMC_GET_TYPE 10 /* Get card type */ @@ -70,9 +73,8 @@ DRESULT disk_ioctl (BYTE, BYTE, void*); #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */ -/* NAND specific ioctl command */ -#define NAND_FORMAT 30 /* Create physical format */ - - -#define _DISKIO +#ifdef __cplusplus +} +#endif + #endif diff --git a/firmware/ext/fatfs.mk b/firmware/ext/fatfs.mk new file mode 100644 index 0000000000..c7f4fc2c58 --- /dev/null +++ b/firmware/ext/fatfs.mk @@ -0,0 +1,7 @@ +# FATFS files. +FATFSSRC = ${CHIBIOS}/os/various/fatfs_bindings/fatfs_diskio.c \ + ${CHIBIOS}/os/various/fatfs_bindings/fatfs_syscall.c \ + ${PROJECT_DIR}/ext/ff.c \ + ${PROJECT_DIR}/ext/option/unicode.c + +FATFSINC = ${PROJECT_DIR}/ext diff --git a/firmware/ext/ff.c b/firmware/ext/ff.c new file mode 100644 index 0000000000..d7d690c70e --- /dev/null +++ b/firmware/ext/ff.c @@ -0,0 +1,4588 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - FAT file system module R0.10b (C)ChaN, 2014 +/-----------------------------------------------------------------------------/ +/ FatFs module is a generic FAT file system module for small embedded systems. +/ This is a free software that opened for education, research and commercial +/ developments under license policy of following terms. +/ +/ Copyright (C) 2014, ChaN, all right reserved. +/ +/ * The FatFs module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-----------------------------------------------------------------------------/ +/ Feb 26,'06 R0.00 Prototype. +/ +/ Apr 29,'06 R0.01 First stable version. +/ +/ Jun 01,'06 R0.02 Added FAT12 support. +/ Removed unbuffered mode. +/ Fixed a problem on small (<32M) partition. +/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM). +/ +/ Sep 22,'06 R0.03 Added f_rename(). +/ Changed option _FS_MINIMUM to _FS_MINIMIZE. +/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast. +/ Fixed f_mkdir() creates incorrect directory on FAT32. +/ +/ Feb 04,'07 R0.04 Supported multiple drive system. +/ Changed some interfaces for multiple drive system. +/ Changed f_mountdrv() to f_mount(). +/ Added f_mkfs(). +/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive. +/ Added a capability of extending file size to f_lseek(). +/ Added minimization level 3. +/ Fixed an endian sensitive code in f_mkfs(). +/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG. +/ Added FSINFO support. +/ Fixed DBCS name can result FR_INVALID_NAME. +/ Fixed short seek (<= csize) collapses the file object. +/ +/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs(). +/ Fixed f_mkfs() on FAT32 creates incorrect FSINFO. +/ Fixed f_mkdir() on FAT32 creates incorrect directory. +/ Feb 03,'08 R0.05a Added f_truncate() and f_utime(). +/ Fixed off by one error at FAT sub-type determination. +/ Fixed btr in f_read() can be mistruncated. +/ Fixed cached sector is not flushed when create and close without write. +/ +/ Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets(). +/ Improved performance of f_lseek() on moving to the same or following cluster. +/ +/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a configuration option. (_FS_TINY) +/ Added long file name feature. +/ Added multiple code page feature. +/ Added re-entrancy for multitask operation. +/ Added auto cluster size selection to f_mkfs(). +/ Added rewind option to f_readdir(). +/ Changed result code of critical errors. +/ Renamed string functions to avoid name collision. +/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg. +/ Added multiple sector size feature. +/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error. +/ Fixed wrong cache control in f_lseek(). +/ Added relative path feature. +/ Added f_chdir() and f_chdrive(). +/ Added proper case conversion to extended character. +/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h. +/ Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. +/ Fixed name matching error on the 13 character boundary. +/ Added a configuration option, _LFN_UNICODE. +/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. +/ +/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3) +/ Added file lock feature. (_FS_SHARE) +/ Added fast seek feature. (_USE_FASTSEEK) +/ Changed some types on the API, XCHAR->TCHAR. +/ Changed .fname in the FILINFO structure on Unicode cfg. +/ String functions support UTF-8 encoding files on Unicode cfg. +/ Aug 16,'10 R0.08a Added f_getcwd(). +/ Added sector erase feature. (_USE_ERASE) +/ Moved file lock semaphore table from fs object to the bss. +/ Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'. +/ Fixed f_mkfs() creates wrong FAT32 volume. +/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write(). +/ f_lseek() reports required table size on creating CLMP. +/ Extended format syntax of f_printf(). +/ Ignores duplicated directory separators in given path name. +/ +/ Sep 06,'11 R0.09 f_mkfs() supports multiple partition to complete the multiple partition feature. +/ Added f_fdisk(). +/ Aug 27,'12 R0.09a Changed f_open() and f_opendir() reject null object pointer to avoid crash. +/ Changed option name _FS_SHARE to _FS_LOCK. +/ Fixed assertion failure due to OS/2 EA on FAT12/16 volume. +/ Jan 24,'13 R0.09b Added f_setlabel() and f_getlabel(). +/ +/ Oct 02,'13 R0.10 Added selection of character encoding on the file. (_STRF_ENCODE) +/ Added f_closedir(). +/ Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) +/ Added forced mount feature with changes of f_mount(). +/ Improved behavior of volume auto detection. +/ Improved write throughput of f_puts() and f_printf(). +/ Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). +/ Fixed f_write() can be truncated when the file size is close to 4GB. +/ Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. +/ Jan 15,'14 R0.10a Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) +/ Added a configuration option of minimum sector size. (_MIN_SS) +/ 2nd argument of f_rename() can have a drive number and it will be ignored. +/ Fixed f_mount() with forced mount fails when drive number is >= 1. +/ Fixed f_close() invalidates the file object without volume lock. +/ Fixed f_closedir() returns but the volume lock is left acquired. +/ Fixed creation of an entry with LFN fails on too many SFN collisions. +/ May 19,'14 R0.10b Fixed a hard error in the disk I/O layer can collapse the directory entry. +/ Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. +/---------------------------------------------------------------------------*/ + +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of disk I/O functions */ + + + + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if _FATFS != 8051 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + + +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration. +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif + +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Definitions of sector size */ +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#error Wrong sector size configuration. +#endif +#if _MAX_SS == _MIN_SS +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* File access control feature */ +#if _FS_LOCK +#if _FS_READONLY +#error _FS_LOCK must be 0 at read-only cfg. +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, directory (0:root) */ + WORD idx; /* Object ID 3, directory index */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + + +/* DBCS code ranges and SBCS extend character conversion table */ + +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} + +#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1253 /* Greek (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ + 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} + +#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1256 /* Arabic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1257 /* Baltic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#if _USE_LFN +#error Cannot use LFN feature without valid code page. +#endif +#define _DF1S 0 + +#else +#error Unknown code page + +#endif + + +/* Character code support macros */ +#define IsUpper(c) (((c)>='A')&&((c)<='Z')) +#define IsLower(c) (((c)>='a')&&((c)<='z')) +#define IsDigit(c) (((c)>='0')&&((c)<='9')) + +#if _DF1S /* Code page is DBCS */ + +#ifdef _DF2S /* Two 1st byte areas */ +#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) +#else /* One 1st byte area */ +#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) +#endif + +#ifdef _DS3S /* Three 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) +#else /* Two 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) +#endif + +#else /* Code page is SBCS */ + +#define IsDBCS1(c) 0 +#define IsDBCS2(c) 0 + +#endif /* _DF1S */ + + +/* Name status flags */ +#define NS 11 /* Index of name status byte in fn[] */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ + + +/* FAT sub-type boundaries */ +#define MIN_FAT16 4086U /* Minimum number of clusters for FAT16 */ +#define MIN_FAT32 65526U /* Minimum number of clusters for FAT32 */ + + +/* FatFs refers the members in the FAT structures as byte array instead of +/ structure member because the structure is not binary compatible between +/ different platforms */ + +#define BS_jmpBoot 0 /* Jump instruction (3) */ +#define BS_OEMName 3 /* OEM name (8) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ +#define BPB_NumFATs 16 /* Number of FAT copies (1) */ +#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */ +#define BPB_TotSec16 19 /* Volume size [sector] (2) */ +#define BPB_Media 21 /* Media descriptor (1) */ +#define BPB_FATSz16 22 /* FAT size [sector] (2) */ +#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ +#define BPB_NumHeads 26 /* Number of heads (2) */ +#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ +#define BPB_TotSec32 32 /* Volume size [sector] (4) */ +#define BS_DrvNum 36 /* Physical drive number (2) */ +#define BS_BootSig 38 /* Extended boot signature (1) */ +#define BS_VolID 39 /* Volume serial number (4) */ +#define BS_VolLab 43 /* Volume label (8) */ +#define BS_FilSysType 54 /* File system type (1) */ +#define BPB_FATSz32 36 /* FAT size [sector] (4) */ +#define BPB_ExtFlags 40 /* Extended flags (2) */ +#define BPB_FSVer 42 /* File system version (2) */ +#define BPB_RootClus 44 /* Root directory first cluster (4) */ +#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ +#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ +#define BS_DrvNum32 64 /* Physical drive number (2) */ +#define BS_BootSig32 66 /* Extended boot signature (1) */ +#define BS_VolID32 67 /* Volume serial number (4) */ +#define BS_VolLab32 71 /* Volume label (8) */ +#define BS_FilSysType32 82 /* File system type (1) */ +#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ +#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ +#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ +#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ +#define MBR_Table 446 /* MBR: Partition table offset (2) */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define BS_55AA 510 /* Signature word (2) */ + +#define DIR_Name 0 /* Short file name (11) */ +#define DIR_Attr 11 /* Attribute (1) */ +#define DIR_NTres 12 /* NT flag (1) */ +#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ +#define DIR_CrtTime 14 /* Created time (2) */ +#define DIR_CrtDate 16 /* Created date (2) */ +#define DIR_LstAccDate 18 /* Last accessed date (2) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ +#define DIR_WrtTime 22 /* Modified time (2) */ +#define DIR_WrtDate 24 /* Modified date (2) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ +#define DIR_FileSize 28 /* File size (4) */ +#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ +#define LDIR_Attr 11 /* LFN attribute (1) */ +#define LDIR_Type 12 /* LFN type (1) */ +#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ +#define LDIR_FstClusLO 26 /* Filled by zero (0) */ +#define SZ_DIR 32 /* Size of a directory entry */ +#define LLE 0x40 /* Last long entry flag in LDIR_Ord */ +#define DDE 0xE5 /* Deleted directory entry mark in DIR_Name[0] */ +#define NDDE 0x05 /* Replacement of the character collides with DDE */ + + + + +/*------------------------------------------------------------*/ +/* Module private work area */ +/*------------------------------------------------------------*/ +/* Note that uninitialized variables with static duration are +/ guaranteed zero/null as initial value. If not, either the +/ linker or start-up routine is out of ANSI-C standard. +*/ + +#if _VOLUMES >= 1 || _VOLUMES <= 10 +static +FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ +#else +#error Number of volumes must be 1 to 10. +#endif + +static +WORD Fsid; /* File system mount ID */ + +#if _FS_RPATH && _VOLUMES >= 2 +static +BYTE CurrVol; /* Current drive */ +#endif + +#if _FS_LOCK +static +FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +#endif + +#if _USE_LFN == 0 /* No LFN feature */ +#define DEF_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) (dobj).fn = sfn +#define FREE_BUF() + +#elif _USE_LFN == 1 /* LFN feature with static working buffer */ +static +WCHAR LfnBuf[_MAX_LFN+1]; +#define DEF_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } +#define FREE_BUF() + +#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ +#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1] +#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } +#define FREE_BUF() + +#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ +#define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn +#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \ + if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \ + (dobj).lfn = lfn; (dobj).fn = sfn; } +#define FREE_BUF() ff_memfree(lfn) + +#else +#error Wrong LFN configuration. +#endif + + +#ifdef _EXCVT +static +const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */ +#endif + + + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +/* Copy memory to memory */ +static +void mem_cpy (void* dst, const void* src, UINT cnt) { + BYTE *d = (BYTE*)dst; + const BYTE *s = (const BYTE*)src; + +#if _WORD_ACCESS == 1 + while (cnt >= sizeof (int)) { + *(int*)d = *(int*)s; + d += sizeof (int); s += sizeof (int); + cnt -= sizeof (int); + } +#endif + while (cnt--) + *d++ = *s++; +} + +/* Fill memory */ +static +void mem_set (void* dst, int val, UINT cnt) { + BYTE *d = (BYTE*)dst; + + while (cnt--) + *d++ = (BYTE)val; +} + +/* Compare memory to memory */ +static +int mem_cmp (const void* dst, const void* src, UINT cnt) { + const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; + int r = 0; + + while (cnt-- && (r = *d++ - *s++) == 0) ; + return r; +} + +/* Check if chr is contained in the string */ +static +int chk_chr (const char* str, int chr) { + while (*str && *str != chr) str++; + return *str; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ +#if _FS_REENTRANT +static +int lock_fs ( + FATFS* fs /* File system object */ +) +{ + return ff_req_grant(fs->sobj); +} + + +static +void unlock_fs ( + FATFS* fs, /* File system object */ + FRESULT res /* Result code to be returned */ +) +{ + if (fs && + res != FR_NOT_ENABLED && + res != FR_INVALID_DRIVE && + res != FR_INVALID_OBJECT && + res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* File lock control functions */ +/*-----------------------------------------------------------------------*/ +#if _FS_LOCK + +static +FRESULT chk_lock ( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i, be; + + /* Search file semaphore table */ + for (i = be = 0; i < _FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */ + Files[i].clu == dp->sclust && + Files[i].idx == dp->index) break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == _FS_LOCK) /* The object is not opened */ + return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + + /* The object has been opened. Reject any open against writing file and all write mode open */ + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static +int enq_lock (void) /* Check if an entry is available for a new object */ +{ + UINT i; + + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + return (i == _FS_LOCK) ? 0 : 1; +} + + +static +UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ + DIR* dp, /* Directory object pointing the file to register or increment */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i; + + + for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->fs && + Files[i].clu == dp->sclust && + Files[i].idx == dp->index) break; + } + + if (i == _FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->fs; + Files[i].clu = dp->sclust; + Files[i].idx = dp->index; + Files[i].ctr = 0; + } + + if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; +} + + +static +FRESULT dec_lock ( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ +) +{ + WORD n; + FRESULT res; + + + if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n) n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index nunber */ + } + return res; +} + + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < _FS_LOCK; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Move/Flush disk access window in the file system object */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync_window ( + FATFS* fs /* File system object */ +) +{ + DWORD wsect; + UINT nf; + + + if (fs->wflag) { /* Write back the sector if it is dirty */ + wsect = fs->winsect; /* Current sector number */ + if (disk_write(fs->drv, fs->win, wsect, 1)) + return FR_DISK_ERR; + fs->wflag = 0; + if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ + for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ + wsect += fs->fsize; + disk_write(fs->drv, fs->win, wsect, 1); + } + } + } + return FR_OK; +} +#endif + + +static +FRESULT move_window ( + FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ +) +{ + if (sector != fs->winsect) { /* Changed current window */ +#if !_FS_READONLY + if (sync_window(fs) != FR_OK) + return FR_DISK_ERR; +#endif + if (disk_read(fs->drv, fs->win, sector, 1)) + return FR_DISK_ERR; + fs->winsect = sector; + } + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize file system and strage device */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ + FATFS* fs /* File system object */ +) +{ + FRESULT res; + + + res = sync_window(fs); + if (res == FR_OK) { + /* Update FSINFO sector if needed */ + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + /* Create FSINFO structure */ + mem_set(fs->win, 0, SS(fs)); + ST_WORD(fs->win+BS_55AA, 0xAA55); + ST_DWORD(fs->win+FSI_LeadSig, 0x41615252); + ST_DWORD(fs->win+FSI_StrucSig, 0x61417272); + ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust); + ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust); + /* Write it into the FSINFO sector */ + fs->winsect = fs->volbase + 1; + disk_write(fs->drv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the physical drive */ + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) + res = FR_DISK_ERR; + } + + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ + + +DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; + if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + + +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to get the link information */ +) +{ + UINT wc, bc; + BYTE *p; + + + if (clst < 2 || clst >= fs->n_fatent) /* Check range */ + return 1; + + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break; + wc = fs->win[bc % SS(fs)]; bc++; + if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break; + wc |= fs->win[bc % SS(fs)] << 8; + return clst & 1 ? wc >> 4 : (wc & 0xFFF); + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break; + p = &fs->win[clst * 2 % SS(fs)]; + return LD_WORD(p); + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break; + p = &fs->win[clst * 4 % SS(fs)]; + return LD_DWORD(p) & 0x0FFFFFFF; + + default: + return 1; + } + + return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of a FAT entry */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY + +FRESULT put_fat ( + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */ + DWORD val /* New value to mark the cluster */ +) +{ + UINT bc; + BYTE *p; + FRESULT res; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = &fs->win[bc % SS(fs)]; + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + bc++; + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = &fs->win[bc % SS(fs)]; + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + break; + + case FS_FAT16 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + p = &fs->win[clst * 2 % SS(fs)]; + ST_WORD(p, (WORD)val); + break; + + case FS_FAT32 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + p = &fs->win[clst * 4 % SS(fs)]; + val |= LD_DWORD(p) & 0xF0000000; + ST_DWORD(p, val); + break; + + default : + res = FR_INT_ERR; + } + fs->wflag = 1; + } + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT remove_chain ( + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to remove a chain from */ +) +{ + FRESULT res; + DWORD nxt; +#if _USE_ERASE + DWORD scl = clst, ecl = clst, rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + res = FR_OK; + while (clst < fs->n_fatent) { /* Not a last link? */ + nxt = get_fat(fs, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ + if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ + res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ + if (res != FR_OK) break; + if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ + fs->free_clust++; + fs->fsi_flag |= 1; + } +#if _USE_ERASE + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous clusters */ + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, rt); /* Erase the block */ + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } + } + + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch or Create a cluster chain */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clust; /* Get suggested start point */ + if (!scl || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch the current chain */ + cs = get_fat(fs, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Invalid value */ + if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; + } + + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(fs, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ + return cs; + if (ncl == scl) return 0; /* No free cluster */ + } + + res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ + } + if (res == FR_OK) { + fs->last_clust = ncl; /* Update FSINFO */ + if (fs->free_clust != 0xFFFFFFFF) { + fs->free_clust--; + fs->fsi_flag |= 1; + } + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + } + + return ncl; /* Return new cluster number or error code */ +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Convert offset into cluster with link map table */ +/*-----------------------------------------------------------------------*/ + +#if _USE_FASTSEEK +static +DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File offset to be converted to cluster# */ +) +{ + DWORD cl, ncl, *tbl; + + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (!ncl) return 0; /* End of table? (error) */ + if (cl < ncl) break; /* In this fragment? */ + cl -= ncl; tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ +} +#endif /* _USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_sdi ( + DIR* dp, /* Pointer to directory object */ + UINT idx /* Index of directory table */ +) +{ + DWORD clst, sect; + UINT ic; + + + dp->index = (WORD)idx; /* Current index */ + clst = dp->sclust; /* Table start cluster (0:root) */ + if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ + return FR_INT_ERR; + if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ + clst = dp->fs->dirbase; + + if (clst == 0) { /* Static table (root-directory in FAT12/16) */ + if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ + return FR_INT_ERR; + sect = dp->fs->dirbase; + } + else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ + ic = SS(dp->fs) / SZ_DIR * dp->fs->csize; /* Entries per cluster */ + while (idx >= ic) { /* Follow cluster chain */ + clst = get_fat(dp->fs, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */ + return FR_INT_ERR; + idx -= ic; + } + sect = clust2sect(dp->fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (!sect) return FR_INT_ERR; + dp->sect = sect + idx / (SS(dp->fs) / SZ_DIR); /* Sector# of the directory entry */ + dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory table index next */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +) +{ + DWORD clst; + UINT i; + + + i = dp->index + 1; + if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ + return FR_NO_FILE; + + if (!(i % (SS(dp->fs) / SZ_DIR))) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (!dp->clust) { /* Static table */ + if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */ + return FR_NO_FILE; + } + else { /* Dynamic table */ + if (((i / (SS(dp->fs) / SZ_DIR)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; + if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */ +#if !_FS_READONLY + UINT c; + if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */ + clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; + /* Clean-up stretched table */ + if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */ + mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */ + dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */ + for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */ + dp->fs->wflag = 1; + if (sync_window(dp->fs)) return FR_DISK_ERR; + dp->fs->winsect++; + } + dp->fs->winsect -= c; /* Rewind window offset */ +#else + if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */ + return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(dp->fs, clst); + } + } + } + + dp->index = (WORD)i; /* Current index */ + dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIR)) * SZ_DIR; /* Current entry in the window */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Reserve directory entry */ +/*-----------------------------------------------------------------------*/ + +#if !_FS_READONLY +static +FRESULT dir_alloc ( + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate (1-21) */ +) +{ + FRESULT res; + UINT n; + + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + if (dp->dir[0] == DDE || dp->dir[0] == 0) { /* Is it a blank entry? */ + if (++n == nent) break; /* A block of contiguous entries is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dp, 1); /* Next entry with table stretch enabled */ + } while (res == FR_OK); + } + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Load/Store start cluster number */ +/*-----------------------------------------------------------------------*/ + +static +DWORD ld_clust ( + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir /* Pointer to the directory entry */ +) +{ + DWORD cl; + + cl = LD_WORD(dir+DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) + cl |= (DWORD)LD_WORD(dir+DIR_FstClusHI) << 16; + + return cl; +} + + +#if !_FS_READONLY +static +void st_clust ( + BYTE* dir, /* Pointer to the directory entry */ + DWORD cl /* Value to be set */ +) +{ + ST_WORD(dir+DIR_FstClusLO, cl); + ST_WORD(dir+DIR_FstClusHI, cl >> 16); +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ + + +static +int cmp_lfn ( /* 1:Matched, 0:Not matched */ + WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ + BYTE* dir /* Pointer to the directory entry containing a part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13; /* Get offset in the LFN buffer */ + s = 0; wc = 1; + do { + uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last character has not been processed */ + wc = ff_wtoupper(uc); /* Convert it to upper case */ + if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ + return 0; /* Not matched */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } while (++s < 13); /* Repeat until all characters in the entry are checked */ + + if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i]) /* Last segment matched but different length */ + return 0; + + return 1; /* The part of LFN matched */ +} + + + +static +int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ + WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ + BYTE* dir /* Pointer to the directory entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + s = 0; wc = 1; + do { + uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last character has not been processed */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } while (++s < 13); /* Read all character in the entry */ + + if (dir[LDIR_Ord] & LLE) { /* Put terminator if it is the last LFN part */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; +} + + +#if !_FS_READONLY +static +void fit_lfn ( + const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ + BYTE* dir, /* Pointer to the directory entry */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* SFN sum */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set check sum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + ST_WORD(dir+LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ + ST_WORD(dir+LfnOfs[s], wc); /* Put it */ + if (!wc) wc = 0xFFFF; /* Padding characters following last character */ + } while (++s < 13); + if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE; /* Bottom LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Create numbered name */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +void gen_numname ( + BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ + WCHAR wc; + DWORD sr = seq; + + while (*lfn) { /* Create a CRC */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sr = (sr << 1) + (wc & 1); + wc >>= 1; + if (sr & 0x10000) sr ^= 0x11021; + } + } + seq = (UINT)sr; + } + + /* itoa (hexdecimal) */ + i = 7; + do { + c = (seq % 16) + '0'; + if (c > '9') c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (IsDBCS1(dst[j])) { + if (j == i - 1) break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Calculate sum of an SFN */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +BYTE sum_sfn ( + const BYTE* dir /* Pointer to the SFN entry */ +) +{ + BYTE sum = 0; + UINT n = 11; + + do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + return sum; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( + DIR* dp /* Pointer to the directory object linked to the file name */ +) +{ + FRESULT res; + BYTE c, *dir; +#if _USE_LFN + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; + +#if _USE_LFN + ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + dir = dp->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if _USE_LFN /* LFN configuration */ + a = dir[DIR_Attr] & AM_MASK; + if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (dp->lfn) { + if (c & LLE) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= ~LLE; ord = c; /* LFN start order */ + dp->lfn_idx = dp->index; /* Start index of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ + if (!(dp->fn[NS] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ +#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 +static +FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res; + BYTE a, c, *dir; +#if _USE_LFN + BYTE ord = 0xFF, sum = 0xFF; +#endif + + res = FR_NO_FILE; + while (dp->sect) { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + dir = dp->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ + a = dir[DIR_Attr] & AM_MASK; +#if _USE_LFN /* LFN configuration */ + if (c == DDE || (!_FS_RPATH && c == '.') || (int)(a == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLE) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= ~LLE; ord = c; + dp->lfn_idx = dp->index; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ + dp->lfn_idx = 0xFFFF; /* It has no LFN. */ + break; + } + } +#else /* Non LFN configuration */ + if (c != DDE && (_FS_RPATH || c != '.') && a != AM_LFN && (int)(a == AM_VOL) == vol) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; + + return res; +} +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ + + + + +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ + DIR* dp /* Target directory with object name to be created */ +) +{ + FRESULT res; +#if _USE_LFN /* LFN configuration */ + UINT n, nent; + BYTE sn[12], *fn, sum; + WCHAR *lfn; + + + fn = dp->fn; lfn = dp->lfn; + mem_cpy(sn, fn, 12); + + if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */ + return FR_INVALID_NAME; + + if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + fn[NS] = 0; dp->lfn = 0; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ + res = dir_find(dp); /* Check if the name collides with existing SFN */ + if (res != FR_OK) break; + } + if (n == 100) return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ + fn[NS] = sn[NS]; dp->lfn = lfn; + } + + if (sn[NS] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */ + for (n = 0; lfn[n]; n++) ; + nent = (n + 25) / 13; + } else { /* Otherwise allocate an entry for an SFN */ + nent = 1; + } + res = dir_alloc(dp, nent); /* Allocate entries */ + + if (res == FR_OK && --nent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->index - nent); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); + dp->fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --nent); + } + } +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ +#endif + + if (res == FR_OK) { /* Set SFN entry */ + res = move_window(dp->fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZ_DIR); /* Clean the entry */ + mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ +#if _USE_LFN + dp->dir[DIR_NTres] = dp->fn[NS] & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + dp->fs->wflag = 1; + } + } + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY && !_FS_MINIMIZE +static +FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; +#if _USE_LFN /* LFN configuration */ + UINT i; + + i = dp->index; /* SFN index */ + res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ + if (res == FR_OK) { + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) break; + mem_set(dp->dir, 0, SZ_DIR); /* Clear and mark the entry "deleted" */ + *dp->dir = DDE; + dp->fs->wflag = 1; + if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR; + } + +#else /* Non LFN configuration */ + res = dir_sdi(dp, dp->index); + if (res == FR_OK) { + res = move_window(dp->fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZ_DIR); /* Clear and mark the entry "deleted" */ + *dp->dir = DDE; + dp->fs->wflag = 1; + } + } +#endif + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +static +void get_fileinfo ( /* No return code */ + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ +) +{ + UINT i; + TCHAR *p, c; + + + p = fno->fname; + if (dp->sect) { /* Get SFN */ + BYTE *dir = dp->dir; + + i = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == NDDE) c = (TCHAR)DDE; /* Restore replaced DDE character */ + if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */ +#if _USE_LFN + if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) + c += 0x20; /* To lower */ +#if _LFN_UNICODE + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) + c = c << 8 | dir[i++]; + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif +#endif + *p++ = c; + } + fno->fattrib = dir[DIR_Attr]; /* Attribute */ + fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */ + fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */ + fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */ + } + *p = 0; /* Terminate SFN string by a \0 */ + +#if _USE_LFN + if (fno->lfname) { + WCHAR w, *lfn; + + i = 0; p = fno->lfname; + if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ + lfn = dp->lfn; + while ((w = *lfn++) != 0) { /* Get an LFN character */ +#if !_LFN_UNICODE + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (!w) { i = 0; break; } /* No LFN if it could not be converted */ + if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ + p[i++] = (TCHAR)(w >> 8); +#endif + if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */ + p[i++] = (TCHAR)w; + } + } + p[i] = 0; /* Terminate LFN string by a \0 */ + } +#endif +} +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2*/ + + + + +/*-----------------------------------------------------------------------*/ +/* Pick a segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT create_name ( + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ +) +{ +#if _USE_LFN /* LFN configuration */ + BYTE b, cf; + WCHAR w, *lfn; + UINT i, ni, si, di; + const TCHAR *p; + + /* Create LFN in Unicode */ + for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ + lfn = dp->lfn; + si = di = 0; + for (;;) { + w = p[si++]; /* Get a character */ + if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ + if (di >= _MAX_LFN) /* Reject too long name */ + return FR_INVALID_NAME; +#if !_LFN_UNICODE + w &= 0xFF; + if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(b)) + return FR_INVALID_NAME; /* Reject invalid sequence */ + w = (w << 8) + b; /* Create a DBC */ + } + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ + if (!w) return FR_INVALID_NAME; /* Reject invalid code */ +#endif + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ + return FR_INVALID_NAME; + lfn[di++] = w; /* Store the Unicode character */ + } + *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ +#if _FS_RPATH + if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */ + (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) { + lfn[di] = 0; + for (i = 0; i < 11; i++) + dp->fn[i] = (i < di) ? '.' : ' '; + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Strip trailing spaces and dots */ + w = lfn[di-1]; + if (w != ' ' && w != '.') break; + di--; + } + if (!di) return FR_INVALID_NAME; /* Reject nul string */ + + lfn[di] = 0; /* LFN is created */ + + /* Create SFN in directory form */ + mem_set(dp->fn, ' ', 11); + for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ + if (si) cf |= NS_LOSS | NS_LFN; + while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + + b = i = 0; ni = 8; + for (;;) { + w = lfn[si++]; /* Get an LFN character */ + if (!w) break; /* Break on end of the LFN */ + if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ + cf |= NS_LOSS | NS_LFN; continue; + } + + if (i >= ni || si == di) { /* Extension or end of SFN */ + if (ni == 11) { /* Long extension */ + cf |= NS_LOSS | NS_LFN; break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ + if (si > di) break; /* No extension */ + si = di; i = 8; ni = 11; /* Enter extension section */ + b <<= 2; continue; + } + + if (w >= 0x80) { /* Non ASCII character */ +#ifdef _EXCVT + w = ff_convert(w, 0); /* Unicode -> OEM code */ + if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ +#else + w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ +#endif + cf |= NS_LFN; /* Force create LFN entry */ + } + + if (_DF1S && w >= 0x100) { /* Double byte character (always false on SBCS cfg) */ + if (i >= ni - 1) { + cf |= NS_LOSS | NS_LFN; i = ni; continue; + } + dp->fn[i++] = (BYTE)(w >> 8); + } else { /* Single byte character */ + if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ + w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(w)) { /* ASCII large capital */ + b |= 2; + } else { + if (IsLower(w)) { /* ASCII small capital */ + b |= 1; w -= 0x20; + } + } + } + } + dp->fn[i++] = (BYTE)w; + } + + if (dp->fn[0] == DDE) dp->fn[0] = NDDE; /* If the first character collides with deleted mark, replace it with 0x05 */ + + if (ni == 8) b <<= 2; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ + cf |= NS_LFN; + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ + if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + } + + dp->fn[NS] = cf; /* SFN is created */ + + return FR_OK; + + +#else /* Non-LFN configuration */ + BYTE b, c, d, *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ + sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = b = 0; ni = 8; +#if _FS_RPATH + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; + *path = &p[si]; /* Return pointer to the next segment */ + sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; + if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ + if (c == '.' || i >= ni) { + if (ni != 8 || c != '.') return FR_INVALID_NAME; + i = 8; ni = 11; + b <<= 2; continue; + } + if (c >= 0x80) { /* Extended character? */ + b |= 3; /* Eliminate NT flag */ +#ifdef _EXCVT + c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else +#if !_DF1S + return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ +#endif +#endif + } + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ + return FR_INVALID_NAME; + sfn[i++] = c; + sfn[i++] = d; + } else { /* Single byte code */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ + return FR_INVALID_NAME; + if (IsUpper(c)) { /* ASCII large capital? */ + b |= 2; + } else { + if (IsLower(c)) { /* ASCII small capital? */ + b |= 1; c -= 0x20; + } + } + sfn[i++] = c; + } + } + *path = &p[si]; /* Return pointer to the next segment */ + c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + + if (!i) return FR_INVALID_NAME; /* Reject nul string */ + if (sfn[0] == DDE) sfn[0] = NDDE; /* When first character collides with DDE, replace it with 0x05 */ + + if (ni == 8) b <<= 2; + if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ + if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ + + sfn[NS] = c; /* Store NT flag, File name is created */ + + return FR_OK; +#endif +} + + + + +/*-----------------------------------------------------------------------*/ +/* Follow a file path */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ +) +{ + FRESULT res; + BYTE *dir, ns; + + +#if _FS_RPATH + if (*path == '/' || *path == '\\') { /* There is a heading separator */ + path++; dp->sclust = 0; /* Strip it and start from the root directory */ + } else { /* No heading separator */ + dp->sclust = dp->fs->cdir; /* Start from the current directory */ + } +#else + if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ + path++; + dp->sclust = 0; /* Always start from the root directory */ +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + res = dir_sdi(dp, 0); + dp->dir = 0; + } else { /* Follow path */ + for (;;) { + res = create_name(dp, &path); /* Get a segment name of the path */ + if (res != FR_OK) break; + res = dir_find(dp); /* Find an object with the sagment name */ + ns = dp->fn[NS]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */ + dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */ + if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ + res = FR_OK; /* Ended at the root directroy. Function completed. */ + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ + } + } + break; + } + if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ + dir = dp->dir; /* Follow the sub-directory */ + if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; break; + } + dp->sclust = ld_clust(dp->fs, dir); + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get logical drive number from path name */ +/*-----------------------------------------------------------------------*/ + +static +int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ + const TCHAR** path /* Pointer to pointer to the path name */ +) +{ + const TCHAR *tp, *tt; + UINT i; + int vol = -1; + + + if (*path) { /* If the pointer is not a null */ + for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ + if (*tt == ':') { /* If a ':' is exist in the path name */ + tp = *path; + i = *tp++ - '0'; + if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ + if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = ++tt; + } + } else { /* No numeric drive number */ +#if _STR_VOLUME_ID /* Find string drive id */ + static const char* const str[] = {_VOLUME_STRS}; + const char *sp; + char c; + TCHAR tc; + + i = 0; tt++; + do { + sp = str[i]; tp = *path; + do { /* Compare a string drive id with path name */ + c = *sp++; tc = *tp++; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */ + if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = tt; + } +#endif + } + return vol; + } +#if _FS_RPATH && _VOLUMES >= 2 + vol = CurrVol; /* Current drive */ +#else + vol = 0; /* Drive 0 */ +#endif + } + return vol; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load a sector and check if it is an FAT boot sector */ +/*-----------------------------------------------------------------------*/ + +static +BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */ + FATFS* fs, /* File system object */ + DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ +) +{ + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) /* Load boot record */ + return 3; + + if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + return 2; + + if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ + return 0; + if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ + return 0; + + return 1; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Find logical drive and check if the volume is mounted */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ + FATFS** rfs, /* Pointer to pointer to the found file system object */ + const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + BYTE wmode /* !=0: Check write protection for write access */ +) +{ + BYTE fmt; + int vol; + DSTATUS stat; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat; + WORD nrsv; + FATFS *fs; + + + /* Get logical drive number from the path name */ + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) return FR_INVALID_DRIVE; + + /* Check if the file system object is valid or not */ + fs = FatFs[vol]; /* Get pointer to the file system object */ + if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ + + ENTER_FF(fs); /* Lock the volume */ + *rfs = fs; /* Return pointer to the file system object */ + + if (fs->fs_type) { /* If the volume has been mounted */ + stat = disk_status(fs->drv); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + return FR_OK; /* The file system object is valid */ + } + } + + /* The file system object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ + + fs->fs_type = 0; /* Clear the file system object */ + fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ + stat = disk_initialize(fs->drv); /* Initialize the physical drive */ + if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ + if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK + || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; +#endif + /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + bsect = 0; + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ + if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ + UINT i; + DWORD br[4]; + + for (i = 0; i < 4; i++) { /* Get partition offset */ + BYTE *pt = fs->win+MBR_Table + i * SZ_PTE; + br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; + } + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + if (i) i--; + do { /* Find an FAT volume */ + bsect = br[i]; + fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ + } while (!LD2PT(vol) && fmt && ++i < 4); + } + if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* An FAT volume is found. Following code initializes the file system object */ + + if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + + fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */ + if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ + if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ + return FR_NO_FILESYSTEM; + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ + return FR_NO_FILESYSTEM; + + fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZ_DIR)) /* (Must be sector aligned) */ + return FR_NO_FILESYSTEM; + + tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */ + if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32); + + nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT12; + if (nclst >= MIN_FAT16) fmt = FS_FAT16; + if (nclst >= MIN_FAT32) fmt = FS_FAT32; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than needed) */ + return FR_NO_FILESYSTEM; + +#if !_FS_READONLY + /* Initialize cluster allocation information */ + fs->last_clust = fs->free_clust = 0xFFFFFFFF; + + /* Get fsinfo if available */ + fs->fsi_flag = 0x80; +#if (_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ + && LD_WORD(fs->win+BPB_FSInfo) == 1 + && move_window(fs, bsect + 1) == FR_OK) + { + fs->fsi_flag = 0; + if (LD_WORD(fs->win+BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + && LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 + && LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) + { +#if (_FS_NOFSINFO & 1) == 0 + fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count); +#endif +#if (_FS_NOFSINFO & 2) == 0 + fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free); +#endif + } + } +#endif +#endif + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ +#if _FS_RPATH + fs->cdir = 0; /* Set current directory to root */ +#endif +#if _FS_LOCK /* Clear file lock semaphores */ + clear_lock(fs); +#endif + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/directory object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ + void* obj /* Pointer to the object FIL/DIR to check validity */ +) +{ + FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ + + + if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) + return FR_INVALID_OBJECT; + + ENTER_FF(fil->fs); /* Lock file system */ + + if (disk_status(fil->fs->drv) & STA_NOINIT) + return FR_NOT_READY; + + return FR_OK; +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +--------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ + const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ +) +{ + FATFS *cfs; + int vol; + FRESULT res; + const TCHAR *rp = path; + + + vol = get_ldnumber(&rp); + if (vol < 0) return FR_INVALID_DRIVE; + cfs = FatFs[vol]; /* Pointer to fs object */ + + if (cfs) { +#if _FS_LOCK + clear_lock(cfs); +#endif +#if _FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#endif + cfs->fs_type = 0; /* Clear old fs object */ + } + + if (fs) { + fs->fs_type = 0; /* Clear new fs object */ +#if _FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; +#endif + } + FatFs[vol] = fs; /* Register new fs object */ + + if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ + + res = find_volume(&fs, &path, 0); /* Force mounted the volume */ + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_open ( + FIL* fp, /* Pointer to the blank file object */ + const TCHAR* path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEF_NAMEBUF; + + + if (!fp) return FR_INVALID_OBJECT; + fp->fs = 0; /* Clear file object */ + + /* Get logical drive number */ +#if !_FS_READONLY + mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; + res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); +#else + mode &= FA_READ; + res = find_volume(&dj.fs, &path, 0); +#endif + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + dir = dj.dir; +#if !_FS_READONLY /* R/W configuration */ + if (res == FR_OK) { + if (!dir) /* Default directory itself */ + res = FR_INVALID_NAME; +#if _FS_LOCK + else + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + DWORD dw, cl; + + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ +#if _FS_LOCK + res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + mode |= FA_CREATE_ALWAYS; /* File is created */ + dir = dj.dir; /* New entry */ + } + else { /* Any object is already existing */ + if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) /* Cannot create as new file */ + res = FR_EXIST; + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ + dw = get_fattime(); /* Created time */ + ST_DWORD(dir+DIR_CrtTime, dw); + dir[DIR_Attr] = 0; /* Reset attribute */ + ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */ + cl = ld_clust(dj.fs, dir); /* Get start cluster */ + st_clust(dir, 0); /* cluster = 0 */ + dj.fs->wflag = 1; + if (cl) { /* Remove the cluster chain if exist */ + dw = dj.fs->winsect; + res = remove_chain(dj.fs, cl); + if (res == FR_OK) { + dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ + res = move_window(dj.fs, dw); + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Follow succeeded */ + if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ + res = FR_DENIED; + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ + mode |= FA__WRITTEN; + fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dir; +#if _FS_LOCK + fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->lockid) res = FR_INT_ERR; +#endif + } + +#else /* R/O configuration */ + if (res == FR_OK) { /* Follow succeeded */ + dir = dj.dir; + if (!dir) { /* Current directory itself */ + res = FR_INVALID_NAME; + } else { + if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ + res = FR_NO_FILE; + } + } +#endif + FREE_BUF(); + + if (res == FR_OK) { + fp->flag = mode; /* File access mode */ + fp->err = 0; /* Clear error flag */ + fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ + fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ + fp->fptr = 0; /* File pointer */ + fp->dsect = 0; +#if _USE_FASTSEEK + fp->cltbl = 0; /* Normal seek mode */ +#endif + fp->fs = dj.fs; /* Validate file object */ + fp->id = fp->fs->id; + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ +) +{ + FRESULT res; + DWORD clst, sect, remain; + UINT rcnt, cc; + BYTE csect, *rbuff = (BYTE*)buff; + + + *br = 0; /* Clear read byte counter */ + + res = validate(fp); /* Check validity */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + remain = fp->fsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr; /* Repeat until all data read */ + rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ + } + if (clst < 2) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_read(fp->fs->drv, rbuff, sect, cc)) + ABORT(fp->fs, FR_DISK_ERR); +#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if _FS_TINY + if (fp->fs->wflag && fp->fs->winsect - sect < cc) + mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); +#else + if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) + mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); +#endif +#endif + rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !_FS_TINY + if (fp->dsect != sect) { /* Load data sector if not in cache */ +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1)) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, sect, 1)) /* Fill sector cache */ + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ + if (rcnt > btr) rcnt = btr; +#if _FS_TINY + if (move_window(fp->fs, fp->dsect)) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ +#else + mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ +#endif + } + + LEAVE_FF(fp->fs, FR_OK); +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL* fp, /* Pointer to the file object */ + const void *buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Pointer to number of bytes written */ +) +{ + FRESULT res; + DWORD clst, sect; + UINT wcnt, cc; + const BYTE *wbuff = (const BYTE*)buff; + BYTE csect; + + + *bw = 0; /* Clear write byte counter */ + + res = validate(fp); /* Check validity */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ + + for ( ; btw; /* Repeat until all data written */ + wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + if (clst == 0) /* When no cluster is allocated, */ + clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ + } +#if _FS_TINY + if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ + ABORT(fp->fs, FR_DISK_ERR); +#else + if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1)) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_write(fp->fs->drv, wbuff, sect, cc)) + ABORT(fp->fs, FR_DISK_ERR); +#if _FS_MINIMIZE <= 2 +#if _FS_TINY + if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); + fp->fs->wflag = 0; + } +#else + if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); + fp->flag &= ~FA__DIRTY; + } +#endif +#endif + wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } +#if _FS_TINY + if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ + if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); + fp->fs->winsect = sect; + } +#else + if (fp->dsect != sect) { /* Fill sector cache with file data */ + if (fp->fptr < fp->fsize && + disk_read(fp->fs->drv, fp->buf, sect, 1)) + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ + if (wcnt > btw) wcnt = btw; +#if _FS_TINY + if (move_window(fp->fs, fp->dsect)) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ + fp->fs->wflag = 1; +#else + mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ + fp->flag |= FA__DIRTY; +#endif + } + + if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ + fp->flag |= FA__WRITTEN; /* Set file change flag */ + + LEAVE_FF(fp->fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + DWORD tm; + BYTE *dir; + + + res = validate(fp); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ + /* Write-back dirty buffer */ +#if !_FS_TINY + if (fp->flag & FA__DIRTY) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1)) + LEAVE_FF(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + /* Update the directory entry */ + res = move_window(fp->fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */ + st_clust(dir, fp->sclust); /* Update start cluster */ + tm = get_fattime(); /* Update updated time */ + ST_DWORD(dir+DIR_WrtTime, tm); + ST_WORD(dir+DIR_LstAccDate, 0); + fp->flag &= ~FA__WRITTEN; + fp->fs->wflag = 1; + res = sync_fs(fp->fs); + } + } + } + + LEAVE_FF(fp->fs, res); +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL *fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + + +#if !_FS_READONLY + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) +#endif + { + res = validate(fp); /* Lock volume */ + if (res == FR_OK) { +#if _FS_REENTRANT + FATFS *fs = fp->fs; +#endif +#if _FS_LOCK + res = dec_lock(fp->lockid); /* Decrement file open counter */ + if (res == FR_OK) +#endif + fp->fs = 0; /* Invalidate file object */ +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Current Directory or Current Drive, Get Current Directory */ +/*-----------------------------------------------------------------------*/ + +#if _FS_RPATH >= 1 +#if _VOLUMES >= 2 +FRESULT f_chdrive ( + const TCHAR* path /* Drive number */ +) +{ + int vol; + + + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + + CurrVol = (BYTE)vol; + + return FR_OK; +} +#endif + + +FRESULT f_chdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the path */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (!dj.dir) { + dj.fs->cdir = dj.sclust; /* Start directory itself */ + } else { + if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ + dj.fs->cdir = ld_clust(dj.fs, dj.dir); + else + res = FR_NO_PATH; /* Reached but a file */ + } + } + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(dj.fs, res); +} + + +#if _FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of path */ +) +{ + FRESULT res; + DIR dj; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEF_NAMEBUF; + + + *buff = 0; + /* Get logical drive number */ + res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ + if (res == FR_OK) { + INIT_BUF(dj); + i = len; /* Bottom of buffer (directory stack base) */ + dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1); /* Get parent directory */ + if (res != FR_OK) break; + res = dir_read(&dj, 0); + if (res != FR_OK) break; + dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) break; + if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; +#if _USE_LFN + fno.lfname = buff; + fno.lfsize = i; +#endif + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + tp = fno.fname; +#if _USE_LFN + if (*buff) tp = buff; +#endif + for (n = 0; tp[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = tp[--n]; + buff[--i] = '/'; + } + tp = buff; + if (res == FR_OK) { +#if _VOLUMES >= 2 + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; +#endif + if (i == len) { /* Root-directory */ + *tp++ = '/'; + } else { /* Sub-directroy */ + do /* Add stacked path str */ + *tp++ = buff[i++]; + while (i < len); + } + } + *tp = 0; + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} +#endif /* _FS_RPATH >= 2 */ +#endif /* _FS_RPATH >= 1 */ + + + +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File R/W Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + FRESULT res; + + + res = validate(fp); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + +#if _USE_FASTSEEK + if (fp->cltbl) { /* Fast seek */ + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; + + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; ulen = 2; /* Given table size and required table size */ + cl = fp->sclust; /* Top of the chain */ + if (cl) { + do { + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { + pcl = cl; ncl++; + cl = get_fat(fp->fs, cl); + if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + } while (cl == pcl + 1); + if (ulen <= tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; *tbl++ = tcl; + } + } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ + } + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) + *tbl = 0; /* Terminate table */ + else + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ + + } else { /* Fast seek */ + if (ofs > fp->fsize) /* Clip offset at the file size */ + ofs = fp->fsize; + fp->fptr = ofs; /* Set file pointer */ + if (ofs) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clust2sect(fp->fs, fp->clust); + if (!dsc) ABORT(fp->fs, FR_INT_ERR); + dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); + if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1)) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, dsc, 1)) /* Load current sector */ + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { + DWORD clst, bcs, nsect, ifptr; + + if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ +#if !_FS_READONLY + && !(fp->flag & FA_WRITE) +#endif + ) ofs = fp->fsize; + + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs) { + bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->sclust; /* start from the first cluster */ +#if !_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(fp->fs, 0); + if (clst == 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ +#if !_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ + if (clst == 0) { /* When disk gets full, clip file size */ + ofs = bcs; break; + } + } else +#endif + clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); + fp->clust = clst; + fp->fptr += bcs; + ofs -= bcs; + } + fp->fptr += ofs; + if (ofs % SS(fp->fs)) { + nsect = clust2sect(fp->fs, clst); /* Current sector */ + if (!nsect) ABORT(fp->fs, FR_INT_ERR); + nsect += ofs / SS(fp->fs); + } + } + } + if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1)) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, nsect, 1)) /* Fill sector cache */ + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = nsect; + } +#if !_FS_READONLY + if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ + fp->fsize = fp->fptr; + fp->flag |= FA__WRITTEN; + } +#endif + } + + LEAVE_FF(fp->fs, res); +} + + + +#if _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Create a Directory Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_opendir ( + DIR* dp, /* Pointer to directory object to create */ + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + FATFS* fs; + DEF_NAMEBUF; + + + if (!dp) return FR_INVALID_OBJECT; + + /* Get logical drive number */ + res = find_volume(&fs, &path, 0); + if (res == FR_OK) { + dp->fs = fs; + INIT_BUF(*dp); + res = follow_path(dp, path); /* Follow the path to the directory */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (dp->dir) { /* It is not the origin directory itself */ + if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ + dp->sclust = ld_clust(fs, dp->dir); + else /* The object is a file */ + res = FR_NO_PATH; + } + if (res == FR_OK) { + dp->id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ +#if _FS_LOCK + if (res == FR_OK) { + if (dp->sclust) { + dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!dp->lockid) + res = FR_TOO_MANY_OPEN_FILES; + } else { + dp->lockid = 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Close Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_closedir ( + DIR *dp /* Pointer to the directory object to be closed */ +) +{ + FRESULT res; + + + res = validate(dp); + if (res == FR_OK) { +#if _FS_REENTRANT + FATFS *fs = dp->fs; +#endif +#if _FS_LOCK + if (dp->lockid) /* Decrement sub-directory open counter */ + res = dec_lock(dp->lockid); + if (res == FR_OK) +#endif + dp->fs = 0; /* Invalidate directory object */ +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entries in Sequence */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_readdir ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DEF_NAMEBUF; + + + res = validate(dp); /* Check validity of the object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_BUF(*dp); + res = dir_read(dp, 0); /* Read an item */ + if (res == FR_NO_FILE) { /* Reached end of directory */ + dp->sect = 0; + res = FR_OK; + } + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dp, fno); /* Get the object information */ + res = dir_next(dp, 0); /* Increment index for next */ + if (res == FR_NO_FILE) { + dp->sect = 0; + res = FR_OK; + } + } + FREE_BUF(); + } + } + + LEAVE_FF(dp->fs, res); +} + + + +#if _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_stat ( + const TCHAR* path, /* Pointer to the file path */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.dir) { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); + } else { /* It is root directory */ + res = FR_INVALID_NAME; + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + const TCHAR* path, /* Path name of the logical drive number */ + DWORD* nclst, /* Pointer to a variable to return number of free clusters */ + FATFS** fatfs /* Pointer to return pointer to corresponding file system object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, sect, stat; + UINT i; + BYTE fat, *p; + + + /* Get logical drive number */ + res = find_volume(fatfs, &path, 0); + fs = *fatfs; + if (res == FR_OK) { + /* If free_clust is valid, return it without full cluster scan */ + if (fs->free_clust <= fs->n_fatent - 2) { + *nclst = fs->free_clust; + } else { + /* Get number of free clusters */ + fat = fs->fs_type; + n = 0; + if (fat == FS_FAT12) { + clst = 2; + do { + stat = get_fat(fs, clst); + if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0) n++; + } while (++clst < fs->n_fatent); + } else { + clst = fs->n_fatent; + sect = fs->fatbase; + i = 0; p = 0; + do { + if (!i) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + p = fs->win; + i = SS(fs); + } + if (fat == FS_FAT16) { + if (LD_WORD(p) == 0) n++; + p += 2; i -= 2; + } else { + if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; + p += 4; i -= 4; + } + } while (--clst); + } + fs->free_clust = n; + fs->fsi_flag |= 1; + *nclst = n; + } + } + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + DWORD ncl; + + + res = validate(fp); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->err) { /* Check error */ + res = (FRESULT)fp->err; + } else { + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + res = FR_DENIED; + } + } + if (res == FR_OK) { + if (fp->fsize > fp->fptr) { + fp->fsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA__WRITTEN; + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(fp->fs, fp->sclust); + fp->sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(fp->fs, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fp->fs->n_fatent) { + res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); + if (res == FR_OK) res = remove_chain(fp->fs, ncl); + } + } +#if !_FS_TINY + if (res == FR_OK && (fp->flag & FA__DIRTY)) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1)) + res = FR_DISK_ERR; + else + fp->flag &= ~FA__DIRTY; + } +#endif + } + if (res != FR_OK) fp->err = (FRESULT)res; + } + + LEAVE_FF(fp->fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File or Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + const TCHAR* path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + DIR dj, sdj; + BYTE *dir; + DWORD dclst; + DEF_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; /* Cannot remove dot entry */ +#if _FS_LOCK + if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */ +#endif + if (res == FR_OK) { /* The object is accessible */ + dir = dj.dir; + if (!dir) { + res = FR_INVALID_NAME; /* Cannot remove the start directory */ + } else { + if (dir[DIR_Attr] & AM_RDO) + res = FR_DENIED; /* Cannot remove R/O object */ + } + dclst = ld_clust(dj.fs, dir); + if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */ + if (dclst < 2) { + res = FR_INT_ERR; + } else { + mem_cpy(&sdj, &dj, sizeof (DIR)); /* Check if the sub-directory is empty or not */ + sdj.sclust = dclst; + res = dir_sdi(&sdj, 2); /* Exclude dot entries */ + if (res == FR_OK) { + res = dir_read(&sdj, 0); /* Read an item */ + if (res == FR_OK /* Not empty directory */ +#if _FS_RPATH + || dclst == dj.fs->cdir /* Current directory */ +#endif + ) res = FR_DENIED; + if (res == FR_NO_FILE) res = FR_OK; /* Empty */ + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK) { + if (dclst) /* Remove the cluster chain if exist */ + res = remove_chain(dj.fs, dclst); + if (res == FR_OK) res = sync_fs(dj.fs); + } + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir, n; + DWORD dsc, dcl, pcl, tm = get_fattime(); + DEF_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) /* Flush FAT */ + res = sync_window(dj.fs); + if (res == FR_OK) { /* Initialize the new directory table */ + dsc = clust2sect(dj.fs, dcl); + dir = dj.fs->win; + mem_set(dir, 0, SS(dj.fs)); + mem_set(dir+DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + ST_DWORD(dir+DIR_WrtTime, tm); + st_clust(dir, dcl); + mem_cpy(dir+SZ_DIR, dir, SZ_DIR); /* Create ".." entry */ + dir[SZ_DIR+1] = '.'; pcl = dj.sclust; + if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) + pcl = 0; + st_clust(dir+SZ_DIR, pcl); + for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + dj.fs->winsect = dsc++; + dj.fs->wflag = 1; + res = sync_window(dj.fs); + if (res != FR_OK) break; + mem_set(dir, 0, SS(dj.fs)); + } + } + if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ + if (res != FR_OK) { + remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ + } else { + dir = dj.dir; + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(dir+DIR_WrtTime, tm); /* Created time */ + st_clust(dir, dcl); /* Table start cluster */ + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + const TCHAR* path, /* Pointer to the file path */ + BYTE value, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEF_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Is it a root directory? */ + res = FR_INVALID_NAME; + } else { /* File or sub directory */ + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the time stamp to be set */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEF_NAMEBUF; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Root directory */ + res = FR_INVALID_NAME; + } else { /* File or sub-directory */ + ST_WORD(dir+DIR_WrtTime, fno->ftime); + ST_WORD(dir+DIR_WrtDate, fno->fdate); + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR* path_old, /* Pointer to the object to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + BYTE buf[21], *dir; + DWORD dw; + DEF_NAMEBUF; + + + /* Get logical drive number of the source object */ + res = find_volume(&djo.fs, &path_old, 1); + if (res == FR_OK) { + djn.fs = djo.fs; + INIT_BUF(djo); + res = follow_path(&djo, path_old); /* Check old object */ + if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; +#if _FS_LOCK + if (res == FR_OK) res = chk_lock(&djo, 2); +#endif + if (res == FR_OK) { /* Old object is found */ + if (!djo.dir) { /* Is root dir? */ + res = FR_NO_FILE; + } else { + mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except name */ + mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ + res = follow_path(&djn, path_new); /* and check if new object is exist */ + else + res = FR_INVALID_DRIVE; + if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ + if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */ +/* Start critical section that any interruption can cause a cross-link */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + dir = djn.dir; /* Copy object information except name */ + mem_cpy(dir+13, buf+2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + djo.fs->wflag = 1; + if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */ + dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); + if (!dw) { + res = FR_INT_ERR; + } else { + res = move_window(djo.fs, dw); + dir = djo.fs->win+SZ_DIR; /* .. entry */ + if (res == FR_OK && dir[1] == '.') { + dw = (djo.fs->fs_type == FS_FAT32 && djn.sclust == djo.fs->dirbase) ? 0 : djn.sclust; + st_clust(dir, dw); + djo.fs->wflag = 1; + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) + res = sync_fs(djo.fs); + } + } +/* End critical section */ + } + } + } + FREE_BUF(); + } + + LEAVE_FF(djo.fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + +#if _USE_LABEL +/*-----------------------------------------------------------------------*/ +/* Get volume label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getlabel ( + const TCHAR* path, /* Path name of the logical drive number */ + TCHAR* label, /* Pointer to a buffer to return the volume label */ + DWORD* vsn /* Pointer to a variable to return the volume serial number */ +) +{ + FRESULT res; + DIR dj; + UINT i, j; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + + /* Get volume label */ + if (res == FR_OK && label) { + dj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ + if (res == FR_OK) { /* A volume label is exist */ +#if _USE_LFN && _LFN_UNICODE + WCHAR w; + i = j = 0; + do { + w = (i < 11) ? dj.dir[i++] : ' '; + if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) + w = w << 8 | dj.dir[i++]; + label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ + } while (j < 11); +#else + mem_cpy(label, dj.dir, 11); +#endif + j = 11; + do { + label[j] = 0; + if (!j) break; + } while (label[--j] == ' '); + } + if (res == FR_NO_FILE) { /* No label, return nul string */ + label[0] = 0; + res = FR_OK; + } + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(dj.fs, dj.fs->volbase); + if (res == FR_OK) { + i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; + *vsn = LD_DWORD(&dj.fs->win[i]); + } + } + + LEAVE_FF(dj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Set volume label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setlabel ( + const TCHAR* label /* Pointer to the volume label to set */ +) +{ + FRESULT res; + DIR dj; + BYTE vn[11]; + UINT i, j, sl; + WCHAR w; + DWORD tm; + + + /* Get logical drive number */ + res = find_volume(&dj.fs, &label, 1); + if (res) LEAVE_FF(dj.fs, res); + + /* Create a volume label in directory form */ + vn[0] = 0; + for (sl = 0; label[sl]; sl++) ; /* Get name length */ + for ( ; sl && label[sl-1] == ' '; sl--) ; /* Remove trailing spaces */ + if (sl) { /* Create volume label in directory form */ + i = j = 0; + do { +#if _USE_LFN && _LFN_UNICODE + w = ff_convert(ff_wtoupper(label[i++]), 0); +#else + w = (BYTE)label[i++]; + if (IsDBCS1(w)) + w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; +#if _USE_LFN + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); +#else + if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ +#ifdef _EXCVT + if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else + if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ +#endif +#endif +#endif + if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ + LEAVE_FF(dj.fs, FR_INVALID_NAME); + if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); + vn[j++] = (BYTE)w; + } while (i < sl); + while (j < 11) vn[j++] = ' '; + } + + /* Set volume label */ + dj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ + if (res == FR_OK) { /* A volume label is found */ + if (vn[0]) { + mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ + tm = get_fattime(); + ST_DWORD(dj.dir+DIR_WrtTime, tm); + } else { + dj.dir[0] = DDE; /* Remove the volume label */ + } + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } else { /* No volume label is found or error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (vn[0]) { /* Create volume label as new */ + res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ + if (res == FR_OK) { + mem_set(dj.dir, 0, SZ_DIR); /* Set volume label */ + mem_cpy(dj.dir, vn, 11); + dj.dir[DIR_Attr] = AM_VOL; + tm = get_fattime(); + ST_DWORD(dj.dir+DIR_WrtTime, tm); + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + } + } + + LEAVE_FF(dj.fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_LABEL */ + + + +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly (available on only tiny cfg) */ +/*-----------------------------------------------------------------------*/ +#if _USE_FORWARD && _FS_TINY + +FRESULT f_forward ( + FIL* fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btf, /* Number of bytes to forward */ + UINT* bf /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + DWORD remain, clst, sect; + UINT rcnt; + BYTE csect; + + + *bf = 0; /* Clear transfer byte counter */ + + res = validate(fp); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + + remain = fp->fsize - fp->fptr; + if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ + fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if (!csect) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->sclust : get_fat(fp->fs, fp->clust); + if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + if (move_window(fp->fs, sect)) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + fp->dsect = sect; + rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ + if (rcnt > btf) rcnt = btf; + rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); + if (!rcnt) ABORT(fp->fs, FR_INT_ERR); + } + + LEAVE_FF(fp->fs, FR_OK); +} +#endif /* _USE_FORWARD */ + + + +#if _USE_MKFS && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Create File System on the Drive */ +/*-----------------------------------------------------------------------*/ +#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ +#define N_FATS 1 /* Number of FAT copies (1 or 2) */ + + +FRESULT f_mkfs ( + const TCHAR* path, /* Logical drive number */ + BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ + UINT au /* Allocation unit [bytes] */ +) +{ + static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; + static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; + int vol; + BYTE fmt, md, sys, *tbl, pdrv, part; + DWORD n_clst, vs, n, wsect; + UINT i; + DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ + DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ + FATFS *fs; + DSTATUS stat; + + + /* Check mounted drive and clear work area */ + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + if (sfd > 1) return FR_INVALID_PARAMETER; + if (au & (au - 1)) return FR_INVALID_PARAMETER; + fs = FatFs[vol]; + if (!fs) return FR_NOT_ENABLED; + fs->fs_type = 0; + pdrv = LD2PD(vol); /* Physical drive */ + part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ + + /* Get disk statics */ + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; +#if _MAX_SS != _MIN_SS /* Get disk sector size */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) + return FR_DISK_ERR; +#endif + if (_MULTI_PARTITION && part) { + /* Get partition information from partition table in the MBR */ + if (disk_read(pdrv, fs->win, 0, 1)) return FR_DISK_ERR; + if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; + tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; + if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ + b_vol = LD_DWORD(tbl+8); /* Volume start sector */ + n_vol = LD_DWORD(tbl+12); /* Volume size */ + } else { + /* Create a partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) + return FR_DISK_ERR; + b_vol = (sfd) ? 0 : 63; /* Volume start sector */ + n_vol -= b_vol; /* Volume size */ + } + + if (!au) { /* AU auto selection */ + vs = n_vol / (2000 / (SS(fs) / 512)); + for (i = 0; vs < vst[i]; i++) ; + au = cst[i]; + } + au /= SS(fs); /* Number of sectors per cluster */ + if (au == 0) au = 1; + if (au > 128) au = 128; + + /* Pre-compute number of clusters and FAT sub-type */ + n_clst = n_vol / au; + fmt = FS_FAT12; + if (n_clst >= MIN_FAT16) fmt = FS_FAT16; + if (n_clst >= MIN_FAT32) fmt = FS_FAT32; + + /* Determine offset and size of FAT structure */ + if (fmt == FS_FAT32) { + n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); + n_rsv = 32; + n_dir = 0; + } else { + n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; + n_fat = (n_fat + SS(fs) - 1) / SS(fs); + n_rsv = 1; + n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs); + } + b_fat = b_vol + n_rsv; /* FAT area start sector */ + b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ + b_data = b_dir + n_dir; /* Data area start sector */ + if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + + /* Align data start sector to erase block boundary (for flash memory media) */ + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; + n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ + n = (n - b_data) / N_FATS; + if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ + n_rsv += n; + b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + n_fat += n; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; + if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) + || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) + return FR_MKFS_ABORTED; + + /* Determine system ID in the partition table */ + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (fmt == FS_FAT12 && n_vol < 0x10000) { + sys = 0x01; /* FAT12(<65536) */ + } else { + sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ + } + } + + if (_MULTI_PARTITION && part) { + /* Update system ID in the partition table */ + tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; + tbl[4] = sys; + if (disk_write(pdrv, fs->win, 0, 1)) /* Write it to teh MBR */ + return FR_DISK_ERR; + md = 0xF8; + } else { + if (sfd) { /* No partition table (SFD) */ + md = 0xF0; + } else { /* Create partition table (FDISK) */ + mem_set(fs->win, 0, SS(fs)); + tbl = fs->win+MBR_Table; /* Create partition table for single partition in the drive */ + tbl[1] = 1; /* Partition start head */ + tbl[2] = 1; /* Partition start sector */ + tbl[3] = 0; /* Partition start cylinder */ + tbl[4] = sys; /* System type */ + tbl[5] = 254; /* Partition end head */ + n = (b_vol + n_vol) / 63 / 255; + tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ + tbl[7] = (BYTE)n; /* End cylinder */ + ST_DWORD(tbl+8, 63); /* Partition start in LBA */ + ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */ + ST_WORD(fs->win+BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(pdrv, fs->win, 0, 1)) /* Write it to the MBR */ + return FR_DISK_ERR; + md = 0xF8; + } + } + + /* Create BPB in the VBR */ + tbl = fs->win; /* Clear sector */ + mem_set(tbl, 0, SS(fs)); + mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ + i = SS(fs); /* Sector size */ + ST_WORD(tbl+BPB_BytsPerSec, i); + tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ + ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ + tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ + i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ + ST_WORD(tbl+BPB_RootEntCnt, i); + if (n_vol < 0x10000) { /* Number of total sectors */ + ST_WORD(tbl+BPB_TotSec16, n_vol); + } else { + ST_DWORD(tbl+BPB_TotSec32, n_vol); + } + tbl[BPB_Media] = md; /* Media descriptor */ + ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */ + ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */ + ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */ + n = get_fattime(); /* Use current time as VSN */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl+BS_VolID32, n); /* VSN */ + ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */ + ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */ + ST_WORD(tbl+BPB_FSInfo, 1); /* FSINFO record offset (VBR+1) */ + ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */ + tbl[BS_DrvNum32] = 0x80; /* Drive number */ + tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + ST_DWORD(tbl+BS_VolID, n); /* VSN */ + ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */ + tbl[BS_DrvNum] = 0x80; /* Drive number */ + tbl[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, tbl, b_vol, 1)) /* Write it to the VBR sector */ + return FR_DISK_ERR; + if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */ + disk_write(pdrv, tbl, b_vol + 6, 1); + + /* Initialize FAT area */ + wsect = b_fat; + for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ + mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ + n = md; /* Media descriptor byte */ + if (fmt != FS_FAT32) { + n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; + ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */ + } else { + n |= 0xFFFFFF00; + ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */ + ST_DWORD(tbl+4, 0xFFFFFFFF); + ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ + } + if (disk_write(pdrv, tbl, wsect++, 1)) + return FR_DISK_ERR; + mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ + for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ + if (disk_write(pdrv, tbl, wsect++, 1)) + return FR_DISK_ERR; + } + } + + /* Initialize root directory */ + i = (fmt == FS_FAT32) ? au : (UINT)n_dir; + do { + if (disk_write(pdrv, tbl, wsect++, 1)) + return FR_DISK_ERR; + } while (--i); + +#if _USE_ERASE /* Erase data area if needed */ + { + DWORD eb[2]; + + eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; + disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb); + } +#endif + + /* Create FSINFO if needed */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl+FSI_LeadSig, 0x41615252); + ST_DWORD(tbl+FSI_StrucSig, 0x61417272); + ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + ST_DWORD(tbl+FSI_Nxt_Free, 2); /* Last allocated cluster# */ + ST_WORD(tbl+BS_55AA, 0xAA55); + disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */ + disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */ + } + + return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; +} + + + +#if _MULTI_PARTITION +/*-----------------------------------------------------------------------*/ +/* Divide Physical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_fdisk ( + BYTE pdrv, /* Physical drive number */ + const DWORD szt[], /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer */ +) +{ + UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; + BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; + DSTATUS stat; + DWORD sz_disk, sz_part, s_part; + + + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; + + /* Determine CHS in the table regardless of the drive geometry */ + for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; + if (n == 256) n--; + e_hd = n - 1; + sz_cyl = 63 * n; + tot_cyl = sz_disk / sz_cyl; + + /* Create partition table */ + mem_set(buf, 0, _MAX_SS); + p = buf + MBR_Table; b_cyl = 0; + for (i = 0; i < 4; i++, p += SZ_PTE) { + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; + if (!p_cyl) continue; + s_part = (DWORD)sz_cyl * b_cyl; + sz_part = (DWORD)sz_cyl * p_cyl; + if (i == 0) { /* Exclude first track of cylinder 0 */ + s_hd = 1; + s_part += 63; sz_part -= 63; + } else { + s_hd = 0; + } + e_cyl = b_cyl + p_cyl - 1; + if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; + + /* Set partition table */ + p[1] = s_hd; /* Start head */ + p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[3] = (BYTE)b_cyl; /* Start cylinder */ + p[4] = 0x06; /* System type (temporary setting) */ + p[5] = e_hd; /* End head */ + p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[7] = (BYTE)e_cyl; /* End cylinder */ + ST_DWORD(p + 8, s_part); /* Start sector in LBA */ + ST_DWORD(p + 12, sz_part); /* Partition size */ + + /* Next partition */ + b_cyl += p_cyl; + } + ST_WORD(p, 0xAA55); + + /* Write it to the MBR */ + return (disk_write(pdrv, buf, 0, 1) || disk_ioctl(pdrv, CTRL_SYNC, 0)) ? FR_DISK_ERR : FR_OK; +} + + +#endif /* _MULTI_PARTITION */ +#endif /* _USE_MKFS && !_FS_READONLY */ + + + + +#if _USE_STRFUNC +/*-----------------------------------------------------------------------*/ +/* Get a string from the file */ +/*-----------------------------------------------------------------------*/ + +TCHAR* f_gets ( + TCHAR* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer (characters) */ + FIL* fp /* Pointer to the file object */ +) +{ + int n = 0; + TCHAR c, *p = buff; + BYTE s[2]; + UINT rc; + + + while (n < len - 1) { /* Read characters until buffer gets filled */ +#if _USE_LFN && _LFN_UNICODE +#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; + if (c >= 0x80) { + if (c < 0xC0) continue; /* Skip stray trailer */ + if (c < 0xE0) { /* Two-byte sequence */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = (c & 0x1F) << 6 | (s[0] & 0x3F); + if (c < 0x80) c = '?'; + } else { + if (c < 0xF0) { /* Three-byte sequence */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); + if (c < 0x800) c = '?'; + } else { /* Reject four-byte sequence */ + c = '?'; + } + } + } +#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = s[1] + (s[0] << 8); +#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = s[0] + (s[1] << 8); +#else /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; + if (IsDBCS1(c)) { + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = (c << 8) + s[0]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif +#else /* Read a character without conversion */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; +#endif + if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */ + *p++ = c; + n++; + if (c == '\n') break; /* Break on EOL */ + } + *p = 0; + return n ? buff : 0; /* When no data read (eof or error), return with error. */ +} + + + +#if !_FS_READONLY +#include +/*-----------------------------------------------------------------------*/ +/* Put a character to the file */ +/*-----------------------------------------------------------------------*/ + +typedef struct { + FIL* fp; + int idx, nchr; + BYTE buf[64]; +} putbuff; + + +static +void putc_bfd ( + putbuff* pb, + TCHAR c +) +{ + UINT bw; + int i; + + + if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ + putc_bfd(pb, '\r'); + + i = pb->idx; /* Buffer write index (-1:error) */ + if (i < 0) return; + +#if _USE_LFN && _LFN_UNICODE +#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ + if (c < 0x80) { /* 7-bit */ + pb->buf[i++] = (BYTE)c; + } else { + if (c < 0x800) { /* 11-bit */ + pb->buf[i++] = (BYTE)(0xC0 | c >> 6); + } else { /* 16-bit */ + pb->buf[i++] = (BYTE)(0xE0 | c >> 12); + pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); + } +#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ + pb->buf[i++] = (BYTE)c; + pb->buf[i++] = (BYTE)(c >> 8); +#else /* Write a character in ANSI/OEM */ + c = ff_convert(c, 0); /* Unicode -> OEM */ + if (!c) c = '?'; + if (c >= 0x100) + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#endif +#else /* Write a character without conversion */ + pb->buf[i++] = (BYTE)c; +#endif + + if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ + f_write(pb->fp, pb->buf, (UINT)i, &bw); + i = (bw == (UINT)i) ? 0 : -1; + } + pb->idx = i; + pb->nchr++; +} + + + +int f_putc ( + TCHAR c, /* A character to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + UINT nw; + + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + putc_bfd(&pb, c); /* Put a character */ + + if ( pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK + && (UINT)pb.idx == nw) return pb.nchr; + return EOF; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a string to the file */ +/*-----------------------------------------------------------------------*/ + +int f_puts ( + const TCHAR* str, /* Pointer to the string to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + UINT nw; + + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + while (*str) /* Put the string */ + putc_bfd(&pb, *str++); + + if ( pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK + && (UINT)pb.idx == nw) return pb.nchr; + return EOF; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a formatted string to the file */ +/*-----------------------------------------------------------------------*/ + +int f_printf ( + FIL* fp, /* Pointer to the file object */ + const TCHAR* fmt, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + BYTE f, r; + UINT nw, i, j, w; + DWORD v; + TCHAR c, d, s[16], *p; + putbuff pb; + + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + va_start(arp, fmt); + + for (;;) { + c = *fmt++; + if (c == 0) break; /* End of string */ + if (c != '%') { /* Non escape character */ + putc_bfd(&pb, c); + continue; + } + w = f = 0; + c = *fmt++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *fmt++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; c = *fmt++; + } + } + while (IsDigit(c)) { /* Precision */ + w = w * 10 + c - '0'; + c = *fmt++; + } + if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ + f |= 4; c = *fmt++; + } + if (!c) break; + d = c; + if (IsLower(d)) d -= 0x20; + switch (d) { /* Type is... */ + case 'S' : /* String */ + p = va_arg(arp, TCHAR*); + for (j = 0; p[j]; j++) ; + if (!(f & 2)) { + while (j++ < w) putc_bfd(&pb, ' '); + } + while (*p) putc_bfd(&pb, *p++); + while (j++ < w) putc_bfd(&pb, ' '); + continue; + case 'C' : /* Character */ + putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 'B' : /* Binary */ + r = 2; break; + case 'O' : /* Octal */ + r = 8; break; + case 'D' : /* Signed decimal */ + case 'U' : /* Unsigned decimal */ + r = 10; break; + case 'X' : /* Hexdecimal */ + r = 16; break; + default: /* Unknown type (pass-through) */ + putc_bfd(&pb, c); continue; + } + + /* Get an argument and put it in numeral */ + v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); + if (d == 'D' && (v & 0x80000000)) { + v = 0 - v; + f |= 8; + } + i = 0; + do { + d = (TCHAR)(v % r); v /= r; + if (d > 9) d += (c == 'x') ? 0x27 : 0x07; + s[i++] = d + '0'; + } while (v && i < sizeof s / sizeof s[0]); + if (f & 8) s[i++] = '-'; + j = i; d = (f & 1) ? '0' : ' '; + while (!(f & 2) && j++ < w) putc_bfd(&pb, d); + do putc_bfd(&pb, s[--i]); while (i); + while (j++ < w) putc_bfd(&pb, d); + } + + va_end(arp); + + if ( pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK + && (UINT)pb.idx == nw) return pb.nchr; + return EOF; +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_STRFUNC */ diff --git a/firmware/ext/ff.h b/firmware/ext/ff.h index b1ff46527c..a93d9a2d4a 100644 --- a/firmware/ext/ff.h +++ b/firmware/ext/ff.h @@ -1,11 +1,11 @@ /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module include file R0.09 (C)ChaN, 2011 +/ FatFs - FAT file system module include file R0.10b (C)ChaN, 2014 /----------------------------------------------------------------------------/ / FatFs module is a generic FAT file system module for small embedded systems. / This is a free software that opened for education, research and commercial -/ developments under license policy of following trems. +/ developments under license policy of following terms. / -/ Copyright (C) 2011, ChaN, all right reserved. +/ Copyright (C) 2014, ChaN, all right reserved. / / * The FatFs module is a free software and there is NO WARRANTY. / * No restriction on use. You can use, modify and redistribute it for @@ -15,7 +15,7 @@ /----------------------------------------------------------------------------*/ #ifndef _FATFS -#define _FATFS 6502 /* Revision ID */ +#define _FATFS 8051 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -41,9 +41,9 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ -#else /* Single partition configuration */ -#define LD2PD(vol) (vol) /* Each logical drive is bound to the same physical drive number */ -#define LD2PT(vol) 0 /* Always mounts the 1st partition or in SFD */ +#else /* Single partition configuration */ +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif @@ -53,7 +53,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ #if _LFN_UNICODE /* Unicode string */ #if !_USE_LFN -#error _LFN_UNICODE must be 0 in non-LFN cfg. +#error _LFN_UNICODE must be 0 at non-LFN cfg. #endif #ifndef _INC_TCHAR typedef WCHAR TCHAR; @@ -78,12 +78,12 @@ typedef struct { BYTE fs_type; /* FAT sub-type (0:Not mounted) */ BYTE drv; /* Physical drive number */ BYTE csize; /* Sectors per cluster (1,2,4...128) */ - BYTE n_fats; /* Number of FAT copies (1,2) */ - BYTE wflag; /* win[] dirty flag (1:must be written back) */ - BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */ + BYTE n_fats; /* Number of FAT copies (1 or 2) */ + BYTE wflag; /* win[] flag (b0:dirty) */ + BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ -#if _MAX_SS != 512 +#if _MAX_SS != _MIN_SS WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ #endif #if _FS_REENTRANT @@ -92,18 +92,18 @@ typedef struct { #if !_FS_READONLY DWORD last_clust; /* Last allocated cluster */ DWORD free_clust; /* Number of free clusters */ - DWORD fsi_sector; /* fsinfo sector (FAT32) */ #endif #if _FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ #endif - DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */ + DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ DWORD fsize; /* Sectors per FAT */ + DWORD volbase; /* Volume start sector */ DWORD fatbase; /* FAT start sector */ DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ DWORD database; /* Data start sector */ DWORD winsect; /* Current sector appearing in the win[] */ - BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */ + BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -111,27 +111,27 @@ typedef struct { /* File object structure (FIL) */ typedef struct { - FATFS* fs; /* Pointer to the owner file system object */ - WORD id; /* Owner file system mount ID */ - BYTE flag; /* File status flags */ - BYTE pad1; - DWORD fptr; /* File read/write pointer (0 on file open) */ + FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ + WORD id; /* Owner file system mount ID (**do not change order**) */ + BYTE flag; /* Status flags */ + BYTE err; /* Abort flag (error code) */ + DWORD fptr; /* File read/write pointer (Zeroed on file open) */ DWORD fsize; /* File size */ - DWORD sclust; /* File start cluster (0 when fsize==0) */ - DWORD clust; /* Current cluster */ - DWORD dsect; /* Current data sector */ + DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ + DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ + DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ #if !_FS_READONLY - DWORD dir_sect; /* Sector containing the directory entry */ - BYTE* dir_ptr; /* Ponter to the directory entry in the window */ + DWORD dir_sect; /* Sector number containing the directory entry */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ #endif #if _USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */ + DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ #endif -#if _FS_SHARE - UINT lockid; /* File lock ID (index of file semaphore table) */ +#if _FS_LOCK + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif #if !_FS_TINY - BYTE buf[_MAX_SS]; /* File data read/write buffer */ + BYTE buf[_MAX_SS]; /* File private data read/write window */ #endif } FIL; @@ -140,14 +140,17 @@ typedef struct { /* Directory object structure (DIR) */ typedef struct { - FATFS* fs; /* Pointer to the owner file system object */ - WORD id; /* Owner file system mount ID */ + FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ + WORD id; /* Owner file system mount ID (**do not change order**) */ WORD index; /* Current read/write index number */ DWORD sclust; /* Table start cluster (0:Root dir) */ DWORD clust; /* Current cluster */ DWORD sect; /* Current sector */ BYTE* dir; /* Pointer to the current SFN entry in the win[] */ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ +#if _FS_LOCK + UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ +#endif #if _USE_LFN WCHAR* lfn; /* Pointer to the LFN working buffer */ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ @@ -176,14 +179,14 @@ typedef struct { typedef enum { FR_OK = 0, /* (0) Succeeded */ - FR_DISK_ERR, /* (1) A hard error occured in the low level disk I/O layer */ + FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ FR_INT_ERR, /* (2) Assertion failed */ FR_NOT_READY, /* (3) The physical drive cannot work */ FR_NO_FILE, /* (4) Could not find the file */ FR_NO_PATH, /* (5) Could not find the path */ FR_INVALID_NAME, /* (6) The path name format is invalid */ - FR_DENIED, /* (7) Acces denied due to prohibited access or directory full */ - FR_EXIST, /* (8) Acces denied due to prohibited access */ + FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to prohibited access */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ @@ -191,7 +194,7 @@ typedef enum { FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ - FR_LOCKED, /* (16) The operation is rejected according to the file shareing policy */ + FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ @@ -202,36 +205,39 @@ typedef enum { /*--------------------------------------------------------------*/ /* FatFs module application interface */ -FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ -FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */ -FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */ -FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */ -FRESULT f_close (FIL*); /* Close an open file object */ -FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */ -FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */ -FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */ -FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */ -FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */ -FRESULT f_truncate (FIL*); /* Truncate file */ -FRESULT f_sync (FIL*); /* Flush cached data of a writing file */ -FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */ -FRESULT f_mkdir (const TCHAR*); /* Create a new directory */ -FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */ -FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */ -FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */ -FRESULT f_chdrive (BYTE); /* Change current drive */ -FRESULT f_chdir (const TCHAR*); /* Change current directory */ -FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */ -FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */ -FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */ -FRESULT f_fdisk (BYTE, const DWORD[], void*); /* Divide a physical drive into some partitions */ -int f_putc (TCHAR, FIL*); /* Put a character to the file */ -int f_puts (const TCHAR*, FIL*); /* Put a string to the file */ -int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */ -TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */ +FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_close (FIL* fp); /* Close an open file object */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ +FRESULT f_truncate (FIL* fp); /* Truncate file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ +FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir (DIR* dp); /* Close an open directory */ +FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod (const TCHAR* path, BYTE value, BYTE mask); /* Change attribute of the file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ +FRESULT f_chdir (const TCHAR* path); /* Change current directory */ +FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ +FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ +FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ +int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ +int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ +int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ +TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ #define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0) -#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0) +#define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) #define f_size(fp) ((fp)->fsize) @@ -251,21 +257,21 @@ DWORD get_fattime (void); #endif /* Unicode support functions */ -#if _USE_LFN /* Unicode - OEM code conversion */ -WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */ -WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */ -#if _USE_LFN == 3 /* Memory functions */ -void* ff_memalloc (UINT); /* Allocate memory block */ -void ff_memfree (void*); /* Free memory block */ +#if _USE_LFN /* Unicode - OEM code conversion */ +WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ +WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ +#if _USE_LFN == 3 /* Memory functions */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ #endif #endif /* Sync functions */ #if _FS_REENTRANT -int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */ -int ff_req_grant (_SYNC_t); /* Lock sync object */ -void ff_rel_grant (_SYNC_t); /* Unlock sync object */ -int ff_del_syncobj (_SYNC_t); /* Delete a sync object */ +int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #endif @@ -279,7 +285,6 @@ int ff_del_syncobj (_SYNC_t); /* Delete a sync object */ #define FA_READ 0x01 #define FA_OPEN_EXISTING 0x00 -#define FA__ERROR 0x80 #if !_FS_READONLY #define FA_WRITE 0x02 diff --git a/firmware/ext/ffconf.h b/firmware/ext/ffconf.h index 0ba6d6ddf2..0f13b23297 100644 --- a/firmware/ext/ffconf.h +++ b/firmware/ext/ffconf.h @@ -2,41 +2,38 @@ #include "ch.h" /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.09 (C)ChaN, 2011 -/----------------------------------------------------------------------------/ -/ -/ CAUTION! Do not forget to make clean the project after any changes to -/ the configuration options. -/ -/----------------------------------------------------------------------------*/ +/ FatFs - FAT file system module configuration file R0.10b (C)ChaN, 2014 +/---------------------------------------------------------------------------*/ + #ifndef _FFCONF -#define _FFCONF 6502 /* Revision ID */ +#define _FFCONF 8051 /* Revision ID */ /*---------------------------------------------------------------------------/ / Functions and Buffer Configurations -/----------------------------------------------------------------------------*/ +/---------------------------------------------------------------------------*/ #define _FS_TINY 0 /* 0:Normal or 1:Tiny */ -/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system -/ object instead of the sector buffer in the individual file object for file -/ data transfer. This reduces memory consumption 512 bytes each file object. */ +/* When _FS_TINY is set to 1, it reduces memory consumption _MAX_SS bytes each +/ file object. For file data transfer, FatFs uses the common sector buffer in +/ the file system object (FATFS) instead of private sector buffer eliminated +/ from the file object (FIL). */ #define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ /* Setting _FS_READONLY to 1 defines read only configuration. This removes -/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, -/ f_truncate and useless f_getfree. */ +/ writing functions, f_write(), f_sync(), f_unlink(), f_mkdir(), f_chmod(), +/ f_rename(), f_truncate() and useless f_getfree(). */ #define _FS_MINIMIZE 0 /* 0 to 3 */ -/* The _FS_MINIMIZE option defines minimization level to remove some functions. +/* The _FS_MINIMIZE option defines minimization level to remove API functions. / -/ 0: Full function. -/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename -/ are removed. -/ 2: f_opendir and f_readdir are removed in addition to 1. -/ 3: f_lseek is removed in addition to 2. */ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), +/ f_truncate() and f_rename() function are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ #define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */ @@ -44,27 +41,30 @@ #define _USE_MKFS 0 /* 0:Disable or 1:Enable */ -/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */ - - -#define _USE_FORWARD 1 /* 0:Disable or 1:Enable */ -/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */ +/* To enable f_mkfs() function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */ #define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ /* To enable fast seek feature, set _USE_FASTSEEK to 1. */ +#define _USE_LABEL 0 /* 0:Disable or 1:Enable */ +/* To enable volume label functions, set _USE_LAVEL to 1 */ + + +#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ +/* To enable f_forward() function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */ + /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations -/----------------------------------------------------------------------------*/ +/---------------------------------------------------------------------------*/ #define _CODE_PAGE 1251 /* The _CODE_PAGE specifies the OEM code page to be used on the target system. / Incorrect setting of the code page can cause a file open failure. / -/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows) +/ 932 - Japanese Shift_JIS (DBCS, OEM, Windows) / 936 - Simplified Chinese GBK (DBCS, OEM, Windows) / 949 - Korean (DBCS, OEM, Windows) / 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) @@ -89,105 +89,142 @@ / 857 - Turkish (OEM) / 862 - Hebrew (OEM) / 874 - Thai (OEM, Windows) -/ 1 - ASCII only (Valid for non LFN cfg.) -*/ +/ 1 - ASCII (Valid for only non-LFN configuration) */ #define _USE_LFN 3 /* 0 to 3 */ #define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ -/* The _USE_LFN option switches the LFN support. +/* The _USE_LFN option switches the LFN feature. / -/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect. -/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant. +/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN, -/ Unicode handling functions ff_convert() and ff_wtoupper() must be added -/ to the project. When enable to use heap, memory control functions -/ ff_memalloc() and ff_memfree() must be added to the project. */ +/ When enable LFN feature, Unicode handling functions ff_convert() and ff_wtoupper() +/ function must be added to the project. +/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. When use stack for the +/ working buffer, take care on stack overflow. When use heap memory for the working +/ buffer, memory management functions, ff_memalloc() and ff_memfree(), must be added +/ to the project. */ #define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ -/* To switch the character code set on FatFs API to Unicode, -/ enable LFN feature and set _LFN_UNICODE to 1. */ +/* To switch the character encoding on the FatFs API (TCHAR) to Unicode, enable LFN +/ feature and set _LFN_UNICODE to 1. This option affects behavior of string I/O +/ functions. This option must be 0 when LFN feature is not enabled. */ + + +#define _STRF_ENCODE 3 /* 0:ANSI/OEM, 1:UTF-16LE, 2:UTF-16BE, 3:UTF-8 */ +/* When Unicode API is enabled by _LFN_UNICODE option, this option selects the character +/ encoding on the file to be read/written via string I/O functions, f_gets(), f_putc(), +/ f_puts and f_printf(). This option has no effect when Unicode API is not enabled. */ #define _FS_RPATH 0 /* 0 to 2 */ /* The _FS_RPATH option configures relative path feature. / / 0: Disable relative path feature and remove related functions. -/ 1: Enable relative path. f_chdrive() and f_chdir() are available. -/ 2: f_getcwd() is available in addition to 1. +/ 1: Enable relative path. f_chdrive() and f_chdir() function are available. +/ 2: f_getcwd() function is available in addition to 1. / -/ Note that output of the f_readdir fnction is affected by this option. */ - +/ Note that output of the f_readdir() fnction is affected by this option. */ /*---------------------------------------------------------------------------/ -/ Physical Drive Configurations -/----------------------------------------------------------------------------*/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ #define _VOLUMES 1 /* Number of volumes (logical drives) to be used. */ -#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ -/* Maximum sector size to be handled. -/ Always set 512 for memory card and hard disk but a larger value may be -/ required for on-board flash memory, floppy disk and optical disk. -/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size -/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */ +#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */ +#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +/* When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each logical +/ drives. Number of items must be equal to _VOLUMES. Valid characters for the drive ID +/ strings are: 0-9 and A-Z. */ -#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */ -/* When set to 0, each volume is bound to the same physical drive number and -/ it can mount only first primaly partition. When it is set to 1, each volume -/ is tied to the partitions listed in VolToPart[]. */ +#define _MULTI_PARTITION 0 /* 0:Single partition, 1:Enable multiple partition */ +/* By default(0), each logical drive number is bound to the same physical drive number +/ and only a FAT volume found on the physical drive is mounted. When it is set to 1, +/ each logical drive number is bound to arbitrary drive/partition listed in VolToPart[]. +*/ + + +#define _MIN_SS 512 +#define _MAX_SS 512 +/* These options configure the range of sector size to be supported. (512, 1024, 2048 or +/ 4096) Always set both 512 for most systems, all memory card and harddisk. But a larger +/ value may be required for on-board flash memory and some type of optical media. +/ When _MAX_SS is larger than _MIN_SS, FatFs is configured to variable sector size and +/ GET_SECTOR_SIZE command must be implemented to the disk_ioctl() function. */ #define _USE_ERASE 0 /* 0:Disable or 1:Enable */ -/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command -/ should be added to the disk_ioctl functio. */ +/* To enable sector erase feature, set _USE_ERASE to 1. Also CTRL_ERASE_SECTOR command +/ should be added to the disk_ioctl() function. */ + + +#define _FS_NOFSINFO 0 /* 0 to 3 */ +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this option +/ and f_getfree() function at first time after volume mount will force a full FAT scan. +/ Bit 1 controls the last allocated cluster number as bit 0. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ /*---------------------------------------------------------------------------/ / System Configurations -/----------------------------------------------------------------------------*/ +/---------------------------------------------------------------------------*/ -#define _WORD_ACCESS 0 /* 0 or 1 */ -/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS -/ option defines which access method is used to the word data on the FAT volume. +#define _FS_LOCK 0 /* 0:Disable or >=1:Enable */ +/* To enable file lock control feature, set _FS_LOCK to non-zero value. +/ The value defines how many files/sub-directories can be opened simultaneously +/ with file lock control. This feature uses bss _FS_LOCK * 12 bytes. */ + + +#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ +#define _FS_TIMEOUT MS2ST(1000) /* Timeout period in unit of time tick */ +#define _SYNC_t semaphore_t* /* O/S dependent sync object type. e.g. HANDLE, OS_EVENT*, ID, SemaphoreHandle_t and etc.. */ +/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs module. / -/ 0: Byte-by-byte access. -/ 1: Word access. Do not choose this unless following condition is met. -/ -/ When the byte order on the memory is big-endian or address miss-aligned word -/ access results incorrect behavior, the _WORD_ACCESS must be set to 0. -/ If it is not the case, the value can also be set to 1 to improve the -/ performance and code size. +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function must be added to the project. */ -/* A header file that defines sync object types on the O/S, such as -/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */ - -#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ -#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ -#define _SYNC_t Semaphore * /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */ - -/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module. +#define _WORD_ACCESS 0 /* 0 or 1 */ +/* The _WORD_ACCESS option is an only platform dependent option. It defines +/ which access method is used to the word data on the FAT volume. / -/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect. -/ 1: Enable reentrancy. Also user provided synchronization handlers, -/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj -/ function must be added to the project. */ +/ 0: Byte-by-byte access. Always compatible with all platforms. +/ 1: Word access. Do not choose this unless under both the following conditions. +/ +/ * Address misaligned memory access is always allowed for ALL instructions. +/ * Byte order on the memory is little-endian. +/ +/ If it is the case, _WORD_ACCESS can also be set to 1 to improve performance and +/ reduce code size. Following table shows an example of some processor types. +/ +/ ARM7TDMI 0 ColdFire 0 V850E2 0 +/ Cortex-M3 0 Z80 0/1 V850ES 0/1 +/ Cortex-M0 0 RX600(LE) 0/1 TLCS-870 0/1 +/ AVR 0/1 RX600(BE) 0 TLCS-900 0/1 +/ AVR32 0 RL78 0 R32C 0 +/ PIC18 0/1 SH-2 0 M16C 0/1 +/ PIC24 0 H8S 0 MSP430 0 +/ PIC32 0 H8/300H 0 x86 0/1 +*/ -#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */ -/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value - defines how many files can be opened simultaneously. */ - - -#endif /* _FFCONFIG */ +#endif /* _FFCONF */ diff --git a/firmware/ext/ffconf_old.h b/firmware/ext/ffconf_old.h new file mode 100644 index 0000000000..0ba6d6ddf2 --- /dev/null +++ b/firmware/ext/ffconf_old.h @@ -0,0 +1,193 @@ +/* CHIBIOS FIX */ +#include "ch.h" + +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file R0.09 (C)ChaN, 2011 +/----------------------------------------------------------------------------/ +/ +/ CAUTION! Do not forget to make clean the project after any changes to +/ the configuration options. +/ +/----------------------------------------------------------------------------*/ +#ifndef _FFCONF +#define _FFCONF 6502 /* Revision ID */ + + +/*---------------------------------------------------------------------------/ +/ Functions and Buffer Configurations +/----------------------------------------------------------------------------*/ + +#define _FS_TINY 0 /* 0:Normal or 1:Tiny */ +/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system +/ object instead of the sector buffer in the individual file object for file +/ data transfer. This reduces memory consumption 512 bytes each file object. */ + + +#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ +/* Setting _FS_READONLY to 1 defines read only configuration. This removes +/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, +/ f_truncate and useless f_getfree. */ + + +#define _FS_MINIMIZE 0 /* 0 to 3 */ +/* The _FS_MINIMIZE option defines minimization level to remove some functions. +/ +/ 0: Full function. +/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename +/ are removed. +/ 2: f_opendir and f_readdir are removed in addition to 1. +/ 3: f_lseek is removed in addition to 2. */ + + +#define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */ +/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ + + +#define _USE_MKFS 0 /* 0:Disable or 1:Enable */ +/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */ + + +#define _USE_FORWARD 1 /* 0:Disable or 1:Enable */ +/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */ + + +#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ +/* To enable fast seek feature, set _USE_FASTSEEK to 1. */ + + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/----------------------------------------------------------------------------*/ + +#define _CODE_PAGE 1251 +/* The _CODE_PAGE specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows) +/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows) +/ 949 - Korean (DBCS, OEM, Windows) +/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) +/ 1250 - Central Europe (Windows) +/ 1251 - Cyrillic (Windows) +/ 1252 - Latin 1 (Windows) +/ 1253 - Greek (Windows) +/ 1254 - Turkish (Windows) +/ 1255 - Hebrew (Windows) +/ 1256 - Arabic (Windows) +/ 1257 - Baltic (Windows) +/ 1258 - Vietnam (OEM, Windows) +/ 437 - U.S. (OEM) +/ 720 - Arabic (OEM) +/ 737 - Greek (OEM) +/ 775 - Baltic (OEM) +/ 850 - Multilingual Latin 1 (OEM) +/ 858 - Multilingual Latin 1 + Euro (OEM) +/ 852 - Latin 2 (OEM) +/ 855 - Cyrillic (OEM) +/ 866 - Russian (OEM) +/ 857 - Turkish (OEM) +/ 862 - Hebrew (OEM) +/ 874 - Thai (OEM, Windows) +/ 1 - ASCII only (Valid for non LFN cfg.) +*/ + + +#define _USE_LFN 3 /* 0 to 3 */ +#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ +/* The _USE_LFN option switches the LFN support. +/ +/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN, +/ Unicode handling functions ff_convert() and ff_wtoupper() must be added +/ to the project. When enable to use heap, memory control functions +/ ff_memalloc() and ff_memfree() must be added to the project. */ + + +#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ +/* To switch the character code set on FatFs API to Unicode, +/ enable LFN feature and set _LFN_UNICODE to 1. */ + + +#define _FS_RPATH 0 /* 0 to 2 */ +/* The _FS_RPATH option configures relative path feature. +/ +/ 0: Disable relative path feature and remove related functions. +/ 1: Enable relative path. f_chdrive() and f_chdir() are available. +/ 2: f_getcwd() is available in addition to 1. +/ +/ Note that output of the f_readdir fnction is affected by this option. */ + + + +/*---------------------------------------------------------------------------/ +/ Physical Drive Configurations +/----------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + + +#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ +/* Maximum sector size to be handled. +/ Always set 512 for memory card and hard disk but a larger value may be +/ required for on-board flash memory, floppy disk and optical disk. +/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size +/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */ + + +#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */ +/* When set to 0, each volume is bound to the same physical drive number and +/ it can mount only first primaly partition. When it is set to 1, each volume +/ is tied to the partitions listed in VolToPart[]. */ + + +#define _USE_ERASE 0 /* 0:Disable or 1:Enable */ +/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command +/ should be added to the disk_ioctl functio. */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/----------------------------------------------------------------------------*/ + +#define _WORD_ACCESS 0 /* 0 or 1 */ +/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS +/ option defines which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. +/ 1: Word access. Do not choose this unless following condition is met. +/ +/ When the byte order on the memory is big-endian or address miss-aligned word +/ access results incorrect behavior, the _WORD_ACCESS must be set to 0. +/ If it is not the case, the value can also be set to 1 to improve the +/ performance and code size. +*/ + + +/* A header file that defines sync object types on the O/S, such as +/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */ + +#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ +#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ +#define _SYNC_t Semaphore * /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */ + +/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module. +/ +/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect. +/ 1: Enable reentrancy. Also user provided synchronization handlers, +/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj +/ function must be added to the project. */ + + +#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */ +/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value + defines how many files can be opened simultaneously. */ + + +#endif /* _FFCONFIG */ diff --git a/firmware/ext/option/ccsbcs.c b/firmware/ext/option/ccsbcs.c new file mode 100644 index 0000000000..8aa71b29f0 --- /dev/null +++ b/firmware/ext/option/ccsbcs.c @@ -0,0 +1,540 @@ +/*------------------------------------------------------------------------*/ +/* Unicode - Local code bidirectional converter (C)ChaN, 2012 */ +/* (SBCS code pages) */ +/*------------------------------------------------------------------------*/ +/* 437 U.S. (OEM) +/ 720 Arabic (OEM) +/ 1256 Arabic (Windows) +/ 737 Greek (OEM) +/ 1253 Greek (Windows) +/ 1250 Central Europe (Windows) +/ 775 Baltic (OEM) +/ 1257 Baltic (Windows) +/ 850 Multilingual Latin 1 (OEM) +/ 852 Latin 2 (OEM) +/ 1252 Latin 1 (Windows) +/ 855 Cyrillic (OEM) +/ 1251 Cyrillic (Windows) +/ 866 Russian (OEM) +/ 857 Turkish (OEM) +/ 1254 Turkish (Windows) +/ 858 Multilingual Latin 1 + Euro (OEM) +/ 862 Hebrew (OEM) +/ 1255 Hebrew (Windows) +/ 874 Thai (OEM, Windows) +/ 1258 Vietnam (OEM, Windows) +*/ + +#include "../ff.h" + + +#if _CODE_PAGE == 437 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 720 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, + 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, + 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 737 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, + 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, + 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, + 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, + 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 775 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, + 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, + 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, + 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, + 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, + 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, + 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 850 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 852 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, + 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, + 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, + 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, + 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, + 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 855 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, + 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, + 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, + 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, + 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, + 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, + 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, + 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 857 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, + 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 858 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP858(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 862 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 866 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 874 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP874(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +#elif _CODE_PAGE == 1250 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1250(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 +}; + +#elif _CODE_PAGE == 1251 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1251(0x80-0xFF) to Unicode conversion table */ + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F +}; + +#elif _CODE_PAGE == 1252 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1252(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF +}; + +#elif _CODE_PAGE == 1253 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1253(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 +}; + +#elif _CODE_PAGE == 1254 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1254(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF +}; + +#elif _CODE_PAGE == 1255 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1255(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000 +}; + +#elif _CODE_PAGE == 1256 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1256(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2 +} + +#elif _CODE_PAGE == 1257 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1257(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9 +}; + +#elif _CODE_PAGE == 1258 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1258(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF +}; + +#endif + + +#if !_TBLDEF || !_USE_LFN +#error This file is not needed in current configuration. Remove from the project. +#endif + + +WCHAR ff_convert ( /* Converted character, Returns zero on error */ + WCHAR chr, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */ +) +{ + WCHAR c; + + + if (chr < 0x80) { /* ASCII */ + c = chr; + + } else { + if (dir) { /* OEMCP to Unicode */ + c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; + + } else { /* Unicode to OEMCP */ + for (c = 0; c < 0x80; c++) { + if (chr == Tbl[c]) break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + + +WCHAR ff_wtoupper ( /* Upper converted character */ + WCHAR chr /* Input character */ +) +{ + static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 }; + static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 }; + int i; + + + for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ; + + return tbl_lower[i] ? tbl_upper[i] : chr; +} diff --git a/firmware/ext/readme.txt b/firmware/ext/readme.txt index fa761829a5..e76920959f 100644 --- a/firmware/ext/readme.txt +++ b/firmware/ext/readme.txt @@ -1 +1,158 @@ -In this folder we have 3rd party code \ No newline at end of file +FatFs Module Source Files R0.10b (C)ChaN, 2014 + + +FILES + + ffconf.h Configuration file for FatFs module. + ff.h Common include file for FatFs and application module. + ff.c FatFs module. + diskio.h Common include file for FatFs and disk I/O module. + diskio.c An example of glue function to attach existing disk I/O module to FatFs. + integer.h Integer type definitions for FatFs. + option Optional external functions. + + Low level disk I/O module is not included in this archive because the FatFs + module is only a generic file system layer and not depend on any specific + storage device. You have to provide a low level disk I/O module that written + to control your storage device. + + + +AGREEMENTS + + FatFs module is an open source software to implement FAT file system to + small embedded systems. This is a free software and is opened for education, + research and commercial developments under license policy of following trems. + + Copyright (C) 2014, ChaN, all right reserved. + + * The FatFs module is a free software and there is NO WARRANTY. + * No restriction on use. You can use, modify and redistribute it for + personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY. + * Redistributions of source code must retain the above copyright notice. + + + +REVISION HISTORY + + Feb 26, 2006 R0.00 Prototype + + Apr 29, 2006 R0.01 First release. + + Jun 01, 2006 R0.02 Added FAT12. + Removed unbuffered mode. + Fixed a problem on small (<32M) patition. + + Jun 10, 2006 R0.02a Added a configuration option _FS_MINIMUM. + + Sep 22, 2006 R0.03 Added f_rename. + Changed option _FS_MINIMUM to _FS_MINIMIZE. + + Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast. + Fixed f_mkdir creates incorrect directory on FAT32. + + Feb 04, 2007 R0.04 Supported multiple drive system. (FatFs) + Changed some APIs for multiple drive system. + Added f_mkfs. (FatFs) + Added _USE_FAT32 option. (Tiny-FatFs) + + Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. (FatFs) + Fixed an endian sensitive code in f_mkfs. (FatFs) + Added a capability of extending the file size to f_lseek. + Added minimization level 3. + Fixed a problem that can collapse a sector when recreate an + existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs) + + May 05, 2007 R0.04b Added _USE_NTFLAG option. + Added FSInfo support. + Fixed some problems corresponds to FAT32. (Tiny-FatFs) + Fixed DBCS name can result FR_INVALID_NAME. + Fixed short seek (0 < ofs <= csize) collapses the file object. + + Aug 25, 2007 R0.05 Changed arguments of f_read, f_write. + Changed arguments of f_mkfs. (FatFs) + Fixed f_mkfs on FAT32 creates incorrect FSInfo. (FatFs) + Fixed f_mkdir on FAT32 creates incorrect directory. (FatFs) + + Feb 03, 2008 R0.05a Added f_truncate(). + Added f_utime(). + Fixed off by one error at FAT sub-type determination. + Fixed btr in f_read() can be mistruncated. + Fixed cached sector is not flushed when create and close without write. + + Apr 01, 2008 R0.06 Added f_forward(). (Tiny-FatFs) + Added string functions: fputc(), fputs(), fprintf() and fgets(). + Improved performance of f_lseek() on move to the same or following cluster. + + Apr 01, 2009, R0.07 Merged Tiny-FatFs as a buffer configuration option. + Added long file name support. + Added multiple code page support. + Added re-entrancy for multitask operation. + Added auto cluster size selection to f_mkfs(). + Added rewind option to f_readdir(). + Changed result code of critical errors. + Renamed string functions to avoid name collision. + + Apr 14, 2009, R0.07a Separated out OS dependent code on reentrant cfg. + Added multiple sector size support. + + Jun 21, 2009, R0.07c Fixed f_unlink() may return FR_OK on error. + Fixed wrong cache control in f_lseek(). + Added relative path feature. + Added f_chdir(). + Added f_chdrive(). + Added proper case conversion for extended characters. + + Nov 03, 2009 R0.07e Separated out configuration options from ff.h to ffconf.h. + Added a configuration option, _LFN_UNICODE. + Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH. + Fixed name matching error on the 13 char boundary. + Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. + + May 15, 2010, R0.08 Added a memory configuration option. (_USE_LFN) + Added file lock feature. (_FS_SHARE) + Added fast seek feature. (_USE_FASTSEEK) + Changed some types on the API, XCHAR->TCHAR. + Changed fname member in the FILINFO structure on Unicode cfg. + String functions support UTF-8 encoding files on Unicode cfg. + + Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2) + Added sector erase feature. (_USE_ERASE) + Moved file lock semaphore table from fs object to the bss. + Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'. + Fixed f_mkfs() creates wrong FAT32 volume. + + Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write(). + f_lseek() reports required table size on creating CLMP. + Extended format syntax of f_printf function. + Ignores duplicated directory separators in given path names. + + Sep 06,'11 R0.09 f_mkfs() supports multiple partition to finish the multiple partition feature. + Added f_fdisk(). (_MULTI_PARTITION = 2) + + Aug 27,'12 R0.09a Fixed assertion failure due to OS/2 EA on FAT12/16. + Changed f_open() and f_opendir() reject null object pointer to avoid crash. + Changed option name _FS_SHARE to _FS_LOCK. + + Jan 23,'13 R0.09b Added f_getlabel() and f_setlabel(). (_USE_LABEL) + + Oct 02,'13 R0.10 Added selection of character encoding on the file. (_STRF_ENCODE) + Added f_closedir(). + Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) + Added forced mount feature with changes of f_mount(). + Improved behavior of volume auto detection. + Improved write throughput of f_puts() and f_printf(). + Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). + Fixed f_write() can be truncated when the file size is close to 4GB. + Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. + + Jan 15,'14 R0.10a Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) + Added a configuration option of minimum sector size. (_MIN_SS) + 2nd argument of f_rename() can have a drive number and it will be ignored. + Fixed f_mount() with forced mount fails when drive number is >= 1. + Fixed f_close() invalidates the file object without volume lock. + Fixed f_closedir() returns but the volume lock is left acquired. + Fixed creation of an entry with LFN fails on too many SFN collisions. + + Mar 19,'14 R0.10b Fixed a hard error in the disk I/O layer can collapse the directory entry. + Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. diff --git a/firmware/global.h b/firmware/global.h index 53746e1cbe..3bb60a41a1 100644 --- a/firmware/global.h +++ b/firmware/global.h @@ -15,6 +15,7 @@ extern "C" #include #include + #include #define DEFAULT_ENGINE_TYPE CUSTOM_ENGINE @@ -53,31 +54,13 @@ typedef unsigned int time_t; #define EFI_ERROR_CODE 0xffffffff #if EFI_USE_CCM && defined __GNUC__ -#define CCM_OPTIONAL __attribute__((section(".ccm"))) +#define CCM_OPTIONAL __attribute__((section(".ram4"))) #elif defined __GNUC__ #define CCM_OPTIONAL #else -#define CCM_OPTIONAL @ ".ccm" +#define CCM_OPTIONAL @ ".ram4" #endif -// this stuff is about ChibiOS 2.6 > Migration -typedef VirtualTimer virtual_timer_t; -typedef EventListener event_listener_t; -typedef Thread thread_t; -typedef EventListener event_listener_t; -typedef EventSource event_source_t; -typedef VTList virtual_timers_list_t; -typedef VirtualTimer virtual_timer_t; -#define chSysLockFromISR chSysLockFromIsr -#define chSysUnlockFromISR chSysUnlockFromIsr -#define chThdGetSelfX chThdSelf - -#define HAL_SUCCESS CH_SUCCESS -#define HAL_FAILED CH_FAILED - -#define THD_WORKING_AREA WORKING_AREA -#define THD_FUNCTION(tname, arg) void tname(void *arg) - #if EFI_PROD_CODE || defined(__DOXYGEN__) /** @@ -133,6 +116,10 @@ typedef VirtualTimer virtual_timer_t; turnAllPinsOff(); \ enginePins.communicationPin.setValue(1); +/* + * Stack debugging + */ +int getRemainingStack(thread_t *otp); #ifdef __cplusplus } diff --git a/firmware/hw_layer/HIP9011.cpp b/firmware/hw_layer/HIP9011.cpp index 45564009cf..b302ee10f7 100644 --- a/firmware/hw_layer/HIP9011.cpp +++ b/firmware/hw_layer/HIP9011.cpp @@ -194,7 +194,7 @@ void setHip9011FrankensoPinout(void) { // todo: convert this to rusEfi, hardware-independent enum engineConfiguration->spi2SckMode = PAL_STM32_OTYPE_OPENDRAIN; // 4 engineConfiguration->spi2MosiMode = PAL_STM32_OTYPE_OPENDRAIN; // 4 - engineConfiguration->spi2MisoMode = PAL_STM32_PUDR_PULLUP; // 32 + engineConfiguration->spi2MisoMode = PAL_STM32_PUPDR_PULLUP; // 32 boardConfiguration->hip9011Gain = 1; engineConfiguration->knockVThreshold = 4; diff --git a/firmware/hw_layer/adc_inputs.cpp b/firmware/hw_layer/adc_inputs.cpp index b40f997514..6eca52b992 100644 --- a/firmware/hw_layer/adc_inputs.cpp +++ b/firmware/hw_layer/adc_inputs.cpp @@ -582,12 +582,15 @@ void initAdcInputs(bool boardTestMode) { slowAdc.init(); pwmStart(EFI_INTERNAL_SLOW_ADC_PWM, &pwmcfg_slow); + pwmEnablePeriodicNotification(EFI_INTERNAL_SLOW_ADC_PWM); + if (boardConfiguration->isFastAdcEnabled) { fastAdc.init(); /* * Initializes the PWM driver. */ pwmStart(EFI_INTERNAL_FAST_ADC_PWM, &pwmcfg_fast); + pwmEnablePeriodicNotification(EFI_INTERNAL_FAST_ADC_PWM); } // ADC_CHANNEL_IN0 // PA0 diff --git a/firmware/hw_layer/can_hw.cpp b/firmware/hw_layer/can_hw.cpp index fa8c419ca6..4bef1731d4 100644 --- a/firmware/hw_layer/can_hw.cpp +++ b/firmware/hw_layer/can_hw.cpp @@ -94,7 +94,7 @@ void sendMessage2(int size) { txmsg.DLC = size; // 1 second timeout msg_t result = canTransmit(&EFI_CAN_DEVICE, CAN_ANY_MAILBOX, &txmsg, MS2ST(1000)); - if (result == RDY_OK) { + if (result == MSG_OK) { canWriteOk++; } else { canWriteNotOk++; @@ -201,7 +201,7 @@ static void canInfoNBCBroadcast(can_nbc_e typeOfNBC) { static void canRead(void) { // scheduleMsg(&logger, "Waiting for CAN"); msg_t result = canReceive(&EFI_CAN_DEVICE, CAN_ANY_MAILBOX, &rxBuffer, MS2ST(1000)); - if (result == RDY_TIMEOUT) { + if (result == MSG_TIMEOUT) { return; } @@ -304,8 +304,8 @@ void initCan(void) { #else canStart(&CAND1, &canConfig); #endif - - canStart(&EFI_CAN_DEVICE, &canConfig); + // FIXME: Can't start a driver twice. + //canStart(&EFI_CAN_DEVICE, &canConfig); #if EFI_PROD_CODE || defined(__DOXYGEN__) chThdCreateStatic(canTreadStack, sizeof(canTreadStack), NORMALPRIO, (tfunc_t) canThread, NULL); diff --git a/firmware/hw_layer/digital_input_hw.cpp b/firmware/hw_layer/digital_input_hw.cpp index 20ed738b2b..7e75f14c05 100644 --- a/firmware/hw_layer/digital_input_hw.cpp +++ b/firmware/hw_layer/digital_input_hw.cpp @@ -199,12 +199,12 @@ void startInputDriver(digital_input_s *hw, bool isActiveHigh) { if (driver != NULL) { if (hw->started) { - icuDisable(driver); + icuDisableNotificationsI(driver); icuStop(driver); } wave_icucfg.channel = getInputCaptureChannel(hw->brainPin); efiIcuStart(driver, &wave_icucfg); - icuEnable(driver); + icuEnableNotifications(driver); } hw->started = true; } diff --git a/firmware/hw_layer/hardware.cpp b/firmware/hw_layer/hardware.cpp index 1e5ffbcd22..590db05471 100644 --- a/firmware/hw_layer/hardware.cpp +++ b/firmware/hw_layer/hardware.cpp @@ -54,7 +54,7 @@ EXTERN_ENGINE ; extern bool hasFirmwareErrorFlag; -static Mutex spiMtx; +static mutex_t spiMtx; int maxNesting = 0; @@ -70,13 +70,13 @@ bool rtcWorks = true; * Only one consumer can use SPI bus at a given time */ void lockSpi(spi_device_e device) { - efiAssertVoid(getRemainingStack(chThdSelf()) > 128, "lockSpi"); + efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 128, "lockSpi"); // todo: different locks for different SPI devices! chMtxLock(&spiMtx); } void unlockSpi(void) { - chMtxUnlock(); + chMtxUnlock(&spiMtx); } static void initSpiModules(board_configuration_s *boardConfiguration) { @@ -155,7 +155,7 @@ extern int tpsFastAdc; * This method is not in the adc* lower-level file because it is more business logic then hardware. */ void adc_callback_fast(ADCDriver *adcp, adcsample_t *buffer, size_t n) { - efiAssertVoid(getRemainingStack(chThdSelf()) > 64, "lowstck12a"); + efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 64, "lowstck12a"); (void) buffer; (void) n; @@ -167,7 +167,7 @@ void adc_callback_fast(ADCDriver *adcp, adcsample_t *buffer, size_t n) { /** * this callback is executed 10 000 times a second, it needs to be as fast as possible */ - efiAssertVoid(getRemainingStack(chThdSelf()) > 128, "lowstck#9b"); + efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 128, "lowstck#9b"); #if EFI_MAP_AVERAGING mapAveragingCallback(fastAdc.samples[fastMapSampleIndex]); @@ -305,7 +305,7 @@ void showBor(void) { } void initHardware(Logging *l) { - efiAssertVoid(getRemainingStack(chThdSelf()) > 256, "init h"); + efiAssertVoid(getRemainingStack(chThdGetSelfX()) > 256, "init h"); sharedLogger = l; engine_configuration_s *engineConfiguration = engine->engineConfiguration; efiAssertVoid(engineConfiguration!=NULL, "engineConfiguration"); @@ -316,7 +316,7 @@ void initHardware(Logging *l) { // 10 extra seconds to re-flash the chip //flashProtect(); - chMtxInit(&spiMtx); + chMtxObjectInit(&spiMtx); #if EFI_HISTOGRAMS /** diff --git a/firmware/hw_layer/mass_storage/mass_storage.mk b/firmware/hw_layer/mass_storage/mass_storage.mk index f03524cc56..cfebe5a517 100644 --- a/firmware/hw_layer/mass_storage/mass_storage.mk +++ b/firmware/hw_layer/mass_storage/mass_storage.mk @@ -1,2 +1,2 @@ -HW_MASS_STORAGE_SRC_C = $(PROJECT_DIR)/hw_layer/mass_storage/usb_msd.c \ No newline at end of file +HW_MASS_STORAGE_SRC_C = $(PROJECT_DIR)/hw_layer/mass_storage/usb_msd_cfg.c diff --git a/firmware/hw_layer/mass_storage/usb_msd.c b/firmware/hw_layer/mass_storage/usb_msd.c deleted file mode 100644 index 026fc77421..0000000000 --- a/firmware/hw_layer/mass_storage/usb_msd.c +++ /dev/null @@ -1,1412 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, - 2011,2012,2013 Giovanni Di Sirio. - - This file is part of ChibiOS/RT. - - ChibiOS/RT 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 3 of the License, or - (at your option) any later version. - - ChibiOS/RT 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 . -*/ - -/** - * @file usb_msd.c - * @brief USB Mass Storage Driver code. - * - * @addtogroup MSD_USB - * @{ - */ - -#define HAL_USE_MASS_STORAGE_USB true - -#include "ch.h" -#include "hal.h" -#include "usb_msd.h" -#include "chprintf.h" -#include "string.h" - - -#if HAL_USE_MASS_STORAGE_USB || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#define MSD_ENABLE_PERF_DEBUG_GPIOS FALSE -#define MSD_DEBUG_NESTING FALSE -#define MSD_DEBUG FALSE -//#define MSD_DEBUG (palReadPad(GPIOI, GPIOI_PIN4)) - -#define msd_debug_print(chp_arg, args ...) if (MSD_DEBUG && chp_arg != NULL ) { chprintf(chp_arg, args); } -#define msd_debug_nest_print(chp_arg, args ...) if ( MSD_DEBUG_NESTING && chp_arg != NULL ) { chprintf(chp_arg, args); } -#define msd_debug_err_print(chp_arg, args ...) if ( chp_arg != NULL ) { chprintf(chp_arg, args); } - - - - - -//#define MSD_DEBUG_SCSI_COMMAND_STATE_STRING(description) g_debug_info.msd.scsi_command_state = description; - -#if !defined(MSD_RW_LED_ON) -#define MSD_RW_LED_ON() -#endif - -#if !defined(MSD_RW_LED_OFF) -#define MSD_RW_LED_OFF() -#endif - -#if !defined(MSD_R_LED_ON) -#define MSD_R_LED_ON() -#endif - -#if !defined(MSD_R_LED_OFF) -#define MSD_R_LED_OFF() -#endif - -#if !defined(MSD_W_LED_ON) -#define MSD_W_LED_ON() -#endif - -#if !defined(MSD_W_LED_OFF) -#define MSD_W_LED_OFF() -#endif - - - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - - - -static msg_t MassStorageUSBTransferThd(void *arg); -static msg_t MassStorageThd(void *arg); - -static Thread *msdThd = NULL; -static Thread *msdUSBTransferThd = NULL; - -#define WAIT_ISR_SUCCESS 0 -#define WAIT_ISR_BUSS_RESET_OR_RECONNECT 1 - -static uint8_t msdWaitForISR(USBMassStorageDriver *msdp, const bool_t check_reset, const msd_wait_mode_t wait_mode); -static void msdSetDefaultSenseKey(USBMassStorageDriver *msdp); - -#define BLOCK_SIZE_INCREMENT 512 -#define BLOCK_WRITE_ITTERATION_COUNT 16 - -#define MSD_START_TRANSMIT(msdp) \ - chSysLock(); \ - msdp->bulk_in_interupt_flag = false; \ - usbStartTransmitI(msdp->usbp, msdp->ms_ep_number); \ - chSysUnlock(); - - -#define MSD_START_RECEIVED(msdp) \ - chSysLock(); \ - msdp->bulk_out_interupt_flag = false; \ - usbStartReceiveI(msdp->usbp, msdp->ms_ep_number); \ - chSysUnlock(); - -typedef enum { - MSD_USB_TRANSFER_STATUS_RUNNING = 0, - MSD_USB_TRANSFER_STATUS_DONE_SUCCESSFUL, - MSD_USB_TRANSFER_STATUS_DONE_FAILED, -} msd_usb_transfer_status_t; - -typedef struct { - //uint8_t is_transfer_done; - msd_usb_transfer_status_t transfer_status; - /*Number of blocks actually read from USB IN endpoint that should be written to SD card*/ - int num_blocks_to_write; - /*Number of blocks to read from USB IN endpoint*/ - int max_blocks_to_read; - uint8_t buf[(BLOCK_SIZE_INCREMENT * BLOCK_WRITE_ITTERATION_COUNT)]; -} rw_usb_sd_buffer_t; - -static volatile rw_usb_sd_buffer_t rw_ping_pong_buffer[2]; -static uint8_t read_buffer[2][BLOCK_SIZE_INCREMENT]; - - -inline uint32_t swap_uint32( uint32_t val ) { - val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); - return ((val << 16) & 0xFFFF0000) | ((val >> 16) & 0x0000FFFF); -} - -#define swap_uint16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) - -inline uint32_t swap_4byte_buffer(uint8_t *buff) { - //Note: this is specifically to avoid pointer aliasing and de-referencing words on non-word boundaries - uint32_t temp = 0; - memcpy(&temp, buff, sizeof(temp)); - return(swap_uint32(temp)); -} - -inline uint16_t swap_2byte_buffer(uint8_t *buff) { - //Note: this is specifically to avoid pointer aliasing and de-referencing words on non-half-word boundaries - uint16_t temp = 0; - memcpy(&temp, buff, sizeof(temp)); - return(swap_uint16(temp)); -} - -/** - * @brief USB Event handler calback - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep USB Endpoint Number - * - * @api - */ -void msdBulkInCallbackComplete(USBDriver *usbp, usbep_t ep) { - (void)usbp; - (void)ep; - - if (ep > 0 && usbp->in_params[ep - 1] != NULL) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->in_params[ep - 1]; - - chSysLockFromIsr(); - chBSemSignalI(&(msdp->bsem)); - - msdp->bulk_in_interupt_flag = true; - - - chSysUnlockFromIsr(); - } -} - -/** - * @brief USB Event handler calback - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] ep USB Endpoint Number - * - * @api - */ -void msdBulkOutCallbackComplete(USBDriver *usbp, usbep_t ep) { - (void)usbp; - (void)ep; - - if (ep > 0 && usbp->in_params[ep - 1] != NULL) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->in_params[ep - 1]; - - chSysLockFromIsr(); - chBSemSignalI(&(msdp->bsem)); - - msdp->bulk_out_interupt_flag = true; - - chSysUnlockFromIsr(); - } -} - - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - - -/** - * @brief This function will initialize a USBMassStorageDriver structure. - * - * @pre Upon entry, the BlockDevice state should be BLK_READY. If it's not BLK_READY, then this will - * wait untile it becomes BLK_READY. - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] bbdp pointer to the @p BaseBlockDevice object, such as an SDCDriver object - * @param[in] msdp pointer to the @p USBMassStorageDriver object - * @param[in] ms_ep_number USB Endpoint Number to be used by the mass storage endpoint - * - * @init - */ -usb_msd_driver_state_t msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp, - const usbep_t ms_ep_number, const uint16_t msd_interface_number) { - - msdp->usbp = usbp; - msdp->driver_state = USB_MSD_DRIVER_OK; - msdp->state = MSD_STATE_IDLE; - msdp->trigger_transfer_index = UINT32_MAX; - msdp->bbdp = bbdp; - msdp->ms_ep_number = ms_ep_number; - msdp->msd_interface_number = msd_interface_number; - msdp->chp = NULL; - msdp->enable_media_removial = true; - msdp->block_dev_info_valid_flag = false; - - chEvtInit(&msdp->evt_connected); - chEvtInit(&msdp->evt_ejected); - - /* Initialize binary semaphore as taken, will cause the thread to initially - * wait on the */ - chBSemInit(&msdp->bsem, TRUE); - /* Initialize binary semaphore as NOT taken */ - chBSemInit(&msdp->usb_transfer_thread_bsem, FALSE); - chBSemInit(&msdp->mass_sorage_thd_bsem, FALSE); - - /* Initialize sense structure to zero */ - memset(&msdp->sense, 0, sizeof(msdp->sense)); - - /* Response code = 0x70, additional sense length = 0x0A */ - msdp->sense.byte[0] = 0x70;//FIXME use #define, what is this??? - msdp->sense.byte[7] = 0x0A;//FIXME use #define, what is this??? - - /* make sure block device is working and get info */ - msdSetDefaultSenseKey(msdp); - - const uint32_t sleep_ms = 50; - uint32_t t; - for(t = 0; t <= 250 && (blkGetDriverState(bbdp) != BLK_READY); t += sleep_ms ) { - chThdSleepMilliseconds(sleep_ms); - } - - if( blkGetDriverState(bbdp) == BLK_READY ) { - blkGetInfo(bbdp, &msdp->block_dev_info); - msdp->block_dev_info_valid_flag = true; - } else { - //msdp->driver_state = USB_MSD_DRIVER_ERROR_BLK_DEV_NOT_READY; - } - - usbp->in_params[ms_ep_number - 1] = (void *)msdp; - - return(msdp->driver_state); -} - -/** - * @brief Starts data handling threads for USB mass storage driver - * - * @param[in] msdp pointer to the @p USBMassStorageDriver object - * - * @api - */ -usb_msd_driver_state_t msdStart(USBMassStorageDriver *msdp) { - /*upon entry, USB bus should be disconnected*/ - - if (msdThd == NULL ) { - msdThd = chThdCreateStatic(msdp->waMassStorage, sizeof(msdp->waMassStorage), NORMALPRIO, - MassStorageThd, msdp); - } - - if (msdUSBTransferThd == NULL ) { - msdUSBTransferThd = chThdCreateStatic(msdp->waMassStorageUSBTransfer, - sizeof(msdp->waMassStorageUSBTransfer), - NORMALPRIO, MassStorageUSBTransferThd, - msdp); - } - - return(msdp->driver_state); -} - -usb_msd_driver_state_t msdStop(USBMassStorageDriver *msdp) { - usb_msd_driver_state_t final_state = USB_MSD_DRIVER_STOPPED; - - if (msdThd != NULL) { - chThdTerminate(msdThd); - int i; - for(i = 0; i < 20 && msdThd->p_state != THD_STATE_FINAL; i++ ) { - chThdSleepMilliseconds(20); - } - - if( msdThd->p_state == THD_STATE_FINAL ) { - final_state = USB_MSD_DRIVER_ERROR; - } - msdThd = NULL; - } - - - if (msdUSBTransferThd == NULL) { - chThdTerminate(msdUSBTransferThd); - int i; - for(i = 0; i < 20 && msdUSBTransferThd->p_state != THD_STATE_FINAL; i++ ) { - chThdSleepMilliseconds(20); - } - - if( msdUSBTransferThd->p_state == THD_STATE_FINAL ) { - final_state = USB_MSD_DRIVER_ERROR; - } - msdUSBTransferThd = NULL; - } - - - msdp->driver_state = final_state; - return(msdp->driver_state); -} - - -/** - * @brief Default requests hook. - * - * @param[in] usbp pointer to the @p USBDriver object - * @return The hook status. - * @retval TRUE Message handled internally. - * @retval FALSE Message not handled. - * - * @api - */ -bool_t msdRequestsHook(USBDriver *usbp) { - return(msdRequestsHook2(usbp, NULL)); -} - -/** - * @brief Alternate request hook, useful for USB composite devices - * - * @param[in] usbp pointer to the @p USBDriver object - * @param[in] msdp pointer to the @p USBMassStorageDriver object - * @return The hook status. - * @retval TRUE Message handled internally. - * @retval FALSE Message not handled. - * - * @api - */ -bool_t msdRequestsHook2(USBDriver *usbp, USBMassStorageDriver *msdp) { - if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) - && ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) - == USB_RTYPE_RECIPIENT_INTERFACE)) { - /* check that the request is for the MSD interface number.*/ - if( msdp != NULL ) { - if (MSD_SETUP_INDEX(usbp->setup) != msdp->msd_interface_number) - return FALSE; - } else if (MSD_SETUP_INDEX(usbp->setup) != 0 ) { - return FALSE; - } - - /* act depending on bRequest = setup[1] */ - switch (usbp->setup[1]) { - case MSD_REQ_RESET: - /* check that it is a HOST2DEV request */ - if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) - || (MSD_SETUP_LENGTH(usbp->setup) != 0) - || (MSD_SETUP_VALUE(usbp->setup) != 0)) - return FALSE; - - /* reset all endpoints */ - /* TODO!*/ - /* The device shall NAK the status stage of the device request until - * the Bulk-Only Mass Storage Reset is complete. - */ - return TRUE; - case MSD_GET_MAX_LUN: - /* check that it is a DEV2HOST request */ - if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) - || (MSD_SETUP_LENGTH(usbp->setup) != 1) - || (MSD_SETUP_VALUE(usbp->setup) != 0)) - return FALSE; - - //static uint8_t len_buf[1] = {0}; - msdp->data.max_lun_len_buf[0] = 0; - usbSetupTransfer(usbp, msdp->data.max_lun_len_buf, 1, NULL); - return TRUE; - default: - return FALSE; - break; - } - } - return FALSE; -} - - -const char* usb_msd_driver_state_t_to_str(const usb_msd_driver_state_t driver_state) { - switch (driver_state) { - case USB_MSD_DRIVER_UNINITIALIZED: - return ("USB_MSD_DRIVER_UNINITIALIZED"); - case USB_MSD_DRIVER_ERROR: - return ("USB_MSD_DRIVER_ERROR"); - case USB_MSD_DRIVER_OK: - return ("USB_MSD_DRIVER_OK"); - case USB_MSD_DRIVER_STOPPED: - return("USB_MSD_DRIVER_STOPPED"); - case USB_MSD_DRIVER_ERROR_BLK_DEV_NOT_READY: - return ("USB_MSD_DRIVER_ERROR_BLK_DEV_NOT_READY"); - } - return ("USB_MSD_DRIVER_UNKNOWN"); -} - - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - - -/* Event Flow Functions */ - - -static uint8_t msdWaitForISR(USBMassStorageDriver *msdp, const bool_t check_reset, const msd_wait_mode_t wait_mode) { - uint8_t ret = WAIT_ISR_SUCCESS; - /* sleep until the ISR completes */ - chSysLock(); - msd_debug_print(msdp->chp, "WaitISR(mode=%d)\r\n", wait_mode); - for (;;) { - const msg_t m = chBSemWaitTimeoutS(&msdp->bsem, 1); - if (m == RDY_OK && wait_mode == MSD_WAIT_MODE_NONE ) { - break; - } - - if( wait_mode == MSD_WAIT_MODE_BULK_IN && msdp->bulk_in_interupt_flag ) { - break; - } else if( wait_mode == MSD_WAIT_MODE_BULK_OUT && msdp->bulk_out_interupt_flag ) { - break; - } - - if (check_reset && msdp->reconfigured_or_reset_event) { - ret = WAIT_ISR_BUSS_RESET_OR_RECONNECT; - break; - } - - if( chThdShouldTerminate() ) { - break; - } - } - chSysUnlock(); - return (ret); -} - - -static void WaitForUSBTransferComplete(USBMassStorageDriver *msdp, - const int ping_pong_buffer_index) { - msd_debug_nest_print(msdp->chp, "A"); - while (TRUE) { - chBSemWaitTimeout(&msdp->mass_sorage_thd_bsem, MS2ST(1)); - - if (rw_ping_pong_buffer[ping_pong_buffer_index].transfer_status != MSD_USB_TRANSFER_STATUS_RUNNING) { - break; - } else { - //chThdSleepMilliseconds(1); - } - } - msd_debug_nest_print(msdp->chp, "a"); -} - - - -/* SCSI Functions */ - -static inline void SCSISetSense(USBMassStorageDriver *msdp, uint8_t key, - uint8_t acode, uint8_t aqual) { - msdp->sense.byte[2] = key; - msdp->sense.byte[12] = acode; - msdp->sense.byte[13] = aqual; -} - - -static void msdSetDefaultSenseKey(USBMassStorageDriver *msdp) { - SCSISetSense(msdp, SCSI_SENSE_KEY_GOOD, - SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, - SCSI_ASENSEQ_NO_QUALIFIER); -} - - -#ifndef USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_0 -# define USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_0 "Chibios" -#endif - -#ifndef USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_1 -# define USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_1 "Mass Storage" -#endif - -#ifndef USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_2 -# define USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_2 {'v', CH_KERNEL_MAJOR + '0', '.', CH_KERNEL_MINOR + '0'} -#endif - -static const scsi_inquiry_response_t default_scsi_inquiry_response = - {0x00, /* peripheral, direct access block device */ - 0x80, /* removable */ - 0x04, /* version, SPC-2 */ - 0x02, /* response data format */ - 0x20, /* additional_length, response has 0x20 + 4 bytes */ - 0x00, /* sccstp*/ - 0x00, /* bqueetc*/ - 0x00, /* cmdqueue*/ - USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_0, - USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_1, - USB_MASS_STORAGE_INQUIRY_RESPONSE_STRING_2, - }; - - -static msd_wait_mode_t SCSICommandInquiry(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - msdp->data.scsi_inquiry_response = default_scsi_inquiry_response; - - if ((cbw->scsi_cmd_data[1] & ((1 << 0) | (1 << 1))) || cbw->scsi_cmd_data[2]) { - /* Optional but unsupported bits set - update the SENSE key and fail - * the request */ - msd_debug_err_print(msdp->chp, " INQ ERR 0x%X 0x%X\r\n", cbw->scsi_cmd_data[1], cbw->scsi_cmd_data[2]); - SCSISetSense(msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); - - //we should indicate that the command failed to the host, but still return data - msdp->command_succeeded_flag = false; - } - - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, (uint8_t *)&msdp->data.scsi_inquiry_response, - sizeof(scsi_inquiry_response_t)); - - - MSD_START_TRANSMIT(msdp); - - /* wait for ISR */ - return MSD_WAIT_MODE_BULK_IN; -} - -static msd_wait_mode_t SCSICommandRequestSense(USBMassStorageDriver *msdp) { - //This command should not affect the sense key - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, (uint8_t *)&msdp->sense, - sizeof(scsi_sense_response_t)); - - MSD_START_TRANSMIT(msdp); - - /* wait for ISR */ - return MSD_WAIT_MODE_BULK_IN; -} - -static msd_wait_mode_t SCSICommandReadFormatCapacity(USBMassStorageDriver *msdp) { - msdSetDefaultSenseKey(msdp); - - const uint32_t formated_capactiy_descriptor_code = 0x02;//see usbmass-ufi10.doc for codes - - msdp->data.format_capacity_response.payload_byte_length[3] = 8; - msdp->data.format_capacity_response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num - 1); - msdp->data.format_capacity_response.block_size = swap_uint32(msdp->block_dev_info.blk_size) | formated_capactiy_descriptor_code; - - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, (uint8_t *)&msdp->data.format_capacity_response, - sizeof(msdp->data.format_capacity_response)); - - MSD_START_TRANSMIT(msdp); - - /* wait for ISR */ - return MSD_WAIT_MODE_BULK_IN; -} - -static msd_wait_mode_t SCSICommandReadCapacity10(USBMassStorageDriver *msdp) { - msdSetDefaultSenseKey(msdp); - - msdp->data.read_capacity10_response.block_size = swap_uint32(msdp->block_dev_info.blk_size); - msdp->data.read_capacity10_response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num - 1); - - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, (uint8_t *)&msdp->data.read_capacity10_response, - sizeof(msdp->data.read_capacity10_response)); - - MSD_START_TRANSMIT(msdp); - - /* wait for ISR */ - return MSD_WAIT_MODE_BULK_IN; -} - -static msd_wait_mode_t SCSICommandSendDiagnostic(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - - if ((!cbw->scsi_cmd_data[1]) & (1 << 2)) { - /* Only self-test supported - update SENSE key and fail the command */ - SCSISetSense(msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); - - msdp->command_succeeded_flag = false; - return MSD_WAIT_MODE_NONE; - } - - /* TODO: actually perform the test */ - - /* don't wait for ISR */ - return MSD_WAIT_MODE_NONE; -} - -static void SCSIWriteTransferPingPong(USBMassStorageDriver *msdp, - volatile rw_usb_sd_buffer_t *dest_buffer) { - msd_debug_nest_print(msdp->chp, "B"); - int cnt; - dest_buffer->transfer_status = MSD_USB_TRANSFER_STATUS_RUNNING; - dest_buffer->num_blocks_to_write = 0; - -#if MSD_ENABLE_PERF_DEBUG_GPIOS - palSetPad(GPIOH, GPIOH_LED2); -#endif - - for (cnt = 0; - cnt < BLOCK_WRITE_ITTERATION_COUNT - && cnt < dest_buffer->max_blocks_to_read; cnt++) { - - msdp->transfer_thread_state = "RX-Prep"; - usbPrepareReceive(msdp->usbp, msdp->ms_ep_number, - (uint8_t*)&dest_buffer->buf[cnt * BLOCK_SIZE_INCREMENT], - (msdp->block_dev_info.blk_size)); - - msdp->transfer_thread_state = "RX"; - MSD_START_RECEIVED(msdp); - - msdp->transfer_thread_state = "RX-Wait"; - msdWaitForISR(msdp, FALSE, MSD_WAIT_MODE_BULK_OUT); - - dest_buffer->num_blocks_to_write++; - } - dest_buffer->transfer_status = MSD_USB_TRANSFER_STATUS_DONE_SUCCESSFUL; - msdp->transfer_thread_state = "RX-Done"; - //FIXME we need to handle setting the status to error if something failed, like a usb reset or something - -#if MSD_ENABLE_PERF_DEBUG_GPIOS - palClearPad(GPIOH, GPIOH_LED2); -#endif - - msd_debug_nest_print(msdp->chp, "b"); -} - - -static msd_wait_mode_t SCSICommandStartReadWrite10(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - int read_success; - int retry_count; - - msdSetDefaultSenseKey(msdp); - - if ((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->bbdp)) { - msd_debug_err_print(msdp->chp, "\r\nWrite Protected!\r\n"); - /* device is write protected and a write has been issued */ - /* Block address is invalid, update SENSE key and return command fail */ - SCSISetSense(msdp, SCSI_SENSE_KEY_NOT_READY, SCSI_ASENSE_WRITE_PROTECTED, - SCSI_ASENSEQ_NO_QUALIFIER); - - msdp->command_succeeded_flag = false; - msdp->stall_in_endpoint = true; - return MSD_WAIT_MODE_NONE; - } - - //FIXME, which of these? - //uint32_t rw_block_address = swap_4byte_buffer(&cbw->scsi_cmd_data[2]); - //const uint16_t total_blocks = swap_2byte_buffer(&cbw->scsi_cmd_data[7]); - uint32_t rw_block_address = swap_uint32(*(uint32_t *)&cbw->scsi_cmd_data[2]); - const uint16_t total_blocks = swap_uint16(*(uint16_t *)&cbw->scsi_cmd_data[7]); - const uint32_t rw_block_address_origional = rw_block_address; - uint16_t i = 0; - - if (rw_block_address >= msdp->block_dev_info.blk_num) { - msd_debug_err_print(msdp->chp, "\r\nBlock Address too large %u > %u\r\n", rw_block_address, msdp->block_dev_info.blk_num); - /* Block address is invalid, update SENSE key and return command fail */ - SCSISetSense(msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, - SCSI_ASENSEQ_NO_QUALIFIER); - - msdp->command_succeeded_flag = false; - msdp->stall_in_endpoint = true; - - /* don't wait for ISR */ - return MSD_WAIT_MODE_NONE; - } - - /*initialized ping pong buffer*/ - for (i = 0; i < 2; i++) { - rw_ping_pong_buffer[i].max_blocks_to_read = 0; - rw_ping_pong_buffer[i].num_blocks_to_write = 0; - rw_ping_pong_buffer[i].transfer_status = MSD_USB_TRANSFER_STATUS_RUNNING; - } - - msd_debug_nest_print(msdp->chp, "\r\nG"); - if (cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) { - /* loop over each block */ - - uint32_t ping_pong_buffer_index = 0; - /*initiate a transfer*/ - rw_ping_pong_buffer[ping_pong_buffer_index].transfer_status = MSD_USB_TRANSFER_STATUS_RUNNING; - rw_ping_pong_buffer[ping_pong_buffer_index].max_blocks_to_read = total_blocks; - - /*Trigger the transfer in the other thread*/ - msdp->trigger_transfer_index = ping_pong_buffer_index; - - /*wake other thread on semaphore to trigger the transfer*/ - chBSemSignal(&msdp->usb_transfer_thread_bsem); - - WaitForUSBTransferComplete(msdp, ping_pong_buffer_index); - - for (i = 0; i < total_blocks;) { - const int done_buffer_index = ping_pong_buffer_index; - const int empty_buffer_index = ((ping_pong_buffer_index + 1) % 2); - - /*initiate another transfer in the other ping pong buffer*/ - //const bool_t queue_another_transfer = ((i + BLOCK_WRITE_ITTERATION_COUNT) < total_blocks); - const bool_t queue_another_transfer = ((i + rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write) < total_blocks); - - msd_debug_nest_print(msdp->chp, "D"); - if (queue_another_transfer) { - while (TRUE) { - if (msdp->trigger_transfer_index == UINT32_MAX) { - rw_ping_pong_buffer[empty_buffer_index].max_blocks_to_read = - total_blocks - i - rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write; - - msdp->trigger_transfer_index = empty_buffer_index; - - /*wake other thread on semaphore to trigger the transfer*/ - chBSemSignal(&msdp->usb_transfer_thread_bsem); - break; - } else { - chThdSleepMilliseconds(1); - } - } - } - msd_debug_nest_print(msdp->chp, "d"); - - if (rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write <= 0) { - /*This should never happen!!! Something is seriously wrong!*/ - msd_debug_err_print( - msdp->chp, "\r\nCant write 0 blocks, this should not happen, halting\r\n"); - chThdSleepMilliseconds(50); - chSysHalt(); - } - - /* now write the block to the block device */ - MSD_W_LED_ON(); - msd_debug_nest_print(msdp->chp, "E"); - if (blkWrite(msdp->bbdp, rw_block_address, - (uint8_t*)rw_ping_pong_buffer[done_buffer_index].buf, - rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write) - == CH_FAILED) { - msd_debug_err_print(msdp->chp, "\r\nSD Block Write Error\r\n"); - chThdSleepMilliseconds(50); - msdp->write_error_count++; - - msdp->command_succeeded_flag = false; - - SCSISetSense(msdp, SCSI_SENSE_KEY_MEDIUM_ERROR, - SCSI_ASENSE_PEREPHERIAL_DEVICE_WRITE_FAULT, - SCSI_ASENSEQ_PEREPHERIAL_DEVICE_WRITE_FAULT); - - -#define OLD_WRITE_ERROR_HANDLING FALSE -#if OLD_WRITE_ERROR_HANDLING - /* - * I think that this mode of error handling is incorrect, and was causing ACM0 usb device resets in the event of EMMC write errors. - * I confirmed using the Beagle USB 480 analyzer that the host gets a failed staus, and retries the write to the given error block, at which point the block write succeeds for thist test case. - * This code should be purged at some point - */ - msdp->stall_out_endpoint = true; - - if (queue_another_transfer) { - /*Let the previous queued transfer finish and ignore it.*/ - WaitForUSBTransferComplete(msdp, empty_buffer_index); - } - - MSD_W_LED_OFF(); - return (MSD_WAIT_MODE_NONE); -#endif - } else { - msdp->write_success_count++; - } - msd_debug_nest_print(msdp->chp, "e"); - MSD_W_LED_OFF(); - - rw_block_address += rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write; - i += rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write; - rw_ping_pong_buffer[done_buffer_index].transfer_status = MSD_USB_TRANSFER_STATUS_RUNNING; - rw_ping_pong_buffer[done_buffer_index].num_blocks_to_write = 0; - - msd_debug_nest_print(msdp->chp, "F"); - if (queue_another_transfer) { - if( !( i< total_blocks) ) { - msd_debug_err_print(msdp->chp, "\r\nERROR: Queued another transfer but not going to rx the data\r\n"); - } - WaitForUSBTransferComplete(msdp, empty_buffer_index); - } - msd_debug_nest_print(msdp->chp, "f"); - - /*Swap the ping pong buffers*/ - ping_pong_buffer_index = empty_buffer_index; - } - - if( i != total_blocks ) { - msd_debug_err_print(msdp->chp, "\r\ni!=total_blocks, %u, %u\r\n", i, total_blocks); - } - - msd_debug_nest_print(msdp->chp, "(%u,%u,%u)", rw_block_address_origional, total_blocks, i); - - } else { - /* FIXME: For some reason, when doing a blkRead on a SanDisk 8g sd card, it takes 2.5ms to read a block, limiting - * max read performance to about 200k/s. However, when using an 8g transcend SD card, we can get up to 2.0 megabytes/sec - * read through put. What's the difference? configuration for the SD driver? - */ - - i = 0; - /* read the first block from block device */ - read_success = FALSE; - for (retry_count = 0; retry_count < 3; retry_count++) { - if (blkRead(msdp->bbdp, rw_block_address, read_buffer[i % 2], 1) - == CH_FAILED) { - msd_debug_err_print(msdp->chp, "\r\nSD Block Read Error: block # %u\r\n", rw_block_address); - msdp->read_error_count++; - } else { - msdp->read_success_count++; - if( retry_count > 0 ) { - msd_debug_err_print(msdp->chp, "Successful Block Read Retry\r\n"); - } - read_success = TRUE; - break; - } - } - - - if ((!read_success) ) { - msd_debug_err_print(msdp->chp, "\r\nSD Block Read Error 1, breaking read sequence, block # %u\r\n", rw_block_address); - - /*wait for printing to finish*/ - chThdSleepMilliseconds(10); - - msdp->command_succeeded_flag = false; - msdp->stall_in_endpoint = true; - - msd_debug_err_print( - msdp->chp, "\r\nSetting sense code %u\r\n", SCSI_SENSE_KEY_MEDIUM_ERROR); - - SCSISetSense(msdp, SCSI_SENSE_KEY_MEDIUM_ERROR, - SCSI_ASENSE_UNRECOVERED_READ_ERROR, - SCSI_ASENSEQ_NO_QUALIFIER); - - return MSD_WAIT_MODE_NONE; - } - - rw_block_address++; - - /* loop over each block */ - for (i = 0; i < total_blocks; i++) { - - /* transmit the block */ - //while (usbGetTransmitStatusI(msdp->usbp, msdp->ms_ep_number)) { - //wait for the prior transmit to complete - //} - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, read_buffer[i % 2], - msdp->block_dev_info.blk_size); - - MSD_START_TRANSMIT(msdp); - - if (i < (total_blocks - 1)) { - /* there is at least one more block to be read from device */ - /* so read that while the USB transfer takes place */ - read_success = FALSE; - MSD_R_LED_ON(); - for (retry_count = 0; retry_count < 3; retry_count++) { - if (blkRead(msdp->bbdp, rw_block_address, read_buffer[(i+1) % 2], 1) - == CH_FAILED) { - msd_debug_err_print(msdp->chp, "\r\nSD Block Read Error 2: block # %u\r\n", rw_block_address); - - msdp->read_error_count++; - } else { - if( retry_count > 0 ) { - msd_debug_err_print(msdp->chp, "Successful Block Read Retry: block # %u\r\n", rw_block_address); - } - read_success = TRUE; - msdp->read_success_count++; - break; - } - } - MSD_R_LED_OFF(); - - if( !read_success ) { - msd_debug_err_print( - msdp->chp, "\r\nSD Block Read Error 22, addr=%d, halting\r\n", rw_block_address); - - /*wait for printing to finish*/ - chThdSleepMilliseconds(70); - - msdp->command_succeeded_flag = false; - msdp->stall_in_endpoint = true; - - msd_debug_err_print( - msdp->chp, "\r\nSetting sense code %u\r\n", SCSI_SENSE_KEY_MEDIUM_ERROR); - - SCSISetSense(msdp, SCSI_SENSE_KEY_MEDIUM_ERROR, - SCSI_ASENSE_UNRECOVERED_READ_ERROR, - SCSI_ASENSEQ_NO_QUALIFIER); - return MSD_WAIT_MODE_NONE; - } - - rw_block_address++; - } - - /*FIXME In the event that the USB connection is unplugged while we're waiting for a bulk - * endpoint ISR, this will never return, and when re-plugged into the host, the drive will - * not show back up on the host. We need a way to break out of this loop when disconnected from the bus. - */ - - if (msdWaitForISR(msdp, TRUE, MSD_WAIT_MODE_BULK_IN) == WAIT_ISR_BUSS_RESET_OR_RECONNECT) { - //fixme are we handling the reset case properly - return MSD_WAIT_MODE_NONE; - } - } - } - msd_debug_nest_print(msdp->chp, "g"); - - /* don't wait for ISR */ - return MSD_WAIT_MODE_NONE; -} - -static msd_wait_mode_t SCSICommandStartStopUnit(USBMassStorageDriver *msdp) { - scsi_start_stop_unit_request_t *ssu = - (scsi_start_stop_unit_request_t *)&(msdp->cbw.scsi_cmd_data); - - if ((ssu->loej_start & 0x3) == 2) { - /* device has been ejected */ - if (!msdp->disable_usb_bus_disconnect_on_eject) { - chEvtBroadcast(&msdp->evt_ejected); - msdp->state = MSD_STATE_EJECTED; - } - } - - /* don't wait for ISR */ - return MSD_WAIT_MODE_NONE; -} - -static msd_wait_mode_t SCSICommandPreventAllowMediumRemovial(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - - if( (cbw->scsi_cmd_data[4] & 0x01) ) { - //prohibit media removal - if( msdp->enable_media_removial ) { - //this can have positive performance - msdp->command_succeeded_flag = false; - SCSISetSense(msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_COMMAND, SCSI_ASENSEQ_NO_QUALIFIER); - } - } - - /* don't wait for ISR */ - return MSD_WAIT_MODE_NONE; -} - - - -static msd_wait_mode_t SCSICommandModeSense6(USBMassStorageDriver *msdp) { - //FIXME check for unsupported mode page set sense code, see page 161(144) of USB Mass storage book - memset(&msdp->data.mode_sense6_response, 0, sizeof(msdp->data.mode_sense6_response)); - msdp->data.mode_sense6_response.mode_data_length = 3; - if( blkIsWriteProtected(msdp->bbdp) ) { - msdp->data.mode_sense6_response.device_specifc_paramters |= (1<<7); - } - - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, (uint8_t*)&msdp->data.mode_sense6_response, 4); - - MSD_START_TRANSMIT(msdp); - - /* wait for ISR */ - return MSD_WAIT_MODE_BULK_IN; -} - -static msd_wait_mode_t msdWaitForCommandBlock(USBMassStorageDriver *msdp) { - usbPrepareReceive(msdp->usbp, msdp->ms_ep_number, (uint8_t *)&msdp->cbw, - sizeof(msd_cbw_t)); - - MSD_START_RECEIVED(msdp); - - msdp->state = MSD_STATE_READ_CMD_BLOCK; - - return(MSD_WAIT_MODE_BULK_OUT);/* wait for ISR */ -} - -/* */ -/** - * @brief A command block has been received - - * - * @param[in] p1 description of parameter one - * @param[out] p2 description of parameter two - * @param[in,out] p3 description of parameter three - * @return Description of the returned value, must be omitted if - * a function returns void. - * @retval TRUE On success - * @retval FALSE On failure - * - */ -static msd_wait_mode_t msdProcessCommandBlock(USBMassStorageDriver *msdp) { - msd_cbw_t *cbw = &(msdp->cbw); - - /* by default transition back to the idle state */ - msdp->state = MSD_STATE_IDLE; - - msd_debug_print(msdp->chp, " CMD 0x%X\r\n", cbw->scsi_cmd_data[0]); - msdp->command_succeeded_flag = true; - msdp->stall_in_endpoint = false; - msdp->stall_out_endpoint = false; - msd_wait_mode_t wait_mode = MSD_WAIT_MODE_NONE; - - - /* check the command */ - if ((cbw->signature != MSD_CBW_SIGNATURE) || (cbw->lun > 0) - || ((cbw->data_len > 0) && (cbw->flags & 0x1F)) - || (cbw->scsi_cmd_len == 0) || (cbw->scsi_cmd_len > 16)) - { - - msdp->scsi_command_state = "Bad CBW"; - msd_debug_err_print(msdp->chp, "Bad CBW, sig=0x%X, lun=0x%X, data_len=0x%X, flags=0x%X, scsi_cmd_len=0x%X\r\n", cbw->signature, cbw->lun, cbw->data_len, cbw->flags, cbw->scsi_cmd_len); - /* stall both IN and OUT endpoints */ - msdp->stall_out_endpoint = true; - msdp->stall_in_endpoint = true; - msdp->command_succeeded_flag = false; - SCSISetSense(msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); - -#if 0 - chSysLock(); - msdp->bulk_out_interupt_flag = false; - usbStallReceiveI(msdp->usbp, msdp->ms_ep_number); - //usbStallTransmitI(msdp->usbp, msdp->ms_ep_number); - chSysUnlock(); - - //wait for the host to clear the stall - msdWaitForISR(msdp, TRUE, MSD_WAIT_MODE_BULK_OUT); - - /* don't wait for ISR */ - return MSD_WAIT_MODE_NONE; -#endif - } - - - if( msdp->command_succeeded_flag ) { - switch ( (msd_scsi_command_t) cbw->scsi_cmd_data[0] ) { - case SCSI_CMD_INQUIRY: - msdp->scsi_command_state = "CMD_INQ"; - msd_debug_print(msdp->chp, "CMD_INQ\r\n"); - wait_mode = SCSICommandInquiry(msdp); - msdp->scsi_command_state = "CMD_INQ-Done"; - break; - case SCSI_CMD_REQUEST_SENSE_6: - msdp->scsi_command_state = "CMD_RS"; - msd_debug_print(msdp->chp, "\r\nCMD_RS\r\n"); - wait_mode = SCSICommandRequestSense(msdp); - msdp->scsi_command_state = "CMD_RS-Done"; - break; - case SCSI_CMD_READ_FORMAT_CAPACITY: - msdp->scsi_command_state = "CMD_RFC"; - msd_debug_print(msdp->chp, "CMD_RFC\r\n"); - wait_mode = SCSICommandReadFormatCapacity(msdp); - msdp->scsi_command_state = "CMD_RFC-Done"; - break; - case SCSI_CMD_READ_CAPACITY_10: - msdp->scsi_command_state = "CMD_RC10"; - msd_debug_print(msdp->chp, "CMD_RC10\r\n"); - wait_mode = SCSICommandReadCapacity10(msdp); - msdp->scsi_command_state = "CMD_RC10-Done"; - break; - case SCSI_CMD_READ_10: - case SCSI_CMD_WRITE_10: - msdp->scsi_command_state = "CMD_RW"; - msd_debug_print(msdp->chp, "CMD_RW\r\n"); - MSD_RW_LED_ON(); - wait_mode = SCSICommandStartReadWrite10(msdp); - MSD_RW_LED_OFF(); - msdp->scsi_command_state = "CMD_RW-Done"; - break; - case SCSI_CMD_SEND_DIAGNOSTIC: - msdp->scsi_command_state = "CMD_DIA"; - msd_debug_print(msdp->chp, "CMD_DIA\r\n"); - wait_mode = SCSICommandSendDiagnostic(msdp); - msdp->scsi_command_state = "CMD_DIA-Done"; - break; - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - msdp->scsi_command_state = "CMD_PAMR"; - msd_debug_print(msdp->chp, "CMD_PAMR\r\n"); - wait_mode = SCSICommandPreventAllowMediumRemovial(msdp); - msdp->scsi_command_state = "CMD_PAMR-Done"; - break; - case SCSI_CMD_TEST_UNIT_READY: - case SCSI_CMD_VERIFY_10: - msdp->scsi_command_state = "CMD_00_1E_2F"; - msd_debug_print(msdp->chp, "CMD_00_1E_2F\r\n"); - msdp->scsi_command_state = "CMD_00_1E_2F-Done"; - /* don't handle */ - break; - case SCSI_CMD_MODE_SENSE_6: - msdp->scsi_command_state = "CMD_S6"; - msd_debug_print(msdp->chp, "\r\nCMD_S6\r\n"); - wait_mode = SCSICommandModeSense6(msdp); - msdp->scsi_command_state = "CMD_S6-Done"; - break; - case SCSI_CMD_START_STOP_UNIT: - msdp->scsi_command_state = "CMD_STOP"; - msd_debug_print(msdp->chp, "CMD_STOP\r\n"); - wait_mode = SCSICommandStartStopUnit(msdp); - msdp->scsi_command_state = "CMD_STOP-Done"; - break; - case SCSI_CMD_SYNCHRONIZE_CACHE_10: - msdp->scsi_command_state = "SYNC_10"; - msd_debug_print(msdp->chp, "SYNC_10\r\n"); - //FIXME impliment this and flush data to the MMC card, Linux sends this command. We are implicitly synchronized - //in our writes since we never leave data in RAM - - SCSISetSense(msdp, SCSI_SENSE_KEY_GOOD, - SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); - wait_mode = MSD_WAIT_MODE_NONE; - - msdp->scsi_command_state = "SYNC_10-Done"; - break; - default: - msdp->last_bad_scsi_command = cbw->scsi_cmd_data[0]; - - msdp->scsi_command_state = "CMD_Def"; - msd_debug_err_print(msdp->chp, "CMD Unknown: 0x%X, using default CMD handler\r\n", cbw->scsi_cmd_data[0]); - msdp->command_succeeded_flag = false; - SCSISetSense(msdp, SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_INVALID_COMMAND, SCSI_ASENSEQ_NO_QUALIFIER); - -#if 0 - /* stall IN endpoint */ - chSysLock() - msdp->bulk_in_interupt_flag = false; - usbStallTransmitI(msdp->usbp, msdp->ms_ep_number); - chSysUnlock() - - msdWaitForISR(msdp, TRUE, MSD_WAIT_MODE_BULK_IN); -#else - //msdp->stall_out_endpoint = true; - //msdp->stall_in_endpoint = true; -#endif - - msdp->scsi_command_state = "CMD_Def-Done"; - cbw->data_len = 0; -#if 0 - return MSD_WAIT_MODE_NONE; -#endif - } - } - - cbw->data_len = 0; - - - if( msdp->stall_in_endpoint || msdp->stall_out_endpoint ) { - msdp->scsi_command_state = "Stall"; - /* stall IN endpoint */ - chSysLock(); - if( msdp->stall_in_endpoint ) { - msd_debug_err_print(msdp->chp, "stalling IN endpoint\r\n"); - msdp->bulk_in_interupt_flag = false; - usbStallTransmitI(msdp->usbp, msdp->ms_ep_number); - } - if( msdp->stall_out_endpoint ) { - msd_debug_err_print(msdp->chp, "stalling OUT endpoint\r\n"); - msdp->bulk_out_interupt_flag = false; - usbStallReceiveI(msdp->usbp, msdp->ms_ep_number); - } - chSysUnlock(); - - if( msdp->stall_in_endpoint ) { - msdWaitForISR(msdp, TRUE, MSD_WAIT_MODE_BULK_IN); - } - - if( msdp->stall_out_endpoint ) { - msdWaitForISR(msdp, TRUE, MSD_WAIT_MODE_BULK_OUT); - } - } - - msdp->scsi_command_state = "Wait"; - - if (wait_mode != MSD_WAIT_MODE_NONE ) { - msd_debug_nest_print(msdp->chp, "H"); - if (msdWaitForISR(msdp, TRUE, wait_mode) == WAIT_ISR_BUSS_RESET_OR_RECONNECT) { - msd_debug_nest_print(msdp->chp, "h"); - return (MSD_WAIT_MODE_NONE); - } - msd_debug_nest_print(msdp->chp, "h"); - } - - msdp->scsi_command_state = "Wait-Done"; - - msd_csw_t *csw = &(msdp->csw); - - - csw->status = (msdp->command_succeeded_flag) ? MSD_COMMAND_PASSED : MSD_COMMAND_FAILED; - csw->signature = MSD_CSW_SIGNATURE; - csw->data_residue = cbw->data_len; - csw->tag = cbw->tag; - - msdp->scsi_command_state = "TX"; - msd_debug_nest_print(msdp->chp, "I"); - usbPrepareTransmit(msdp->usbp, msdp->ms_ep_number, (uint8_t *)csw, - sizeof(msd_csw_t)); - - chSysLock(); - msdp->bulk_out_interupt_flag = false; - msdWaitForCommandBlock(msdp); - - msdp->bulk_in_interupt_flag = false; - usbStartTransmitI(msdp->usbp, msdp->ms_ep_number); - chSysUnlock(); - msd_debug_nest_print(msdp->chp, "i"); - - msdWaitForISR(msdp, TRUE, MSD_WAIT_MODE_BULK_IN);//wait for our status to be sent back - - msdp->scsi_command_state = "Done All"; - - /* wait on ISR */ - //return MSD_WAIT_MODE_BULK_IN; - return MSD_WAIT_MODE_BULK_OUT; -} - - - - - -/*===========================================================================*/ -/* Threads */ -/*===========================================================================*/ - -/** - * @brief This thread is responsible for triggering a USB write of date - * from the MCU to the host. It is run as a separate thread to allow - * for concurrent RXing of data and writing of data to the SD card to - * thus significantly improve performance. - * - * @param[in] arg pointer to the @p USBMassStorageDriver object - * - * @special - */ -static msg_t MassStorageUSBTransferThd(void *arg) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)arg; - - chRegSetThreadName("MSD-Transfer"); - - while ( !chThdShouldTerminate() ) { - if (msdp->suspend_threads_callback != NULL && msdp->suspend_threads_callback()) { - /* Suspend the thread for power savings mode */ - chSysLock(); - chSchGoSleepS(THD_STATE_SUSPENDED); - chSysUnlock(); - } - - if (msdp->trigger_transfer_index != UINT32_MAX) { - msdp->transfer_thread_state = "PP"; - SCSIWriteTransferPingPong( - msdp, &rw_ping_pong_buffer[msdp->trigger_transfer_index]); - msdp->trigger_transfer_index = UINT32_MAX; - /*notify other thread*/ - chBSemSignal(&msdp->mass_sorage_thd_bsem); - } - - chBSemWaitTimeout(&msdp->usb_transfer_thread_bsem, MS2ST(1)); - } - - return (0); -} - - - -static msg_t MassStorageThd(void *arg) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)arg; - chRegSetThreadName("MSD"); - - msd_wait_mode_t wait_for_isr = MSD_WAIT_MODE_NONE; - - /* wait for the usb to be initialized */ - msd_debug_print(msdp->chp, "Y"); - msdWaitForISR(msdp, FALSE, MSD_WAIT_MODE_NONE); - msd_debug_print(msdp->chp, "y"); - - while ( !chThdShouldTerminate() ) { - -#if 0 - if( msdp->suspend_threads_callback != NULL && msdp->suspend_threads_callback() ) { - /* Suspend the thread for power savings mode */ - chSysLock(); - chSchGoSleepS(THD_STATE_SUSPENDED); - chSysUnlock(); - } -#endif - - - wait_for_isr = MSD_WAIT_MODE_NONE; - - if (msdp->reconfigured_or_reset_event) { - /*If the devices is unplugged and re-plugged but did not have a CPU reset, - * we must set the state back to idle.*/ - msdp->reconfigured_or_reset_event = FALSE; - msdp->state = MSD_STATE_IDLE; - - msdSetDefaultSenseKey(msdp); - } - - bool_t enable_msd = true; - if (msdp->enable_msd_callback != NULL) { - enable_msd = msdp->enable_msd_callback(); - } - - if( msdp->driver_state != USB_MSD_DRIVER_OK ) { - enable_msd = false; - } - msdp->debug_enable_msd = enable_msd; - - if ( enable_msd ) { - - if( ! msdp->block_dev_info_valid_flag ) { - if( blkGetDriverState(msdp->bbdp) == BLK_READY ) { - blkGetInfo(msdp->bbdp, &msdp->block_dev_info); - msdp->block_dev_info_valid_flag = true; - } - } - - msd_debug_print(msdp->chp, "state=%d\r\n", msdp->state); - /* wait on data depending on the current state */ - switch (msdp->state) { - case MSD_STATE_IDLE: - msdp->msd_thread_state = "IDL"; - msd_debug_print(msdp->chp, "IDL"); - wait_for_isr = msdWaitForCommandBlock(msdp); - msd_debug_print(msdp->chp, "x\r\n"); - break; - case MSD_STATE_READ_CMD_BLOCK: - msdp->msd_thread_state = "RCB"; - msd_debug_print(msdp->chp, "RCB"); - wait_for_isr = msdProcessCommandBlock(msdp); - msd_debug_print(msdp->chp, "x\r\n"); - break; - case MSD_STATE_EJECTED: - /* disconnect usb device */ - msd_debug_print(msdp->chp, "ejected\r\n"); - if (!msdp->disable_usb_bus_disconnect_on_eject) { - msdp->msd_thread_state = "Ejected"; - chThdSleepMilliseconds(70); - usbDisconnectBus(msdp->usbp); - usbStop(msdp->usbp); - chThdExit(0); - } - return 0; - } - } - - msdp->debug_wait_for_isr = wait_for_isr; - - if( enable_msd ) { - msd_debug_nest_print(msdp->chp, "L"); - } else { - msd_debug_nest_print(msdp->chp, "M"); - } - - if (wait_for_isr) { - msd_debug_nest_print(msdp->chp, "J"); - } else { - msd_debug_nest_print(msdp->chp, "K"); - } - - if (wait_for_isr && (!msdp->reconfigured_or_reset_event)) { - /* wait until the ISR wakes thread */ - msd_debug_print(msdp->chp, "W%d,%d", wait_for_isr, msdp->state); - msdWaitForISR(msdp, TRUE, wait_for_isr); - msd_debug_print(msdp->chp, "w\r\n"); - } else if( ! enable_msd ) { - chThdSleepMilliseconds(5); - } - - - if (wait_for_isr) { - msd_debug_nest_print(msdp->chp, "j"); - } else { - msd_debug_nest_print(msdp->chp, "k"); - } - } - - return 0; -} - - - - - -#endif /* HAL_USE_MASS_STORAGE_USB */ diff --git a/firmware/hw_layer/mass_storage/usb_msd.h b/firmware/hw_layer/mass_storage/usb_msd.h deleted file mode 100644 index d4466b0842..0000000000 --- a/firmware/hw_layer/mass_storage/usb_msd.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, - 2011,2012,2013 Giovanni Di Sirio. - - This file is part of ChibiOS/RT. - - ChibiOS/RT 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 3 of the License, or - (at your option) any later version. - - ChibiOS/RT 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 . -*/ - -#ifndef _USB_MSD_H_ -#define _USB_MSD_H_ - -#include "hal.h" - -/* Default to disabled for USB Mass Storage */ -#if !defined(HAL_USE_MASS_STORAGE_USB) -# define HAL_USE_MASS_STORAGE_USB TRUE -#endif - -#if HAL_USE_MASS_STORAGE_USB || defined(__DOXYGEN__) - - -#if 0 -#define MSD_RW_LED_ON() palSetPad(GPIOI, GPIOI_TRI_LED_BLUE) -#define MSD_RW_LED_OFF() palClearPad(GPIOI, GPIOI_TRI_LED_BLUE) -#define MSD_R_LED_ON() palSetPad(GPIOI, GPIOI_TRI_LED_BLUE) -#define MSD_R_LED_OFF() palClearPad(GPIOI, GPIOI_TRI_LED_BLUE) -#define MSD_W_LED_ON() palSetPad(GPIOH, GPIOI_TRI_LED_BLUE) -#define MSD_W_LED_OFF() palClearPad(GPIOH, GPIOI_TRI_LED_BLUE) -#else -#define MSD_RW_LED_ON() -#define MSD_RW_LED_OFF() -#define MSD_R_LED_ON() -#define MSD_R_LED_OFF() -#define MSD_W_LED_ON() -#define MSD_W_LED_OFF() -#endif - - -#if STM32_USB_USE_OTG2 && STM32_USE_USB_OTG2_HS -# define USB_MS_EP_SIZE 512 -#else -# define USB_MS_EP_SIZE 64 -#endif - -#define MSD_THREAD_STACK_SIZE 1024 - -#define MSD_REQ_RESET 0xFF -#define MSD_GET_MAX_LUN 0xFE -#define MSD_CBW_SIGNATURE 0x43425355 -#define MSD_CSW_SIGNATURE 0x53425355 -#define MSD_COMMAND_DIR_DATA_OUT (0 << 7) -#define MSD_COMMAND_DIR_DATA_IN (1 << 7) - -#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index+1] << 8) | (setup[index] & 0x00FF)) - -#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2) -#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4) -#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6) - -typedef enum { - SCSI_CMD_TEST_UNIT_READY = 0x00, - SCSI_CMD_REQUEST_SENSE_6 = 0x03, - SCSI_CMD_INQUIRY = 0x12, - SCSI_CMD_MODE_SENSE_6 = 0x1A, - SCSI_CMD_START_STOP_UNIT = 0x1B, - SCSI_CMD_SEND_DIAGNOSTIC = 0x1D, - SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E, - SCSI_CMD_READ_FORMAT_CAPACITY = 0x23, - SCSI_CMD_READ_CAPACITY_10 = 0x25, - SCSI_CMD_READ_10 = 0x28, - SCSI_CMD_WRITE_10 = 0x2A, - SCSI_CMD_VERIFY_10 = 0x2F, - SCSI_CMD_SYNCHRONIZE_CACHE_10 = 0x35, -} msd_scsi_command_t; - - - -#define MSD_COMMAND_PASSED 0x00 -#define MSD_COMMAND_FAILED 0x01 -#define MSD_COMMAND_PHASE_ERROR 0x02 - -#define SCSI_SENSE_KEY_GOOD 0x00 -#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 -#define SCSI_SENSE_KEY_NOT_READY 0x02 -#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 -#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 -#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 -#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 -#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 -#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 -#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 -#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A -#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B -#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D -#define SCSI_SENSE_KEY_MISCOMPARE 0x0E - -#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 -#define SCSI_ASENSE_PEREPHERIAL_DEVICE_WRITE_FAULT 0x03 -#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 -#define SCSI_ASENSE_UNRECOVERED_READ_ERROR 0x11 -#define SCSI_ASENSE_INVALID_COMMAND 0x20 -#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 -#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 -#define SCSI_ASENSE_WRITE_PROTECTED 0x27 -#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 -#define SCSI_ASENSE_FORMAT_ERROR 0x31 -#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A - -#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 -#define SCSI_ASENSEQ_PEREPHERIAL_DEVICE_WRITE_FAULT 0x00 -#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 -#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 -#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 - - -PACK_STRUCT_BEGIN typedef struct { - uint32_t signature; - uint32_t tag; - uint32_t data_len; - uint8_t flags; - uint8_t lun; - uint8_t scsi_cmd_len; - uint8_t scsi_cmd_data[16]; -} PACK_STRUCT_STRUCT msd_cbw_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct { - uint32_t signature; - uint32_t tag; - uint32_t data_residue; - uint8_t status; -} PACK_STRUCT_STRUCT msd_csw_t PACK_STRUCT_END; - -typedef struct { - uint8_t byte[18]; -} PACK_STRUCT_STRUCT scsi_sense_response_t; - -typedef struct { - uint8_t mode_data_length; //Number of bytes that follow - uint8_t medium_type; //0x00 for SBC devices - uint8_t device_specifc_paramters; //bit 7 is the write protect bit - uint8_t block_descriptor_length; //Length in bytes of all block descriptors in the mode parameter list. -} PACK_STRUCT_STRUCT scsi_mode_sense6_response_t; - -PACK_STRUCT_BEGIN typedef struct -{ - uint8_t peripheral; - uint8_t removable; - uint8_t version; - uint8_t response_data_format; - uint8_t additional_length; - uint8_t sccstp; - uint8_t bqueetc; - uint8_t cmdque; - uint8_t vendorID[8]; - uint8_t productID[16]; - uint8_t productRev[4]; -} PACK_STRUCT_STRUCT scsi_inquiry_response_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct { - uint8_t payload_byte_length[4]; - uint32_t last_block_addr; - uint32_t block_size; -} PACK_STRUCT_STRUCT scsi_read_format_capacity_response_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct { - uint32_t last_block_addr; - uint32_t block_size; -} PACK_STRUCT_STRUCT scsi_read_capacity10_response_t PACK_STRUCT_END; - -PACK_STRUCT_BEGIN typedef struct { - uint8_t op_code; - uint8_t lun_immed; - uint8_t res1; - uint8_t res2; - uint8_t loej_start; - uint8_t control; -} PACK_STRUCT_STRUCT scsi_start_stop_unit_request_t; - - - -typedef enum { - MSD_WAIT_MODE_NONE = 0, - MSD_WAIT_MODE_BULK_IN, - MSD_WAIT_MODE_BULK_OUT -} msd_wait_mode_t; - -typedef enum { - MSD_STATE_IDLE = 0, - MSD_STATE_READ_CMD_BLOCK, - MSD_STATE_EJECTED -} msd_state_t; - -typedef enum { - USB_MSD_DRIVER_UNINITIALIZED = 0, - USB_MSD_DRIVER_ERROR, - USB_MSD_DRIVER_OK, - USB_MSD_DRIVER_STOPPED, - USB_MSD_DRIVER_ERROR_BLK_DEV_NOT_READY, -} usb_msd_driver_state_t; - -typedef struct USBMassStorageDriver USBMassStorageDriver; - -struct USBMassStorageDriver { - /* Driver Setup Data */ - USBDriver *usbp; - BaseBlockDevice *bbdp; - EventSource evt_connected; - EventSource evt_ejected; - BlockDeviceInfo block_dev_info; - bool block_dev_info_valid_flag; - usb_msd_driver_state_t driver_state; - usbep_t ms_ep_number; - uint16_t msd_interface_number; - bool_t (*enable_msd_callback)(void); - bool_t (*suspend_threads_callback)(void); - - /* Externally modifiable settings */ - bool_t enable_media_removial; - bool_t disable_usb_bus_disconnect_on_eject; - BaseSequentialStream *chp; /*For debug logging*/ - - /*Internal data for operation of the driver */ - BinarySemaphore bsem; - BinarySemaphore usb_transfer_thread_bsem; - BinarySemaphore mass_sorage_thd_bsem; - volatile uint32_t trigger_transfer_index; - - volatile bool_t bulk_in_interupt_flag; - volatile bool_t bulk_out_interupt_flag; - - struct { - scsi_read_format_capacity_response_t format_capacity_response; - scsi_read_capacity10_response_t read_capacity10_response; - scsi_mode_sense6_response_t mode_sense6_response; - uint8_t max_lun_len_buf[1]; - scsi_inquiry_response_t scsi_inquiry_response; - } data; - - msd_state_t state; - msd_cbw_t cbw; - msd_csw_t csw; - scsi_sense_response_t sense; - - volatile bool_t reconfigured_or_reset_event; - - bool_t command_succeeded_flag; - bool_t stall_in_endpoint; - bool_t stall_out_endpoint; - - - /*Debugging Information*/ - volatile uint32_t read_error_count; - volatile uint32_t write_error_count; - volatile uint32_t read_success_count; - volatile uint32_t write_success_count; - char *msd_thread_state; - char *transfer_thread_state; - char *scsi_command_state; - volatile uint8_t last_bad_scsi_command; - - /* Externally readable values */ - volatile bool_t debug_enable_msd; - volatile msd_wait_mode_t debug_wait_for_isr; - - WORKING_AREA(waMassStorage, MSD_THREAD_STACK_SIZE); - WORKING_AREA(waMassStorageUSBTransfer, MSD_THREAD_STACK_SIZE); -}; - - -#ifdef __cplusplus -extern "C" { -#endif -usb_msd_driver_state_t msdInit(USBDriver *usbp, BaseBlockDevice *bbdp, USBMassStorageDriver *msdp, const usbep_t ms_ep_number, const uint16_t msd_interface_number); -usb_msd_driver_state_t msdStart(USBMassStorageDriver *msdp); -usb_msd_driver_state_t msdStop(USBMassStorageDriver *msdp); -void msdBulkInCallbackComplete(USBDriver *usbp, usbep_t ep); -void msdBulkOutCallbackComplete(USBDriver *usbp, usbep_t ep); -bool_t msdRequestsHook(USBDriver *usbp); -bool_t msdRequestsHook2(USBDriver *usbp, USBMassStorageDriver *msdp); -const char* usb_msd_driver_state_t_to_str(const usb_msd_driver_state_t driver_state); -#ifdef __cplusplus -} -#endif - - -#endif /* HAL_USE_MASS_STORAGE_USB */ - -#endif /* _USB_MSD_H_ */ diff --git a/firmware/hw_layer/mass_storage/usb_msd_cfg.c b/firmware/hw_layer/mass_storage/usb_msd_cfg.c index 56b76ff278..6421ce7ace 100644 --- a/firmware/hw_layer/mass_storage/usb_msd_cfg.c +++ b/firmware/hw_layer/mass_storage/usb_msd_cfg.c @@ -1,43 +1,41 @@ /* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, - 2011,2012,2013 Giovanni Di Sirio. + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio - This file is part of ChibiOS/RT. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - ChibiOS/RT 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 3 of the License, or - (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 - ChibiOS/RT 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 . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ -#include "ch.h" #include "hal.h" + +#include "hal_usb_msd.h" #include "usb_msd_cfg.h" -#include "usb_msd.h" - - +/* + * must be 64 for full speed and 512 for high speed + */ +#define USB_MSD_EP_SIZE 64U /* * USB Device Descriptor. */ static const uint8_t msd_device_descriptor_data[18] = { USB_DESC_DEVICE (0x0200, /* bcdUSB (2.0). */ - 0x00, /* bDeviceClass (None). */ + 0x02, /* bDeviceClass (CDC). */ 0x00, /* bDeviceSubClass. */ 0x00, /* bDeviceProtocol. */ - 0x40, /* Control Endpoint Size. */ + 0x40, /* bMaxPacketSize. */ 0x0483, /* idVendor (ST). */ 0x5742, /* idProduct. */ - 0x0100, /* bcdDevice. */ + 0x0200, /* bcdDevice. */ 1, /* iManufacturer. */ 2, /* iProduct. */ 3, /* iSerialNumber. */ @@ -52,34 +50,34 @@ static const USBDescriptor msd_device_descriptor = { msd_device_descriptor_data }; -/* Configuration Descriptor tree*/ -static const uint8_t msd_configuration_descriptor_data[] = { - /* Configuration Descriptor.*/ - USB_DESC_CONFIGURATION(0x0020, /* wTotalLength. */ - 0x01, /* bNumInterfaces. */ - 0x01, /* bConfigurationValue. */ - 0, /* iConfiguration. */ - 0xC0, /* bmAttributes (self powered). */ - 0x32), /* bMaxPower (100mA). */ - /* Interface Descriptor.*/ - USB_DESC_INTERFACE (USB_MSD_INTERFACE_NUMBER, /* bInterfaceNumber. */ - 0x00, /* bAlternateSetting. */ - 0x02, /* bNumEndpoints. */ - 0x08, /* bInterfaceClass (Mass Storage) */ - 0x06, /* bInterfaceSubClass (SCSI - Transparent storage class) */ - 0x50, /* bInterfaceProtocol (Bulk Only) */ - 0), /* iInterface. (none) */ - /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP|0x80, - 0x02, /* bmAttributes (Bulk). */ - USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05), /* bInterval. 1ms */ - /* Mass Storage Data In Endpoint Descriptor.*/ - USB_DESC_ENDPOINT (USB_MS_DATA_EP, - 0x02, /* bmAttributes (Bulk). */ - USB_MS_EP_SIZE,/* wMaxPacketSize. */ - 0x05) /* bInterval. 1ms */ +/* Configuration Descriptor tree for a CDC.*/ +static const uint8_t msd_configuration_descriptor_data[67] = { + /* Configuration Descriptor.*/ + USB_DESC_CONFIGURATION(0x0020, /* wTotalLength. */ + 0x01, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0xC0, /* bmAttributes (self powered). */ + 0x32), /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x08, /* bInterfaceClass (Mass Storage) */ + 0x06, /* bInterfaceSubClass (SCSI + Transparent storage class) */ + 0x50, /* bInterfaceProtocol (Bulk Only) */ + 0), /* iInterface. (none) */ + /* Mass Storage Data In Endpoint Descriptor.*/ + USB_DESC_ENDPOINT (USB_MSD_DATA_EP | 0x80, + 0x02, /* bmAttributes (Bulk). */ + USB_MSD_EP_SIZE, /* wMaxPacketSize. */ + 0x00), /* bInterval. 1ms */ + /* Mass Storage Data Out Endpoint Descriptor.*/ + USB_DESC_ENDPOINT (USB_MSD_DATA_EP, + 0x02, /* bmAttributes (Bulk). */ + USB_MSD_EP_SIZE, /* wMaxPacketSize. */ + 0x00) /* bInterval. 1ms */ }; /* @@ -114,17 +112,17 @@ static const uint8_t msd_string1[] = { * Device Description string. */ static const uint8_t msd_string2[] = { - USB_DESC_BYTE(58), /* bLength. */ + USB_DESC_BYTE(62), /* bLength. */ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ - 'r', 0, 'u', 0, 's', 0, 'E', 0, 'f', 0, 'i', 0, - ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, + 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, + 'R', 0, 'T', 0, ' ', 0, 'M', 0, 'a', 0, 's', 0, 's', 0, ' ', 0, 'S', 0, 't', 0, 'o', 0, 'r', 0, 'a', 0, 'g', 0, 'e', 0, ' ', 0, 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0 }; static const uint8_t msd_string3[] = { - USB_DESC_BYTE(26), /* bLength. */ - USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + USB_DESC_BYTE(26), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ 'A', 0, 'E', 0, 'C', 0, 'C', 0, 'E', 0, 'C', 0, 'C', 0, 'C', 0, 'C', 0, '0' + CH_KERNEL_MAJOR, 0, '0' + CH_KERNEL_MINOR, 0, @@ -164,53 +162,51 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp, return NULL; } - - /** * @brief IN EP1 state. */ -static USBInEndpointState ep1InState; -static USBOutEndpointState ep1OutState; +static USBInEndpointState ep1instate; /** - * @brief EP1 initialization structure (IN only). + * @brief OUT EP1 state. */ -static const USBEndpointConfig epDataConfig = { +static USBOutEndpointState ep1outstate; + +/** + * @brief EP1 initialization structure (both IN and OUT). + */ +static const USBEndpointConfig ep1config = { USB_EP_MODE_TYPE_BULK, NULL, - msdBulkInCallbackComplete, - msdBulkOutCallbackComplete, - USB_MS_EP_SIZE, - USB_MS_EP_SIZE, - &ep1InState, - &ep1OutState, - 1, + NULL, + NULL, + USB_MSD_EP_SIZE, + USB_MSD_EP_SIZE, + &ep1instate, + &ep1outstate, + 4, NULL }; - /* * Handles the USB driver global events. */ static void usb_event(USBDriver *usbp, usbevent_t event) { - USBMassStorageDriver *msdp = (USBMassStorageDriver *)usbp->in_params[USB_MS_DATA_EP - 1]; + switch (event) { case USB_EVENT_RESET: - msdp->reconfigured_or_reset_event = TRUE; return; case USB_EVENT_ADDRESS: return; case USB_EVENT_CONFIGURED: - chSysLockFromIsr(); - msdp->reconfigured_or_reset_event = TRUE; - usbInitEndpointI(usbp, msdp->ms_ep_number, &epDataConfig); - /* Kick-start the thread */ - chBSemSignalI(&msdp->bsem); - - /* signal that the device is connected */ - chEvtBroadcastI(&msdp->evt_connected); - chSysUnlockFromIsr(); - + chSysLockFromISR(); + /* Enables the endpoints specified into the configuration. + Note, this callback is invoked from an ISR so I-Class functions + must be used.*/ + usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); + chSysUnlockFromISR(); + return; + case USB_EVENT_UNCONFIGURED: return; case USB_EVENT_SUSPEND: return; @@ -222,10 +218,13 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { return; } -const USBConfig msd_usb_config = { - usb_event, - get_descriptor, - msdRequestsHook, - NULL +/* + * USB driver configuration. + */ +const USBConfig msdusbcfg = { + usb_event, + get_descriptor, + msd_request_hook, + NULL }; diff --git a/firmware/hw_layer/mass_storage/usb_msd_cfg.h b/firmware/hw_layer/mass_storage/usb_msd_cfg.h index 55e91230bc..2904c0e2c0 100644 --- a/firmware/hw_layer/mass_storage/usb_msd_cfg.h +++ b/firmware/hw_layer/mass_storage/usb_msd_cfg.h @@ -22,8 +22,9 @@ #define USB_MSD_CFG_H_ -#define USB_MS_DATA_EP 1 -#define USB_MSD_INTERFACE_NUMBER 0x00 +#define USBD1_DATA_REQUEST_EP 1 +#define USBD1_DATA_AVAILABLE_EP 1 +#define USBD1_INTERRUPT_REQUEST_EP 2 #endif /* USB_MSD_CFG_H_ */ diff --git a/firmware/hw_layer/microsecond_timer.cpp b/firmware/hw_layer/microsecond_timer.cpp index 5198d575a5..54e4197ab8 100644 --- a/firmware/hw_layer/microsecond_timer.cpp +++ b/firmware/hw_layer/microsecond_timer.cpp @@ -87,10 +87,10 @@ static void callback(GPTDriver *gptp) { // // test code // setOutputPinValue(LED_CRANKING, timerCallbackCounter % 2); // int mod = timerCallbackCounter % 400; -// chSysLockFromIsr() +// chSysLockFromISR() // ; // setHardwareUsTimer(400 - mod); -// chSysUnlockFromIsr() +// chSysUnlockFromISR() // ; globalTimerCallback(NULL); @@ -127,7 +127,7 @@ static msg_t mwThread(int param) { static const GPTConfig gpt5cfg = { 1000000, /* 1 MHz timer clock.*/ callback, /* Timer callback.*/ -0 }; +0, 0 }; void initMicrosecondTimer(void) { diff --git a/firmware/hw_layer/mmc_card.cpp b/firmware/hw_layer/mmc_card.cpp index d9e90475d6..71bec76745 100644 --- a/firmware/hw_layer/mmc_card.cpp +++ b/firmware/hw_layer/mmc_card.cpp @@ -24,7 +24,7 @@ #include "hardware.h" #include "engine_configuration.h" #include "status_loop.h" -#include "usb_msd.h" +#include "hal_usb_msd.h" #include "usb_msd_cfg.h" #include "rtc_helper.h" @@ -56,7 +56,7 @@ extern board_configuration_s *boardConfiguration; //static USBDriver *ms_usb_driver = &USBD1; //static USBMassStorageDriver UMSD1; -//extern const USBConfig msd_usb_config; +extern const USBConfig msdusbcfg; @@ -317,7 +317,7 @@ static void MMCumount(void) { f_sync(&FDLogFile); // sync ALL mmcDisconnect(&MMCD1); // Brings the driver in a state safe for card removal. mmcStop(&MMCD1); // Disables the MMC peripheral. - f_mount(0, NULL); // FATFS: Unregister work area prior to discard it + f_mount(NULL, 0, 0); // FATFS: Unregister work area prior to discard it memset(&FDLogFile, 0, sizeof(FIL)); // clear FDLogFile fs_ready = false; // status = false scheduleMsg(&logger, "MMC/SD card removed"); @@ -333,17 +333,17 @@ static void MMCmount(void) { scheduleMsg(&logger, "Error: Already mounted. \"umountsd\" first"); return; } - if ((MMCD1.state != BLK_STOP) && (MMCD1.state != BLK_ACTIVE)) { - firmwareError(CUSTOM_OBD_MMC_START1, "mmc_state1 %d", MMCD1.state); - return; + if ((MMCD1.state == BLK_STOP) || (MMCD1.state == BLK_ACTIVE)) { + // looks like we would only get here after manual unmount with mmcStop? Do we really need to ever mmcStop? + // not sure if this code is needed + // start to initialize MMC/SD + mmcStart(&MMCD1, &mmccfg); // Configures and activates the MMC peripheral. } - // start to initialize MMC/SD - mmcStart(&MMCD1, &mmccfg); // Configures and activates the MMC peripheral. // Performs the initialization procedure on the inserted card. lockSpi(SPI_NONE); sdStatus = SD_STATE_CONNECTING; - if (mmcConnect(&MMCD1) != CH_SUCCESS) { + if (mmcConnect(&MMCD1) != HAL_SUCCESS) { sdStatus = SD_STATE_NOT_CONNECTED; warning(CUSTOM_OBD_MMC_ERROR, "Can't connect or mount MMC/SD"); unlockSpi(); @@ -372,7 +372,7 @@ static void MMCmount(void) { unlockSpi(); // if Ok - mount FS now memset(&MMC_FS, 0, sizeof(FATFS)); - if (f_mount(0, &MMC_FS) == FR_OK) { + if (f_mount(&MMC_FS, "/", 1) == FR_OK) { sdStatus = SD_STATE_MOUNTED; incLogFileName(); createLogFile(); @@ -423,11 +423,6 @@ void initMmcCard(void) { // start to initialize MMC/SD mmcObjectInit(&MMCD1); // Initializes an instance. - if ((MMCD1.state != BLK_STOP) && (MMCD1.state != BLK_ACTIVE)) { - firmwareError(CUSTOM_OBD_MMC_START2, "mmc_state2 %d", MMCD1.state); - return; - } - mmcStart(&MMCD1, &mmccfg); chThdCreateStatic(mmcThreadStack, sizeof(mmcThreadStack), LOWPRIO, (tfunc_t) MMCmonThread, NULL); diff --git a/firmware/hw_layer/rtc_helper.cpp b/firmware/hw_layer/rtc_helper.cpp index 4a11664c3b..87355e5679 100644 --- a/firmware/hw_layer/rtc_helper.cpp +++ b/firmware/hw_layer/rtc_helper.cpp @@ -13,25 +13,57 @@ #include "rtc_helper.h" #if EFI_RTC || defined(__DOXYGEN__) -#include "chrtclib.h" +#include "rtc.h" static LoggingWithStorage logger("RTC"); +static RTCDateTime timespec; #endif /* EFI_RTC */ void date_set_tm(struct tm *timp) { (void)timp; #if EFI_RTC || defined(__DOXYGEN__) - rtcSetTimeTm(&RTCD1, timp); + rtcConvertStructTmToDateTime(timp, 0, ×pec); + rtcSetTime(&RTCD1, ×pec); #endif /* EFI_RTC */ } void date_get_tm(struct tm *timp) { - (void)timp; #if EFI_RTC || defined(__DOXYGEN__) - rtcGetTimeTm(&RTCD1, timp); + rtcGetTime(&RTCD1, ×pec); + rtcConvertDateTimeToStructTm(×pec, timp, NULL); #endif /* EFI_RTC */ } +static time_t GetTimeUnixSec(void) { +#if EFI_RTC || defined(__DOXYGEN__) + struct tm tim; + + rtcGetTime(&RTCD1, ×pec); + rtcConvertDateTimeToStructTm(×pec, &tim, NULL); + return mktime(&tim); +#endif +} + +static void SetTimeUnixSec(time_t unix_time) { +#if EFI_RTC || defined(__DOXYGEN__) + struct tm tim; + +#if defined __GNUC__ + struct tm *canary; + /* If the conversion is successful the function returns a pointer + to the object the result was written into.*/ + canary = localtime_r(&unix_time, &tim); + osalDbgCheck(&tim == canary); +#else + struct tm *t = localtime(&unix_time); + memcpy(&tim, t, sizeof(struct tm)); +#endif + + rtcConvertStructTmToDateTime(&tim, 0, ×pec); + rtcSetTime(&RTCD1, ×pec); +#endif +} + static void put2(int offset, char *lcd_str, int value) { static char buff[_MAX_FILLER]; efiAssertVoid(value >=0 && value <100, "value"); @@ -95,7 +127,7 @@ void printDateTime(void) { static time_t unix_time; struct tm timp; - unix_time = rtcGetTimeUnixSec(&RTCD1); + unix_time = GetTimeUnixSec(); if (unix_time == -1) { scheduleMsg(&logger, "incorrect time in RTC cell"); } else { @@ -114,7 +146,7 @@ void setDateTime(const char *strDate) { if (strlen(strDate) > 0) { time_t unix_time = atoi(strDate); if (unix_time > 0) { - rtcSetTimeUnixSec(&RTCD1, unix_time); + SetTimeUnixSec(unix_time); printDateTime(); return; } @@ -125,7 +157,7 @@ void setDateTime(const char *strDate) { void initRtc(void) { #if EFI_RTC || defined(__DOXYGEN__) - rtcGetTimeUnixSec(&RTCD1); // this would test RTC, see 'rtcWorks' variable, see #311 + GetTimeUnixSec(); // this would test RTC, see 'rtcWorks' variable, see #311 printMsg(&logger, "initRtc()"); #endif /* EFI_RTC */ } diff --git a/firmware/hw_layer/serial_over_usb/usbcfg.c b/firmware/hw_layer/serial_over_usb/usbcfg.c index b13196f2c6..ee8e1c8f17 100644 --- a/firmware/hw_layer/serial_over_usb/usbcfg.c +++ b/firmware/hw_layer/serial_over_usb/usbcfg.c @@ -1,5 +1,5 @@ /* - ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,9 @@ #if HAL_USE_SERIAL_USB || defined(__DOXYGEN__) +/* Virtual serial port over USB.*/ +SerialUSBDriver SDU1; + /* * Endpoints to be used for USBD1. */ @@ -271,7 +274,7 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { case USB_EVENT_ADDRESS: return; case USB_EVENT_CONFIGURED: - chSysLockFromIsr(); + chSysLockFromISR(); /* Enables the endpoints specified into the configuration. Note, this callback is invoked from an ISR so I-Class functions @@ -282,9 +285,17 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { /* Resetting the state of the CDC subsystem.*/ sduConfigureHookI(&SDU1); - chSysUnlockFromIsr(); + chSysUnlockFromISR(); + return; + case USB_EVENT_UNCONFIGURED: return; case USB_EVENT_SUSPEND: + chSysLockFromISR(); + + /* Disconnection event on suspend.*/ + sduDisconnectI(&SDU1); + + chSysUnlockFromISR(); return; case USB_EVENT_WAKEUP: return; @@ -294,6 +305,18 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { return; } +/* + * Handles the USB driver global events. + */ +static void sof_handler(USBDriver *usbp) { + + (void)usbp; + + osalSysLockFromISR(); + sduSOFHookI(&SDU1); + osalSysUnlockFromISR(); +} + /* * USB driver configuration. */ @@ -301,7 +324,7 @@ const USBConfig usbcfg = { usb_event, get_descriptor, sduRequestsHook, - NULL + sof_handler }; /* @@ -314,6 +337,4 @@ const SerialUSBConfig serusbcfg = { USBD1_INTERRUPT_REQUEST_EP }; -/* Virtual serial port over USB.*/ -SerialUSBDriver SDU1; -#endif +#endif /* EFI_USB_SERIAL */ diff --git a/firmware/hw_layer/stm32f4/mpu_util.cpp b/firmware/hw_layer/stm32f4/mpu_util.cpp index eca12acc1f..e493c0372b 100644 --- a/firmware/hw_layer/stm32f4/mpu_util.cpp +++ b/firmware/hw_layer/stm32f4/mpu_util.cpp @@ -11,6 +11,7 @@ #include "engine.h" #include "pin_repository.h" #include "stm32f4xx_hal_flash.h" +#include "rfiutil.h" EXTERN_ENGINE; @@ -26,16 +27,18 @@ extern uint32_t __main_stack_base__; #if defined __GNUC__ // GCC version +typedef struct port_intctx intctx_t; + int getRemainingStack(thread_t *otp) { #if CH_DBG_ENABLE_STACK_CHECK // this would dismiss coverity warning - see http://rusefi.com/forum/viewtopic.php?f=5&t=655 // coverity[uninit_use] - register struct intctx *r13 asm ("r13"); + register intctx_t *r13 asm ("r13"); otp->activeStack = r13; int remainingStack; - if (dbg_isr_cnt > 0) { + if (ch.dbg.isr_cnt > 0) { // ISR context remainingStack = (int)(r13 - 1) - (int)&__main_stack_base__; } else { @@ -53,13 +56,13 @@ int getRemainingStack(thread_t *otp) { extern uint32_t CSTACK$$Base; /* symbol created by the IAR linker */ extern uint32_t IRQSTACK$$Base; /* symbol created by the IAR linker */ -int getRemainingStack(Thread *otp) { +int getRemainingStack(thread_t *otp) { #if CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__) int remainingStack; - if (dbg_isr_cnt > 0) { - remainingStack = (__get_SP() - sizeof(struct intctx)) - (int)&IRQSTACK$$Base; + if (ch.dbg.isr_cnt > 0) { + remainingStack = (__get_SP() - sizeof(port_intctx)) - (int)&IRQSTACK$$Base; } else { - remainingStack = (__get_SP() - sizeof(struct intctx)) - (int)otp->p_stklimit; + remainingStack = (__get_SP() - sizeof(port_intctx)) - (int)otp->p_stklimit; } otp->remainingStack = remainingStack; return remainingStack; @@ -74,7 +77,7 @@ int getRemainingStack(Thread *otp) { void baseHardwareInit(void) { // looks like this holds a random value on start? Let's set a nice clean zero - DWT_CYCCNT = 0; + DWT->CYCCNT = 0; BOR_Set(BOR_Level_1); // one step above default value } diff --git a/firmware/hw_layer/trigger_input.cpp b/firmware/hw_layer/trigger_input.cpp index 305fd9175c..a3c2d78150 100644 --- a/firmware/hw_layer/trigger_input.cpp +++ b/firmware/hw_layer/trigger_input.cpp @@ -31,11 +31,13 @@ int vvtEventRiseCounter = 0; int vvtEventFallCounter = 0; static void cam_icu_width_callback(ICUDriver *icup) { + (void)icup; vvtEventRiseCounter++; hwHandleVvtCamSignal(TV_RISE); } static void cam_icu_period_callback(ICUDriver *icup) { + (void)icup; vvtEventFallCounter++; hwHandleVvtCamSignal(TV_FALL); } @@ -80,14 +82,24 @@ static void shaft_icu_period_callback(ICUDriver *icup) { /** * the main purpose of this configuration structure is to specify the input interrupt callbacks */ -static ICUConfig shaft_icucfg = { ICU_INPUT_ACTIVE_LOW, 100000, /* 100kHz ICU clock frequency. */ -shaft_icu_width_callback, shaft_icu_period_callback }; +static ICUConfig shaft_icucfg = { ICU_INPUT_ACTIVE_LOW, + 100000, /* 100kHz ICU clock frequency. */ + shaft_icu_width_callback, + shaft_icu_period_callback, + NULL, + ICU_CHANNEL_1, + 0}; /** * this is about VTTi and stuff kind of cam sensor */ -static ICUConfig cam_icucfg = { ICU_INPUT_ACTIVE_LOW, 100000, /* 100kHz ICU clock frequency. */ -cam_icu_width_callback, cam_icu_period_callback }; +static ICUConfig cam_icucfg = { ICU_INPUT_ACTIVE_LOW, + 100000, /* 100kHz ICU clock frequency. */ + cam_icu_width_callback, + cam_icu_period_callback, + NULL, + ICU_CHANNEL_1, + 0}; static ICUDriver *turnOnTriggerInputPin(const char *msg, brain_pin_e hwPin, ICUConfig *icucfg) { @@ -111,7 +123,8 @@ static ICUDriver *turnOnTriggerInputPin(const char *msg, brain_pin_e hwPin, ICUC efiIcuStart(driver, icucfg); if (driver->state == ICU_READY) { - icuEnable(driver); + icuStartCapture(driver); + icuEnableNotifications(driver); } else { // we would be here for example if same pin is used for multiple input capture purposes firmwareError(CUSTOM_ERR_ICU_STATE, "ICU unexpected state [%s]", hwPortname(hwPin)); @@ -123,7 +136,8 @@ static ICUDriver *turnOnTriggerInputPin(const char *msg, brain_pin_e hwPin, ICUC static void turnOffTriggerInputPin(brain_pin_e hwPin) { ICUDriver *driver = getInputCaptureDriver("trigger_off", hwPin); if (driver != NULL) { - icuDisable(driver); + icuDisableNotifications(driver); + icuStopCapture(driver); icuStop(driver); scheduleMsg(logger, "turnOffTriggerInputPin %s", hwPortname(hwPin)); unmarkPin(hwPin); diff --git a/firmware/iar/ch.ewp b/firmware/iar/ch.ewp index 6580fcd981..0045a07eda 100644 --- a/firmware/iar/ch.ewp +++ b/firmware/iar/ch.ewp @@ -298,25 +298,64 @@