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 @@