From b00529e287c13197f80787f5126626b0d08c06a1 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 18 Nov 2022 21:38:03 +0700 Subject: add msc file explorer example - add lib/fatfs version 15 - add lib/embedded-cli --- examples/host/msc_file_explorer/CMakeLists.txt | 43 ++++++ examples/host/msc_file_explorer/Makefile | 38 +++++ examples/host/msc_file_explorer/only.txt | 11 ++ examples/host/msc_file_explorer/src/main.c | 97 ++++++++++++ examples/host/msc_file_explorer/src/msc_app.c | 171 ++++++++++++++++++++++ examples/host/msc_file_explorer/src/tusb_config.h | 115 +++++++++++++++ 6 files changed, 475 insertions(+) create mode 100644 examples/host/msc_file_explorer/CMakeLists.txt create mode 100644 examples/host/msc_file_explorer/Makefile create mode 100644 examples/host/msc_file_explorer/only.txt create mode 100644 examples/host/msc_file_explorer/src/main.c create mode 100644 examples/host/msc_file_explorer/src/msc_app.c create mode 100644 examples/host/msc_file_explorer/src/tusb_config.h (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt new file mode 100644 index 000000000..fc4765cdc --- /dev/null +++ b/examples/host/msc_file_explorer/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.5) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) + +# gets PROJECT name for the example (e.g. -) +family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) + +project(${PROJECT}) + +# Checks this example is valid for the family and initializes the project +family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) + +add_executable(${PROJECT}) + +# Example source +target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c + ) + +# Example include +target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +# Configure compilation flags and libraries for the example... see the corresponding function +# in hw/bsp/FAMILY/family.cmake for details. +family_configure_host_example(${PROJECT}) + +# For rp2040, un-comment to enable pico-pio-usb +family_add_pico_pio_usb(${PROJECT}) + +# due to warnings from Pico-PIO-USB +target_compile_options(${PROJECT} PUBLIC + -Wno-error=shadow + -Wno-error=cast-align + -Wno-error=cast-qual + -Wno-error=redundant-decls + -Wno-error=sign-conversion + -Wno-error=conversion + -Wno-error=sign-compare + -Wno-error=unused-function + ) diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile new file mode 100644 index 000000000..518d75063 --- /dev/null +++ b/examples/host/msc_file_explorer/Makefile @@ -0,0 +1,38 @@ +include ../../../tools/top.mk +include ../../make.mk + +FATFS_PATH = lib/fatfs/source + +INC += \ + src \ + $(TOP)/hw \ + $(TOP)/$(FATFS_PATH) \ + $(TOP)/lib/embedded-cli \ + +# Example source +EXAMPLE_SOURCE = \ + src/main.c \ + src/msc_app.c \ + +SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) + +# FatFS source +SRC_C += \ + $(FATFS_PATH)/ff.c \ + $(FATFS_PATH)/ffsystem.c \ + $(FATFS_PATH)/ffunicode.c \ + +# TODO: suppress warning caused by host stack +CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference + +# TinyUSB Host Stack source +SRC_C += \ + src/class/cdc/cdc_host.c \ + src/class/hid/hid_host.c \ + src/class/msc/msc_host.c \ + src/host/hub.c \ + src/host/usbh.c \ + src/portable/ohci/ohci.c \ + src/portable/nxp/lpc17_40/hcd_lpc17_40.c + +include ../../rules.mk diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt new file mode 100644 index 000000000..fa9c14857 --- /dev/null +++ b/examples/host/msc_file_explorer/only.txt @@ -0,0 +1,11 @@ +mcu:LPC175X_6X +mcu:LPC177X_8X +mcu:LPC18XX +mcu:LPC40XX +mcu:LPC43XX +mcu:MIMXRT +mcu:MIMXRT10XX +mcu:MIMXRT11XX +mcu:RP2040 +mcu:MSP432E4 +mcu:RX65X diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c new file mode 100644 index 000000000..13c473d9b --- /dev/null +++ b/examples/host/msc_file_explorer/src/main.c @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include + +#include "bsp/board.h" +#include "tusb.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ +void led_blinking_task(void); + +extern bool msc_app_init(void); +extern void msc_app_task(void); + +/*------------- MAIN -------------*/ +int main(void) +{ + board_init(); + + printf("TinyUSB Host CDC MSC HID Example\r\n"); + + // init host stack on configured roothub port + tuh_init(BOARD_TUH_RHPORT); + msc_app_init(); + + while (1) + { + // tinyusb host task + tuh_task(); + + msc_app_task(); + led_blinking_task(); + } + + return 0; +} + +//--------------------------------------------------------------------+ +// TinyUSB Callbacks +//--------------------------------------------------------------------+ + +void tuh_mount_cb(uint8_t dev_addr) +{ + // application set-up + printf("A device with address %d is mounted\r\n", dev_addr); +} + +void tuh_umount_cb(uint8_t dev_addr) +{ + // application tear-down + printf("A device with address %d is unmounted \r\n", dev_addr); +} + + +//--------------------------------------------------------------------+ +// Blinking Task +//--------------------------------------------------------------------+ +void led_blinking_task(void) +{ + const uint32_t interval_ms = 1000; + static uint32_t start_ms = 0; + + static bool led_state = false; + + // Blink every interval ms + if ( board_millis() - start_ms < interval_ms) return; // not enough time + start_ms += interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c new file mode 100644 index 000000000..a9976be23 --- /dev/null +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -0,0 +1,171 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "tusb.h" + +#define EMBEDDED_CLI_IMPL +#include "embedded_cli.h" // lib/embedded-cli + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +// embedded cli configuration +#define CLI_BUFFER_SIZE 256 +#define CLI_RX_BUFFER_SIZE 16 +#define CLI_CMD_BUFFER_SIZE 32 +#define CLI_HISTORY_SIZE 32 +#define CLI_BINDING_COUNT 3 + +static EmbeddedCli *_cli; +static CLI_UINT cli_buffer[BYTES_TO_CLI_UINTS(CLI_BUFFER_SIZE)]; + +static scsi_inquiry_resp_t inquiry_resp; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +void cli_write_char(EmbeddedCli *cli, char c) +{ + (void) cli; + putchar((int) c); +} + +void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command) +{ + (void) cli; + printf("Unknown commands: %s\r\n", command->name); +} + +bool msc_app_init(void) +{ + // disable stdout buffered for echoing typing command + setbuf(stdout, NULL); + + EmbeddedCliConfig *config = embeddedCliDefaultConfig(); + config->cliBuffer = cli_buffer; + config->cliBufferSize = CLI_BUFFER_SIZE; + config->rxBufferSize = CLI_RX_BUFFER_SIZE; + config->cmdBufferSize = CLI_CMD_BUFFER_SIZE; + config->historyBufferSize = CLI_HISTORY_SIZE; + config->maxBindingCount = CLI_BINDING_COUNT; + + _cli = embeddedCliNew(config); + TU_ASSERT(_cli != NULL); + + _cli->writeChar = cli_write_char; + + return true; +} + +void msc_app_task(void) +{ + if (!_cli) return; + + int ch; + while( (ch = getchar()) > 0 ) + { + embeddedCliReceiveChar(_cli, (char) ch); + } + + embeddedCliProcess(_cli); +} + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + + +bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + if (csw->status != 0) + { + printf("Inquiry failed\r\n"); + return false; + } + + // Print out Vendor ID, Product ID and Rev + printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev); + + // Get capacity of device + uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); + uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); + + printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size)); + printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + + return true; +} + +//------------- IMPLEMENTATION -------------// +void tuh_msc_mount_cb(uint8_t dev_addr) +{ + printf("A MassStorage device is mounted\r\n"); + + uint8_t const lun = 0; + tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb); +// +// //------------- file system (only 1 LUN support) -------------// +// uint8_t phy_disk = dev_addr-1; +// disk_initialize(phy_disk); +// +// if ( disk_is_ready(phy_disk) ) +// { +// if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK ) +// { +// puts("mount failed"); +// return; +// } +// +// f_chdrive(phy_disk); // change to newly mounted drive +// f_chdir("/"); // root as current dir +// +// cli_init(); +// } +} + +void tuh_msc_umount_cb(uint8_t dev_addr) +{ + (void) dev_addr; + printf("A MassStorage device is unmounted\r\n"); + +// uint8_t phy_disk = dev_addr-1; +// +// f_mount(phy_disk, NULL); // unmount disk +// disk_deinitialize(phy_disk); +// +// if ( phy_disk == f_get_current_drive() ) +// { // active drive is unplugged --> change to other drive +// for(uint8_t i=0; i Date: Sat, 19 Nov 2022 13:44:07 +0700 Subject: msc explorer ls work great --- examples/host/msc_file_explorer/src/main.c | 2 +- examples/host/msc_file_explorer/src/msc_app.c | 216 +- examples/host/msc_file_explorer/src/tusb_config.h | 5 +- lib/fatfs/00readme.txt | 138 - lib/fatfs/ccsbcs.c | 543 --- lib/fatfs/diskio.c | 193 - lib/fatfs/diskio.h | 95 - lib/fatfs/ff.c | 4330 --------------------- lib/fatfs/ff.h | 342 -- lib/fatfs/ffconf.h | 193 - lib/fatfs/integer.h | 36 - lib/fatfs/source/ffconf.h | 6 +- 12 files changed, 197 insertions(+), 5902 deletions(-) delete mode 100644 lib/fatfs/00readme.txt delete mode 100644 lib/fatfs/ccsbcs.c delete mode 100644 lib/fatfs/diskio.c delete mode 100644 lib/fatfs/diskio.h delete mode 100644 lib/fatfs/ff.c delete mode 100644 lib/fatfs/ff.h delete mode 100644 lib/fatfs/ffconf.h delete mode 100644 lib/fatfs/integer.h (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c index 13c473d9b..f46e5092b 100644 --- a/examples/host/msc_file_explorer/src/main.c +++ b/examples/host/msc_file_explorer/src/main.c @@ -43,7 +43,7 @@ int main(void) { board_init(); - printf("TinyUSB Host CDC MSC HID Example\r\n"); + printf("TinyUSB Host MSC Explorer Example\r\n"); // init host stack on configured roothub port tuh_init(BOARD_TUH_RHPORT); diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index a9976be23..a8603c9df 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -25,14 +25,18 @@ #include "tusb.h" +#include "ff.h" +#include "diskio.h" + +// lib/embedded-cli #define EMBEDDED_CLI_IMPL -#include "embedded_cli.h" // lib/embedded-cli +#include "embedded_cli.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ -// embedded cli configuration +//------------- embedded-cli -------------// #define CLI_BUFFER_SIZE 256 #define CLI_RX_BUFFER_SIZE 16 #define CLI_CMD_BUFFER_SIZE 32 @@ -42,12 +46,18 @@ static EmbeddedCli *_cli; static CLI_UINT cli_buffer[BYTES_TO_CLI_UINTS(CLI_BUFFER_SIZE)]; +//------------- Elm Chan FatFS -------------// +static FATFS fatfs[CFG_TUH_DEVICE_MAX]; // for simplicity only support 1 LUN per device +static volatile bool _disk_busy[CFG_TUH_DEVICE_MAX]; + static scsi_inquiry_resp_t inquiry_resp; //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ +void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); + void cli_write_char(EmbeddedCli *cli, char c) { (void) cli; @@ -62,6 +72,8 @@ void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command) bool msc_app_init(void) { + for(size_t i=0; iwriteChar = cli_write_char; + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "ls", + "Usage: ls [FILE]...\r\n\tList information about the FILEs (the current directory by default).", + true, + NULL, + cli_cmd_ls + }); + return true; } @@ -117,6 +137,19 @@ bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size)); printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + // For simplicity: we only mount 1 LUN per device + uint8_t const drive_num = dev_addr-1; + char drive_path[3] = "0:"; + drive_path[0] += drive_num; + + if ( f_mount(&fatfs[drive_num], drive_path, 1) != FR_OK ) + { + puts("mount failed"); + } + + f_chdrive(drive_path); // change to newly mounted drive + f_chdir("/"); // root as current dir + return true; } @@ -127,24 +160,6 @@ void tuh_msc_mount_cb(uint8_t dev_addr) uint8_t const lun = 0; tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb); -// -// //------------- file system (only 1 LUN support) -------------// -// uint8_t phy_disk = dev_addr-1; -// disk_initialize(phy_disk); -// -// if ( disk_is_ready(phy_disk) ) -// { -// if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK ) -// { -// puts("mount failed"); -// return; -// } -// -// f_chdrive(phy_disk); // change to newly mounted drive -// f_chdir("/"); // root as current dir -// -// cli_init(); -// } } void tuh_msc_umount_cb(uint8_t dev_addr) @@ -152,11 +167,12 @@ void tuh_msc_umount_cb(uint8_t dev_addr) (void) dev_addr; printf("A MassStorage device is unmounted\r\n"); -// uint8_t phy_disk = dev_addr-1; -// -// f_mount(phy_disk, NULL); // unmount disk -// disk_deinitialize(phy_disk); -// + uint8_t const drive_num = dev_addr-1; + char drive_path[3] = "0:"; + drive_path[0] += drive_num; + + f_unmount(drive_path); + // if ( phy_disk == f_get_current_drive() ) // { // active drive is unplugged --> change to other drive // for(uint8_t i=0; i 1 ) return; + + // default is current directory + const char* dpath = "."; + if (argc) dpath = args; + + DIR dir; + if ( FR_OK != f_opendir(&dir, dpath) ) + { + printf("cannot access '%s': No such file or directory", dpath); + return; + } + + FILINFO fno; + while( (f_readdir(&dir, &fno) == FR_OK) && (fno.fname[0] != 0) ) + { + if ( fno.fname[0] != '.' ) // ignore . and .. entry + { + if ( fno.fattrib & AM_DIR ) + { + // directory + printf("/%s\n", fno.fname); + }else + { + printf("%-40s%lu KB\n", fno.fname, fno.fsize / 1000); + } + } + } + + f_closedir(&dir); +} diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index fd1215388..ddf8368f4 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -104,9 +104,8 @@ // max device support (excluding hub device) #define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports -//------------- HID -------------// -#define CFG_TUH_HID_EPIN_BUFSIZE 64 -#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +//------------- MSC -------------// +#define CFG_TUH_MSC_MAXLUN 4 // typical for most card reader #ifdef __cplusplus } diff --git a/lib/fatfs/00readme.txt b/lib/fatfs/00readme.txt deleted file mode 100644 index f7330e924..000000000 --- a/lib/fatfs/00readme.txt +++ /dev/null @@ -1,138 +0,0 @@ -FatFs Module Source Files R0.09b (C)ChaN, 2013 - - -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) 2012, 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 == 1) - diff --git a/lib/fatfs/ccsbcs.c b/lib/fatfs/ccsbcs.c deleted file mode 100644 index 07d6f0983..000000000 --- a/lib/fatfs/ccsbcs.c +++ /dev/null @@ -1,543 +0,0 @@ -/*------------------------------------------------------------------------*/ -/* 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 CFG_TUH_MSC - -#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; -} - -#endif // CFG_TUH_MSC diff --git a/lib/fatfs/diskio.c b/lib/fatfs/diskio.c deleted file mode 100644 index a6132f27b..000000000 --- a/lib/fatfs/diskio.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "tusb.h" - -#if CFG_TUH_MSC -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "ffconf.h" -#include "diskio.h" -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -// TODO change it to portable init -static DSTATUS disk_state[CFG_TUH_DEVICE_MAX]; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// IMPLEMENTATION -//--------------------------------------------------------------------+ -static DRESULT wait_for_io_complete(uint8_t usb_addr) -{ - // TODO with RTOS, this should use semaphore instead of blocking - while ( !tuh_msc_ready(usb_addr) ) - { - // TODO should have timeout here - #if CFG_TUSB_OS != OPT_OS_NONE - osal_task_delay(10); - #endif - } - - return RES_OK; -} - -void diskio_init(void) -{ - memset(disk_state, STA_NOINIT, CFG_TUH_DEVICE_MAX); -} - -//pdrv Specifies the physical drive number. -DSTATUS disk_initialize ( BYTE pdrv ) -{ - disk_state[pdrv] &= (~STA_NOINIT); // clear NOINIT bit - return disk_state[pdrv]; -} - -void disk_deinitialize ( BYTE pdrv ) -{ - disk_state[pdrv] |= STA_NOINIT; // set NOINIT bit -} - -DSTATUS disk_status (BYTE pdrv) -{ - return disk_state[pdrv]; -} - -//pdrv -// Specifies the physical drive number --> == dev_addr-1 -//buff -// Pointer to the byte array to store the read data. The size of buffer must be in sector size * sector count. -//sector -// Specifies the start sector number in logical block address (LBA). -//count -// Specifies number of sectors to read. The value can be 1 to 128. Generally, a multiple sector transfer request -// must not be split into single sector transactions to the device, or you may not get good read performance. -DRESULT disk_read (BYTE pdrv, BYTE*buff, DWORD sector, BYTE count) -{ - uint8_t usb_addr = pdrv+1; - - if ( TUSB_ERROR_NONE != tuh_msc_read10(usb_addr, 0, buff, sector, count) ) return RES_ERROR; - - return wait_for_io_complete(usb_addr); -} - - -DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, BYTE count) -{ - uint8_t usb_addr = pdrv+1; - - if ( TUSB_ERROR_NONE != tuh_msc_write10(usb_addr, 0, buff, sector, count) ) return RES_ERROR; - - return wait_for_io_complete(usb_addr); -} - -/* [IN] Drive number */ -/* [IN] Control command code */ -/* [I/O] Parameter and data buffer */ -DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) -{ - (void) buff; (void) pdrv; // compiler warnings - - if (cmd != CTRL_SYNC) return RES_ERROR; - return RES_OK; -} - -static inline uint8_t month2number(char* p_ch) -{ - char const * const month_str[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - for(uint8_t i=0; i<12; i++) - { - if ( strncmp(p_ch, month_str[i], 3) == 0 ) return i+1; - } - - return 1; -} - -static inline uint8_t c2i(char ch) -{ - return ch - '0'; -} - -DWORD get_fattime (void) -{ - union { - struct { - DWORD second : 5; - DWORD minute : 6; - DWORD hour : 5; - DWORD day_in_month : 5; - DWORD month : 4; - DWORD year : 7; - }; - - DWORD value; - } timestamp; - - //------------- Date is compiled date-------------// - char compile_date[] = __DATE__; // eg. "Sep 26 2013" - char* p_ch; - - p_ch = strtok (compile_date, " "); - timestamp.month = month2number(p_ch); - - p_ch = strtok (NULL, " "); - timestamp.day_in_month = 10*c2i(p_ch[0])+ c2i(p_ch[1]); - - p_ch = strtok (NULL, " "); - timestamp.year = 1000*c2i(p_ch[0]) + 100*c2i(p_ch[1]) + 10*c2i(p_ch[2]) + c2i(p_ch[3]) - 1980; - - //------------- Time each time this function call --> sec ++ -------------// - static uint8_t sec = 0; - static uint8_t min = 0; - static uint8_t hour = 0; - - if (++sec >= 60) - { - sec = 0; - if (++min >= 60) - { - min = 0; - if (++hour >= 24) - { - hour = 0; // assume demo wont call this function more than 24*60*60 times - } - } - } - - timestamp.hour = hour; - timestamp.minute = min; - timestamp.second = sec; - - return timestamp.value; -} - -#endif // CFG_TUH_MSC diff --git a/lib/fatfs/diskio.h b/lib/fatfs/diskio.h deleted file mode 100644 index f1f4bd327..000000000 --- a/lib/fatfs/diskio.h +++ /dev/null @@ -1,95 +0,0 @@ -/*----------------------------------------------------------------------- -/ Low level disk interface modlue include file (C)ChaN, 2013 -/-----------------------------------------------------------------------*/ - -#ifndef _DISKIO_DEFINED -#define _DISKIO_DEFINED - -#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" -#include - -/* Status of Disk Functions */ -typedef BYTE DSTATUS; - -/* Results of Disk Functions */ -typedef enum { - RES_OK = 0, /* 0: Successful */ - RES_ERROR, /* 1: R/W Error */ - RES_WRPRT, /* 2: Write Protected */ - RES_NOTRDY, /* 3: Not Ready */ - RES_PARERR /* 4: Invalid Parameter */ -} DRESULT; - - -/* Disk Status Bits (DSTATUS) */ -#define STA_NOINIT 0x01 /* Drive not initialized */ -#define STA_NODISK 0x02 /* No medium in the drive */ -#define STA_PROTECT 0x04 /* Write protected */ - - -/* Command code for disk_ioctrl fucntion */ - -/* 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 (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 */ -#define MMC_GET_CSD 11 /* Get CSD */ -#define MMC_GET_CID 12 /* Get CID */ -#define MMC_GET_OCR 13 /* Get OCR */ -#define MMC_GET_SDSTAT 14 /* Get SD status */ - -/* ATA/CF specific ioctl command */ -#define ATA_GET_REV 20 /* Get F/W revision */ -#define ATA_GET_MODEL 21 /* Get model name */ -#define ATA_GET_SN 22 /* Get serial number */ - - -/* MMC card type flags (MMC_GET_TYPE) */ -#define CT_MMC 0x01 /* MMC ver 3 */ -#define CT_SD1 0x02 /* SD ver 1 */ -#define CT_SD2 0x04 /* SD ver 2 */ -#define CT_SDC (CT_SD1|CT_SD2) /* SD */ -#define CT_BLOCK 0x08 /* Block addressing */ - -/*---------------------------------------*/ -/* Prototypes for disk control functions */ - -void diskio_init(void); -void disk_deinitialize ( BYTE pdrv ); -DSTATUS disk_initialize (BYTE pdrv); -DSTATUS disk_status (BYTE pdrv); -DRESULT disk_read (BYTE pdrv, BYTE*buff, DWORD sector, BYTE count); -DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, BYTE count); -DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); - -static inline bool disk_is_ready(BYTE pdrv); -static inline bool disk_is_ready(BYTE pdrv) -{ - return (pdrv < CFG_TUH_DEVICE_MAX) && - ( (disk_status(pdrv) & (STA_NOINIT | STA_NODISK)) == 0 ); -} - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/fatfs/ff.c b/lib/fatfs/ff.c deleted file mode 100644 index 79414af07..000000000 --- a/lib/fatfs/ff.c +++ /dev/null @@ -1,4330 +0,0 @@ -/*----------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.09b (C)ChaN, 2013 -/-----------------------------------------------------------------------------/ -/ 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) 2013, 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 char. -/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h. -/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH. -/ Fixed name matching error on the 13 char 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 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 name. -/ -/ 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 volume. -/ Changed f_open() and f_opendir reject null object pointer to avoid crash. -/ Changed option name _FS_SHARE to _FS_LOCK. -/ Jan 24,'13 R0.09b Added f_setlabel() and f_getlabel(). (_USE_LABEL = 1) -/---------------------------------------------------------------------------*/ - -#include "ff.h" /* FatFs configurations and declarations */ -#include "diskio.h" /* Declarations of low level disk I/O functions */ - -#if CFG_TUH_MSC -/*-------------------------------------------------------------------------- - - Module Private Definitions - ----------------------------------------------------------------------------*/ - -#if _FATFS != 82786 /* Revision ID */ -#error Wrong include file (ff.h). -#endif - - -/* Definitions on sector size */ -#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096 -#error Wrong sector size. -#endif -#if _MAX_SS != 512 -#define SS(fs) ((fs)->ssize) /* Variable sector size */ -#else -#define SS(fs) 512U /* Fixed sector size */ -#endif - - -/* Reentrancy related */ -#if _FS_REENTRANT -#if _USE_LFN == 1 -#error Static LFN work area must not be used in re-entrant 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->flag |= FA__ERROR; LEAVE_FF(fs, res); } - - -/* File access control feature */ -#if _FS_LOCK -#if _FS_READONLY -#error _FS_LOCK must be 0 on read-only cfg. -#endif -typedef struct { - FATFS *fs; /* File ID 1, volume (NULL:blank entry) */ - DWORD clu; /* File ID 2, directory */ - WORD idx; /* File ID 3, directory index */ - WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */ -} FILESEM; -#endif - - - -/* DBCS code ranges and SBCS extend char 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 */ -/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */ -#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */ -#define MIN_FAT32 65526 /* 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 dir 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 dir 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 /* Boot sector signature (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 -/ zeroed/nulled at start-up. If not, the compiler or start-up -/ routine is out of ANSI-C standard. -*/ - -#if _VOLUMES -static -FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ -#else -#error Number of volumes must not be 0. -#endif - -static -WORD Fsid; /* File system mount ID */ - -#if _FS_RPATH -static -BYTE CurrVol; /* Current drive */ -#endif - -#if _FS_LOCK -static -FILESEM Files[_FS_LOCK]; /* File 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 chars */ -#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* dj, /* Directory object pointing the file to be checked */ - int acc /* Desired access (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 == dj->fs && /* Check if the file matched with an open file */ - Files[i].clu == dj->sclust && - Files[i].idx == dj->index) break; - } else { /* Blank entry */ - be++; - } - } - if (i == _FS_LOCK) /* The file is not opened */ - return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */ - - /* The file 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 file */ -{ - UINT i; - - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - return (i == _FS_LOCK) ? 0 : 1; -} - - -static -UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */ - DIR* dj, /* Directory object pointing the file to register or increment */ - int acc /* Desired access mode (0:Read, !0:Write) */ -) -{ - UINT i; - - - for (i = 0; i < _FS_LOCK; i++) { /* Find the file */ - if (Files[i].fs == dj->fs && - Files[i].clu == dj->sclust && - Files[i].idx == dj->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 space to register (int err) */ - Files[i].fs = dj->fs; - Files[i].clu = dj->sclust; - Files[i].idx = dj->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 file open counter */ - UINT i /* Semaphore index */ -) -{ - WORD n; - FRESULT res; - - - if (--i < _FS_LOCK) { - n = Files[i].ctr; - if (n == 0x100) n = 0; - if (n) n--; - Files[i].ctr = n; - if (!n) Files[i].fs = 0; - res = FR_OK; - } else { - res = FR_INT_ERR; - } - 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 */ -/*-----------------------------------------------------------------------*/ - - -#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) != RES_OK) - return FR_DISK_ERR; - fs->wflag = 0; - if (wsect >= fs->fatbase && wsect < (fs->fatbase + fs->fsize)) { /* In 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) != RES_OK) - 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) { - fs->winsect = 0; - /* Create FSInfo structure */ - mem_set(fs->win, 0, 512); - 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 */ - disk_write(fs->drv, fs->win, fs->fsi_sector, 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; - } - - 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; /* It is an invalid cluster */ - 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) { /* 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 *dj, /* Pointer to directory object */ - WORD idx /* Index of directory table */ -) -{ - DWORD clst; - WORD ic; - - - dj->index = idx; - clst = dj->sclust; - if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */ - return FR_INT_ERR; - if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ - clst = dj->fs->dirbase; - - if (clst == 0) { /* Static table (root-dir in FAT12/16) */ - dj->clust = clst; - if (idx >= dj->fs->n_rootdir) /* Index is out of range */ - return FR_INT_ERR; - dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */ - } - else { /* Dynamic table (sub-dirs or root-dir in FAT32) */ - ic = SS(dj->fs) / SZ_DIR * dj->fs->csize; /* Entries per cluster */ - while (idx >= ic) { /* Follow cluster chain */ - clst = get_fat(dj->fs, clst); /* Get next cluster */ - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */ - return FR_INT_ERR; - idx -= ic; - } - dj->clust = clst; - dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */ - } - - dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */ - - return FR_OK; /* Seek succeeded */ -} - - - - -/*-----------------------------------------------------------------------*/ -/* 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 *dj, /* Pointer to the directory object */ - int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ -) -{ - DWORD clst; - WORD i; - - - stretch = stretch; /* To suppress warning on read-only cfg. */ - i = dj->index + 1; - if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ - return FR_NO_FILE; - - if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */ - dj->sect++; /* Next sector */ - - if (dj->clust == 0) { /* Static table */ - if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */ - return FR_NO_FILE; - } - else { /* Dynamic table */ - if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ - clst = get_fat(dj->fs, dj->clust); /* Get next cluster */ - if (clst <= 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */ -#if !_FS_READONLY - BYTE c; - if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */ - clst = create_chain(dj->fs, dj->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(dj->fs)) return FR_DISK_ERR; /* Flush active window */ - mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */ - dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */ - for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */ - dj->fs->wflag = 1; - if (sync_window(dj->fs)) return FR_DISK_ERR; - dj->fs->winsect++; - } - dj->fs->winsect -= c; /* Rewind window address */ -#else - return FR_NO_FILE; /* Report EOT */ -#endif - } - dj->clust = clst; /* Initialize data for new cluster */ - dj->sect = clust2sect(dj->fs, clst); - } - } - } - - dj->index = i; - dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; - - return FR_OK; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Directory handling - Reserve directory entry */ -/*-----------------------------------------------------------------------*/ - -#if !_FS_READONLY -static -FRESULT dir_alloc ( - DIR* dj, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate (1-21) */ -) -{ - FRESULT res; - UINT n; - - - res = dir_sdi(dj, 0); - if (res == FR_OK) { - n = 0; - do { - res = move_window(dj->fs, dj->sect); - if (res != FR_OK) break; - if (dj->dir[0] == DDE || dj->dir[0] == 0) { /* Is it a blank entry? */ - if (++n == nent) break; /* A block of contiguous entry is found */ - } else { - n = 0; /* Not a blank entry. Restart to search */ - } - res = dir_next(dj, 1); /* Next entry with table stretch enabled */ - } while (res == FR_OK); - } - 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 chars 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 char 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 chars 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 char 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 char */ - ST_WORD(dir+LfnOfs[s], wc); /* Put it */ - if (!wc) wc = 0xFFFF; /* Padding chars following last char */ - } 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 -void gen_numname ( - BYTE *dst, /* Pointer to generated SFN */ - const BYTE *src, /* Pointer to source SFN to be modified */ - const WCHAR *lfn, /* Pointer to LFN */ - WORD 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 */ - do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn); - } - - /* 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 /* Ptr to directory 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 *dj /* 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(dj, 0); /* Rewind directory object */ - if (res != FR_OK) return res; - -#if _USE_LFN - ord = sum = 0xFF; -#endif - do { - res = move_window(dj->fs, dj->sect); - if (res != FR_OK) break; - dir = dj->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; - } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (dj->lfn) { - if (c & LLE) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; - c &= ~LLE; ord = c; /* LFN start order */ - dj->lfn_idx = dj->index; - } - /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF; - } - } else { /* An SFN entry is found */ - if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ - ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */ - if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */ - } - } -#else /* Non LFN configuration */ - if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */ - break; -#endif - res = dir_next(dj, 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 *dj, /* Pointer to the directory object */ - int vol /* Filtered by 0:file/dir or 1:volume label */ -) -{ - FRESULT res; - BYTE a, c, *dir; -#if _USE_LFN - BYTE ord = 0xFF, sum = 0xFF; -#endif - - res = FR_NO_FILE; - while (dj->sect) { - res = move_window(dj->fs, dj->sect); - if (res != FR_OK) break; - dir = dj->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 == '.') || (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; - dj->lfn_idx = dj->index; - } - /* Check LFN validity and capture it */ - ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF; - } else { /* An SFN entry is found */ - if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ - dj->lfn_idx = 0xFFFF; /* It has no LFN. */ - break; - } - } -#else /* Non LFN configuration */ - if (c != DDE && (_FS_RPATH || c != '.') && a != AM_LFN && (a == AM_VOL) == vol) /* Is it a valid entry? */ - break; -#endif - res = dir_next(dj, 0); /* Next entry */ - if (res != FR_OK) break; - } - - if (res != FR_OK) dj->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 *dj /* Target directory with object name to be created */ -) -{ - FRESULT res; -#if _USE_LFN /* LFN configuration */ - WORD n, ne; - BYTE sn[12], *fn, sum; - WCHAR *lfn; - - - fn = dj->fn; lfn = dj->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; dj->lfn = 0; /* Find only SFN */ - for (n = 1; n < 100; n++) { - gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ - res = dir_find(dj); /* 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]; dj->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++) ; - ne = (n + 25) / 13; - } else { /* Otherwise allocate an entry for an SFN */ - ne = 1; - } - res = dir_alloc(dj, ne); /* Allocate entries */ - - if (res == FR_OK && --ne) { /* Set LFN entry if needed */ - res = dir_sdi(dj, (WORD)(dj->index - ne)); - if (res == FR_OK) { - sum = sum_sfn(dj->fn); /* Sum value of the SFN tied to the LFN */ - do { /* Store LFN entries in bottom first */ - res = move_window(dj->fs, dj->sect); - if (res != FR_OK) break; - fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum); - dj->fs->wflag = 1; - res = dir_next(dj, 0); /* Next entry */ - } while (res == FR_OK && --ne); - } - } -#else /* Non LFN configuration */ - res = dir_alloc(dj, 1); /* Allocate an entry for SFN */ -#endif - - if (res == FR_OK) { /* Set SFN entry */ - res = move_window(dj->fs, dj->sect); - if (res == FR_OK) { - mem_set(dj->dir, 0, SZ_DIR); /* Clean the entry */ - mem_cpy(dj->dir, dj->fn, 11); /* Put SFN */ -#if _USE_LFN - dj->dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */ -#endif - dj->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 *dj /* Directory object pointing the entry to be removed */ -) -{ - FRESULT res; -#if _USE_LFN /* LFN configuration */ - WORD i; - - i = dj->index; /* SFN index */ - res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */ - if (res == FR_OK) { - do { - res = move_window(dj->fs, dj->sect); - if (res != FR_OK) break; - *dj->dir = DDE; /* Mark the entry "deleted" */ - dj->fs->wflag = 1; - if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ - res = dir_next(dj, 0); /* Next entry */ - } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR; - } - -#else /* Non LFN configuration */ - res = dir_sdi(dj, dj->index); - if (res == FR_OK) { - res = move_window(dj->fs, dj->sect); - if (res == FR_OK) { - *dj->dir = DDE; /* Mark the entry "deleted" */ - dj->fs->wflag = 1; - } - } -#endif - - return res; -} -#endif /* !_FS_READONLY */ - - - - -/*-----------------------------------------------------------------------*/ -/* Pick a segment and create the object name in directory form */ -/*-----------------------------------------------------------------------*/ - -static -FRESULT create_name ( - DIR *dj, /* 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 = dj->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 chars for LFN */ - return FR_INVALID_NAME; - lfn[di++] = w; /* Store the Unicode char */ - } - *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++) - dj->fn[i] = (i < di) ? '.' : ' '; - dj->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(dj->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 char */ - 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 char */ -#ifdef _EXCVT - w = ff_convert(w, 0); /* Unicode -> OEM code */ - if (w) w = ExCvt[w - 0x80]; /* Convert extended char 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 char (always false on SBCS cfg) */ - if (i >= ni - 1) { - cf |= NS_LOSS | NS_LFN; i = ni; continue; - } - dj->fn[i++] = (BYTE)(w >> 8); - } else { /* Single byte char */ - if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars 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; - } - } - } - } - dj->fn[i++] = (BYTE)w; - } - - if (dj->fn[0] == DDE) dj->fn[0] = NDDE; /* If the first char 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 char, 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) */ - } - - dj->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 = dj->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 char? */ - b |= 3; /* Eliminate NT flag */ -#ifdef _EXCVT - c = ExCvt[c - 0x80]; /* To upper extended chars (SBCS cfg) */ -#else -#if !_DF1S - return FR_INVALID_NAME; /* Reject extended chars (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 char 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 -} - - - - -/*-----------------------------------------------------------------------*/ -/* Get file information from directory entry */ -/*-----------------------------------------------------------------------*/ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 -static -void get_fileinfo ( /* No return code */ - DIR *dj, /* Pointer to the directory object */ - FILINFO *fno /* Pointer to the file information to be filled */ -) -{ - UINT i; - BYTE nt, *dir; - TCHAR *p, c; - - - p = fno->fname; - if (dj->sect) { - dir = dj->dir; - nt = dir[DIR_NTres]; /* NT flag */ - for (i = 0; i < 8; i++) { /* Copy name body */ - c = dir[i]; - if (c == ' ') break; - if (c == NDDE) c = (TCHAR)DDE; - if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20; -#if _LFN_UNICODE - if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1])) - c = (c << 8) | dir[++i]; - c = ff_convert(c, 1); - if (!c) c = '?'; -#endif - *p++ = c; - } - if (dir[8] != ' ') { /* Copy name extension */ - *p++ = '.'; - for (i = 8; i < 11; i++) { - c = dir[i]; - if (c == ' ') break; - if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20; -#if _LFN_UNICODE - if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1])) - c = (c << 8) | dir[++i]; - c = ff_convert(c, 1); - if (!c) c = '?'; -#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 str by a \0 */ - -#if _USE_LFN - if (fno->lfname && fno->lfsize) { - TCHAR *tp = fno->lfname; - WCHAR w, *lfn; - - i = 0; - if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */ - lfn = dj->lfn; - while ((w = *lfn++) != 0) { /* Get an LFN char */ -#if !_LFN_UNICODE - w = ff_convert(w, 0); /* Unicode -> OEM conversion */ - if (!w) { i = 0; break; } /* Could not convert, no LFN */ - if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ - tp[i++] = (TCHAR)(w >> 8); -#endif - if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */ - tp[i++] = (TCHAR)w; - } - } - tp[i] = 0; /* Terminate the LFN str by a \0 */ - } -#endif -} -#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2*/ - - - - -/*-----------------------------------------------------------------------*/ -/* Follow a file path */ -/*-----------------------------------------------------------------------*/ - -static -FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ - DIR *dj, /* 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++; dj->sclust = 0; /* Strip it and start from the root dir */ - } else { /* No heading separator */ - dj->sclust = dj->fs->cdir; /* Start from the current dir */ - } -#else - if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ - path++; - dj->sclust = 0; /* Start from the root dir */ -#endif - - if ((UINT)*path < ' ') { /* Nul path means the start directory itself */ - res = dir_sdi(dj, 0); - dj->dir = 0; - } else { /* Follow path */ - for (;;) { - res = create_name(dj, &path); /* Get a segment */ - if (res != FR_OK) break; - res = dir_find(dj); /* Find it */ - ns = *(dj->fn+NS); - if (res != FR_OK) { /* Failed to find the object */ - if (res != FR_NO_FILE) break; /* Abort if any hard error occurred */ - /* Object not found */ - if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */ - dj->sclust = 0; dj->dir = 0; /* It is the root dir */ - res = FR_OK; - if (!(ns & NS_LAST)) continue; - } else { /* Could not find the object */ - if (!(ns & NS_LAST)) res = FR_NO_PATH; - } - break; - } - if (ns & NS_LAST) break; /* Last segment match. Function completed. */ - dir = dj->dir; /* There is next segment. Follow the sub directory */ - if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */ - res = FR_NO_PATH; break; - } - dj->sclust = ld_clust(dj->fs, dir); - } - } - - return res; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Load a sector and check if it is an FAT Volume Boot Record */ -/*-----------------------------------------------------------------------*/ - -static -BYTE check_fs ( /* 0:FAT-VBR, 1:Any BR but not FAT, 2:Not a BR, 3:Disk error */ - FATFS *fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ -) -{ - if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */ - return 3; - if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check 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) - return 0; - - return 1; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Check if the file system object is valid or not */ -/*-----------------------------------------------------------------------*/ - -static -FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ - const TCHAR **path, /* Pointer to pointer to the path name (drive number) */ - FATFS **rfs, /* Pointer to pointer to the found file system object */ - BYTE wmode /* !=0: Check write protection for write access */ -) -{ - BYTE fmt, b, pi, *tbl; - UINT vol; - DSTATUS stat; - DWORD bsect, fasize, tsect, sysect, nclst, szbfat; - WORD nrsv; - const TCHAR *p = *path; - FATFS *fs; - - - /* Get logical drive number from the path name */ - vol = p[0] - '0'; /* Is there a drive number? */ - if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */ - p += 2; *path = p; /* Return pointer to the path name */ - } else { /* No drive number, use default drive */ -#if _FS_RPATH - vol = CurrVol; /* Use current drive */ -#else - vol = 0; /* Use drive 0 */ -#endif - } - - /* Check if the file system object is valid or not */ - *rfs = 0; - if (vol >= _VOLUMES) /* Is the drive number valid? */ - return FR_INVALID_DRIVE; - fs = FatFs[vol]; /* Get corresponding file system object */ - if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ - - ENTER_FF(fs); /* Lock volume */ - - *rfs = fs; /* Return pointer to the corresponding 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 (has not been changed), */ - 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 != 512 /* Get disk sector size (variable sector size cfg only) */ - if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK) - return FR_DISK_ERR; -#endif - /* Search FAT partition on the drive. Supports only generic partitions, FDISK and SFD. */ - fmt = check_fs(fs, bsect = 0); /* Load sector 0 and check if it is an FAT-VBR (in SFD) */ - if (LD2PT(vol) && !fmt) fmt = 1; /* Force non-SFD if the volume is forced partition */ - if (fmt == 1) { /* Not an FAT-VBR, the physical drive can be partitioned */ - /* Check the partition listed in the partition table */ - pi = LD2PT(vol); - if (pi) pi--; - tbl = &fs->win[MBR_Table + pi * SZ_PTE];/* Partition table */ - if (tbl[4]) { /* Is the partition existing? */ - bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */ - fmt = check_fs(fs, bsect); /* Check the partition */ - } - } - if (fmt == 3) return FR_DISK_ERR; - 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 = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */ - if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ - fasize *= b; /* Number of sectors for FAT area */ - - fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ - if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ - - fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */ - if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */ - - 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; /* (BPB_RsvdSecCnt 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; /* (Required 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) ? /* (Required 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 required) */ - return FR_NO_FILESYSTEM; - -#if !_FS_READONLY - /* Initialize cluster allocation information */ - fs->free_clust = 0xFFFFFFFF; - fs->last_clust = 0; - - /* Get fsinfo if available */ - if (fmt == FS_FAT32) { - fs->fsi_flag = 0; - fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo); - if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK && - LD_WORD(fs->win+BS_55AA) == 0xAA55 && - LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 && - LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) { - fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free); - fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count); - } - } -#endif - fs->fs_type = fmt; /* FAT sub-type */ - fs->id = ++Fsid; /* File system mount ID */ - fs->winsect = 0; /* Invalidate sector cache */ - fs->wflag = 0; -#if _FS_RPATH - fs->cdir = 0; /* Current directory (root dir) */ -#endif -#if _FS_LOCK /* Clear file lock semaphores */ - clear_lock(fs); -#endif - - return FR_OK; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Check if the file/dir 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 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 ( - BYTE vol, /* Logical drive number to be mounted/unmounted */ - FATFS *fs /* Pointer to new file system object (NULL for unmount)*/ -) -{ - FATFS *rfs; - - - if (vol >= _VOLUMES) /* Check if the drive number is valid */ - return FR_INVALID_DRIVE; - rfs = FatFs[vol]; /* Get current fs object */ - - if (rfs) { -#if _FS_LOCK - clear_lock(rfs); -#endif -#if _FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR; -#endif - rfs->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(vol, &fs->sobj)) return FR_INT_ERR; -#endif - } - FatFs[vol] = fs; /* Register new fs object */ - - return FR_OK; -} - - - - -/*-----------------------------------------------------------------------*/ -/* 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 */ - -#if !_FS_READONLY - mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; - res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ)); -#else - mode &= FA_READ; - res = chk_mounted(&path, &dj.fs, 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) /* Current dir 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 dir 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->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; fp->id = dj.fs->id; /* Validate file object */ - } - } - - 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->flag & FA__ERROR) /* Aborted file? */ - LEAVE_FF(fp->fs, FR_INT_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, (BYTE)cc) != RES_OK) - 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) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* 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->flag & FA__ERROR) /* Aborted file? */ - LEAVE_FF(fp->fs, FR_INT_ERR); - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - if ((DWORD)(fp->fsize + btw) < fp->fsize) 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, */ - fp->sclust = 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 _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) != RES_OK) - 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, (BYTE)cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); -#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 - 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) != RES_OK) - 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 Object */ -/*-----------------------------------------------------------------------*/ - -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? */ -#if !_FS_TINY /* Write-back dirty buffer */ - if (fp->flag & FA__DIRTY) { - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - 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 = validate(fp); - { -#if _FS_REENTRANT - FATFS *fs = fp->fs; -#endif - if (res == FR_OK) fp->fs = 0; /* Discard file object */ - LEAVE_FF(fs, res); - } -#else - res = f_sync(fp); /* Flush cached data */ -#if _FS_LOCK - if (res == FR_OK) { /* Decrement open counter */ -#if _FS_REENTRANT - FATFS *fs = fp->fs;; - res = validate(fp); - if (res == FR_OK) { - res = dec_lock(fp->lockid); - unlock_fs(fs, FR_OK); - } -#else - res = dec_lock(fp->lockid); -#endif - } -#endif - if (res == FR_OK) fp->fs = 0; /* Discard file object */ - return res; -#endif -} - - - - -/*-----------------------------------------------------------------------*/ -/* Current Drive/Directory Handlings */ -/*-----------------------------------------------------------------------*/ - -#if _FS_RPATH >= 1 - -FRESULT f_chdrive ( - BYTE drv /* Drive number */ -) -{ - if (drv >= _VOLUMES) return FR_INVALID_DRIVE; - - CurrVol = drv; - - return FR_OK; -} - -BYTE f_get_current_drive(void) -{ - return CurrVol; -} - -FRESULT f_chdir ( - const TCHAR *path /* Pointer to the directory path */ -) -{ - FRESULT res; - DIR dj; - DEF_NAMEBUF; - - - res = chk_mounted(&path, &dj.fs, 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; - res = chk_mounted((const TCHAR**)&buff, &dj.fs, 0); /* Get current volume */ - if (res == FR_OK) { - INIT_BUF(dj); - i = len; /* Bottom of buffer (dir stack base) */ - dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */ - while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */ - res = dir_sdi(&dj, 1); /* Get parent dir */ - 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 dir */ - res = dir_sdi(&dj, 0); - if (res != FR_OK) break; - do { /* Find the entry links to the child dir */ - 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 dir name and push it to the buffer */ - tp = fno.fname; - if (_USE_LFN && *buff) tp = buff; - 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) { - *tp++ = '0' + CurrVol; /* Put drive number */ - *tp++ = ':'; - if (i == len) { /* Root-dir */ - *tp++ = '/'; - } else { /* Sub-dir */ - 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->flag & FA__ERROR) /* Check abort flag */ - LEAVE_FF(fp->fs, FR_INT_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) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* 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) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* 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 *dj, /* Pointer to directory object to create */ - const TCHAR *path /* Pointer to the directory path */ -) -{ - FRESULT res; - FATFS *fs; - DEF_NAMEBUF; - - - if (!dj) return FR_INVALID_OBJECT; - - res = chk_mounted(&path, &dj->fs, 0); - fs = dj->fs; - if (res == FR_OK) { - INIT_BUF(*dj); - res = follow_path(dj, path); /* Follow the path to the directory */ - FREE_BUF(); - if (res == FR_OK) { /* Follow completed */ - if (dj->dir) { /* It is not the root dir */ - if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */ - dj->sclust = ld_clust(fs, dj->dir); - } else { /* The object is not a directory */ - res = FR_NO_PATH; - } - } - if (res == FR_OK) { - dj->id = fs->id; - res = dir_sdi(dj, 0); /* Rewind dir */ - } - } - if (res == FR_NO_FILE) res = FR_NO_PATH; - if (res != FR_OK) dj->fs = 0; /* Invalidate the dir object if function faild */ - } else { - dj->fs = 0; - } - - LEAVE_FF(fs, res); -} - - - - -/*-----------------------------------------------------------------------*/ -/* Read Directory Entry in Sequence */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_readdir ( - DIR *dj, /* Pointer to the open directory object */ - FILINFO *fno /* Pointer to file information to return */ -) -{ - FRESULT res; - DEF_NAMEBUF; - - - res = validate(dj); /* Check validity of the object */ - if (res == FR_OK) { - if (!fno) { - res = dir_sdi(dj, 0); /* Rewind the directory object */ - } else { - INIT_BUF(*dj); - res = dir_read(dj, 0); /* Read an item */ - if (res == FR_NO_FILE) { /* Reached end of dir */ - dj->sect = 0; - res = FR_OK; - } - if (res == FR_OK) { /* A valid entry is found */ - get_fileinfo(dj, fno); /* Get the object information */ - res = dir_next(dj, 0); /* Increment index for next */ - if (res == FR_NO_FILE) { - dj->sect = 0; - res = FR_OK; - } - } - FREE_BUF(); - } - } - - LEAVE_FF(dj->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; - - - res = chk_mounted(&path, &dj.fs, 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 */ - get_fileinfo(&dj, fno); - else /* It is root dir */ - 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 drive number */ - res = chk_mounted(&path, fatfs, 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; - if (fat == FS_FAT32) 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->flag & FA__ERROR) { /* Check abort flag */ - res = FR_INT_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 (res != FR_OK) fp->flag |= FA__ERROR; - } - - 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; - - - res = chk_mounted(&path, &dj.fs, 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-dir 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 dir */ -#if _FS_RPATH - || dclst == dj.fs->cdir /* Current dir */ -#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; - - - res = chk_mounted(&path, &dj.fs, 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[33] = '.'; 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; - - - res = chk_mounted(&path, &dj.fs, 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; - - - res = chk_mounted(&path, &dj.fs, 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 old name */ - const TCHAR *path_new /* Pointer to the new name */ -) -{ - FRESULT res; - DIR djo, djn; - BYTE buf[21], *dir; - DWORD dw; - DEF_NAMEBUF; - - - res = chk_mounted(&path_old, &djo.fs, 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 for name */ - mem_cpy(&djn, &djo, sizeof (DIR)); /* Check new object */ - res = follow_path(&djn, path_new); - 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 for 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* sn /* Pointer to a variable to return the volume serial number */ -) -{ - FRESULT res; - DIR dj; - UINT i, j; - - - /* Get logical drive */ - res = chk_mounted(&path, &dj.fs, 0); - - /* Get volume label */ - if (res == FR_OK && label) { - dj.sclust = 0; /* Open root dir */ - 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 _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); - } 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 && sn) { - res = move_window(dj.fs, dj.fs->volbase); - if (res == FR_OK) { - i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; - *sn = 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 */ - res = chk_mounted(&label, &dj.fs, 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 _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 chars */ -#ifdef _EXCVT - if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended chars (SBCS cfg) */ -#else - if (!_DF1S && w >= 0x80) w = 0; /* Reject extended chars (ASCII cfg) */ -#endif -#endif -#endif - if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid chars 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 dir */ - 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->flag & FA__ERROR) /* Check error flag */ - LEAVE_FF(fp->fs, FR_INT_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 dir entries for FAT12/16 */ -#define N_FATS 1 /* Number of FAT copies (1 or 2) */ - - -FRESULT f_mkfs ( - BYTE vol, /* Logical drive number */ - BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ - UINT au /* Allocation unit size [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}; - 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 */ - if (vol >= _VOLUMES) 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 != 512 /* Get disk sector size */ - if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_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) != RES_OK) 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; - - switch (fmt) { /* Determine system ID for partition table */ - case FS_FAT12: sys = 0x01; break; - case FS_FAT16: sys = (n_vol < 0x10000) ? 0x04 : 0x06; break; - default: sys = 0x0C; - } - - 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) != RES_OK) 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) != RES_OK) /* Write it to the MBR sector */ - 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 rootdir 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) != RES_OK) /* 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 dir */ - } - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - 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) != RES_OK) - return FR_DISK_ERR; - } - } - - /* Initialize root directory */ - i = (fmt == FS_FAT32) ? au : n_dir; - do { - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - 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] <= 100) ? (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 bytes until buffer gets filled */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; /* Break on EOF or error */ - c = s[0]; -#if _LFN_UNICODE /* Read a character in UTF-8 encoding */ - 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 = '?'; - } - } - } -#endif -#if _USE_STRFUNC >= 2 - if (c == '\r') continue; /* Strip '\r' */ -#endif - *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 */ -/*-----------------------------------------------------------------------*/ - -int f_putc ( - TCHAR c, /* A character to be output */ - FIL* fp /* Pointer to the file object */ -) -{ - UINT bw, btw; - BYTE s[3]; - - -#if _USE_STRFUNC >= 2 - if (c == '\n') f_putc ('\r', fp); /* LF -> CRLF conversion */ -#endif - -#if _LFN_UNICODE /* Write the character in UTF-8 encoding */ - if (c < 0x80) { /* 7-bit */ - s[0] = (BYTE)c; - btw = 1; - } else { - if (c < 0x800) { /* 11-bit */ - s[0] = (BYTE)(0xC0 | (c >> 6)); - s[1] = (BYTE)(0x80 | (c & 0x3F)); - btw = 2; - } else { /* 16-bit */ - s[0] = (BYTE)(0xE0 | (c >> 12)); - s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F)); - s[2] = (BYTE)(0x80 | (c & 0x3F)); - btw = 3; - } - } -#else /* Write the character without conversion */ - s[0] = (BYTE)c; - btw = 1; -#endif - f_write(fp, s, btw, &bw); /* Write the char to the file */ - return (bw == btw) ? 1 : EOF; /* Return the result */ -} - - - - -/*-----------------------------------------------------------------------*/ -/* 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 */ -) -{ - int n; - - - for (n = 0; *str; str++, n++) { - if (f_putc(*str, fp) == EOF) return EOF; - } - return n; -} - - - - -/*-----------------------------------------------------------------------*/ -/* Put a formatted string to the file */ -/*-----------------------------------------------------------------------*/ - -int f_printf ( - FIL* fp, /* Pointer to the file object */ - const TCHAR* str, /* Pointer to the format string */ - ... /* Optional arguments... */ -) -{ - va_list arp; - BYTE f, r; - UINT i, j, w; - ULONG v; - TCHAR c, d, s[16], *p; - int res, chc, cc; - - - va_start(arp, str); - - for (cc = res = 0; cc != EOF; res += cc) { - c = *str++; - if (c == 0) break; /* End of string */ - if (c != '%') { /* Non escape character */ - cc = f_putc(c, fp); - if (cc != EOF) cc = 1; - continue; - } - w = f = 0; - c = *str++; - if (c == '0') { /* Flag: '0' padding */ - f = 1; c = *str++; - } else { - if (c == '-') { /* Flag: left justified */ - f = 2; c = *str++; - } - } - while (IsDigit(c)) { /* Precision */ - w = w * 10 + c - '0'; - c = *str++; - } - if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ - f |= 4; c = *str++; - } - 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++) ; - chc = 0; - if (!(f & 2)) { - while (j++ < w) chc += (cc = f_putc(' ', fp)); - } - chc += (cc = f_puts(p, fp)); - while (j++ < w) chc += (cc = f_putc(' ', fp)); - if (cc != EOF) cc = chc; - continue; - case 'C' : /* Character */ - cc = f_putc((TCHAR)va_arg(arp, int), fp); 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) */ - cc = f_putc(c, fp); continue; - } - - /* Get an argument and put it in numeral */ - v = (f & 4) ? (ULONG)va_arg(arp, long) : ((d == 'D') ? (ULONG)(long)va_arg(arp, int) : (ULONG)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' : ' '; - chc = 0; - while (!(f & 2) && j++ < w) chc += (cc = f_putc(d, fp)); - do chc += (cc = f_putc(s[--i], fp)); while(i); - while (j++ < w) chc += (cc = f_putc(' ', fp)); - if (cc != EOF) cc = chc; - } - - va_end(arp); - return (cc == EOF) ? cc : res; -} - -#endif /* !_FS_READONLY */ -#endif /* _USE_STRFUNC */ - -#endif // CFG_TUH_MSC diff --git a/lib/fatfs/ff.h b/lib/fatfs/ff.h deleted file mode 100644 index 5c2a611ae..000000000 --- a/lib/fatfs/ff.h +++ /dev/null @@ -1,342 +0,0 @@ -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module include file R0.09b (C)ChaN, 2013 -/----------------------------------------------------------------------------/ -/ 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) 2013, 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. -/ -/----------------------------------------------------------------------------*/ - -#ifndef _FATFS -#define _FATFS 82786 /* Revision ID */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "integer.h" /* Basic integer types */ -#include "ffconf.h" /* FatFs configuration options */ -#include "tusb_config.h" - -#if _FATFS != _FFCONF -#error Wrong configuration file (ffconf.h). -#endif - - - -/* Definitions of volume management */ - -#if _MULTI_PARTITION /* Multiple partition configuration */ -typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ -} PARTITION; -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) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ -#define LD2PT(vol) 0 /* Always mounts the 1st partition or in SFD */ - -#endif - - - -/* Type of path name strings on FatFs API */ - -#if _LFN_UNICODE /* Unicode string */ -#if !_USE_LFN -#error _LFN_UNICODE must be 0 in non-LFN cfg. -#endif -#ifndef _INC_TCHAR -typedef WCHAR TCHAR; -#define _T(x) L ## x -#define _TEXT(x) L ## x -#endif - -#else /* ANSI/OEM string */ -#ifndef _INC_TCHAR -typedef char TCHAR; -#define _T(x) x -#define _TEXT(x) x -#endif - -#endif - - - -/* File system object structure (FATFS) */ - -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) */ - WORD id; /* File system mount ID */ - WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ -#if _MAX_SS != 512 - WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ -#endif -#if _FS_REENTRANT - _SYNC_t sobj; /* Identifier of sync object */ -#endif -#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 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) */ -} FATFS; - - - -/* File object structure (FIL) */ - -typedef struct { - 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; /* File status flags */ - BYTE pad1; - DWORD fptr; /* File read/write pointer (0ed on file open) */ - DWORD fsize; /* File size */ - DWORD sclust; /* File data start cluster (0:no data cluster, always 0 when fsize is 0) */ - DWORD clust; /* Current cluster of fpter */ - DWORD dsect; /* Current data sector of fpter */ -#if !_FS_READONLY - DWORD dir_sect; /* Sector containing the directory entry */ - BYTE* dir_ptr; /* Pointer to the directory entry in the window */ -#endif -#if _USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */ -#endif -#if _FS_LOCK - UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ -#endif -#if !_FS_TINY - BYTE buf[_MAX_SS]; /* File data read/write buffer */ -#endif -} FIL; - - - -/* Directory object structure (DIR) */ - -typedef struct { - 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 _USE_LFN - WCHAR* lfn; /* Pointer to the LFN working buffer */ - WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ -#endif -} DIR; - - - -/* File status structure (FILINFO) */ - -typedef struct { - DWORD fsize; /* File size */ - WORD fdate; /* Last modified date */ - WORD ftime; /* Last modified time */ - BYTE fattrib; /* Attribute */ - TCHAR fname[13]; /* Short file name (8.3 format) */ -#if _USE_LFN - TCHAR* lfname; /* Pointer to the LFN buffer */ - UINT lfsize; /* Size of LFN buffer in TCHAR */ -#endif -} FILINFO; - - - -/* File function return code (FRESULT) */ - -typedef enum { - FR_OK = 0, /* (0) Succeeded */ - 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) 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 */ - FR_NOT_ENABLED, /* (12) The volume has no work area */ - 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 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 */ -} FRESULT; - - - -/*--------------------------------------------------------------*/ -/* FatFs module application interface */ - -FRESULT f_mount (BYTE vol, FATFS* fs); /* Mount/Unmount a logical drive */ -FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ -FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ -FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ -FRESULT f_close (FIL* fp); /* Close an open file object */ -FRESULT f_opendir (DIR* dj, const TCHAR* path); /* Open an existing directory */ -FRESULT f_readdir (DIR* dj, FILINFO* fno); /* Read a directory item */ -FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ -FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ -FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ -FRESULT f_truncate (FIL* fp); /* Truncate file */ -FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ -FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ -FRESULT f_mkdir (const TCHAR* path); /* Create a new directory */ -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_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ -FRESULT f_chdrive (BYTE drv); /* Change current drive */ -BYTE f_get_current_drive(void); -FRESULT f_chdir (const TCHAR* path); /* Change current directory */ -FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ -FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* sn); /* Get volume label */ -FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ -FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_mkfs (BYTE vol, BYTE sfd, UINT au); /* Create a file system on the drive */ -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_tell(fp) ((fp)->fptr) -#define f_size(fp) ((fp)->fsize) - -#ifndef EOF -#define EOF (-1) -#endif - - - - -/*--------------------------------------------------------------*/ -/* Additional user defined functions */ - -/* RTC function */ -#if !_FS_READONLY -DWORD get_fattime (void); -#endif - -/* Unicode support functions */ -#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 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 - - - - -/*--------------------------------------------------------------*/ -/* Flags and offset address */ - - -/* File access control and file status flags (FIL.flag) */ - -#define FA_READ 0x01 -#define FA_OPEN_EXISTING 0x00 -#define FA__ERROR 0x80 - -#if !_FS_READONLY -#define FA_WRITE 0x02 -#define FA_CREATE_NEW 0x04 -#define FA_CREATE_ALWAYS 0x08 -#define FA_OPEN_ALWAYS 0x10 -#define FA__WRITTEN 0x20 -#define FA__DIRTY 0x40 -#endif - - -/* FAT sub type (FATFS.fs_type) */ - -#define FS_FAT12 1 -#define FS_FAT16 2 -#define FS_FAT32 3 - - -/* File attribute bits for directory entry */ - -#define AM_RDO 0x01 /* Read only */ -#define AM_HID 0x02 /* Hidden */ -#define AM_SYS 0x04 /* System */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_DIR 0x10 /* Directory */ -#define AM_ARC 0x20 /* Archive */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - -/* Fast seek feature */ -#define CREATE_LINKMAP 0xFFFFFFFF - - - -/*--------------------------------*/ -/* Multi-byte word access macros */ - -#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) -#else /* Use byte-by-byte access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) -#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _FATFS */ diff --git a/lib/fatfs/ffconf.h b/lib/fatfs/ffconf.h deleted file mode 100644 index 782057ea4..000000000 --- a/lib/fatfs/ffconf.h +++ /dev/null @@ -1,193 +0,0 @@ -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.09b (C)ChaN, 2013 -/----------------------------------------------------------------------------/ -/ -/ CAUTION! Do not forget to make clean the project after any changes to -/ the configuration options. -/ -/----------------------------------------------------------------------------*/ -#ifndef _FFCONF -#define _FFCONF 82786 /* Revision ID */ - -#include "tusb_config.h" - -/*---------------------------------------------------------------------------/ -/ 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_FASTSEEK 0 /* 0:Disable or 1:Enable */ -/* To enable fast seek feature, set _USE_FASTSEEK to 1. */ - - -#define _USE_LABEL 1 /* 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 437 -/* 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 1 /* 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 2 /* 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 CFG_TUH_DEVICE_MAX -/* 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: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 HANDLE /* 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_LOCK 0 /* 0:Disable or >=1:Enable */ -/* To enable file lock control feature, set _FS_LOCK to 1 or greater. - The value defines how many files can be opened simultaneously. */ - - -#endif /* _FFCONFIG */ diff --git a/lib/fatfs/integer.h b/lib/fatfs/integer.h deleted file mode 100644 index f34f56d92..000000000 --- a/lib/fatfs/integer.h +++ /dev/null @@ -1,36 +0,0 @@ -/*-------------------------------------------*/ -/* Integer type definitions for FatFs module */ -/*-------------------------------------------*/ - -#ifndef _INTEGER -#define _INTEGER - -#ifdef _WIN32 /* FatFs development platform */ - -#include -#include - -#else /* Embedded platform */ - -/* These types must be 16-bit, 32-bit or larger integer */ -typedef int INT; -typedef unsigned int UINT; - -/* These types must be 8-bit integer */ -typedef unsigned char UCHAR; -typedef unsigned char BYTE; - -/* These types must be 16-bit integer */ -typedef short SHORT; -typedef unsigned short USHORT; -typedef unsigned short WORD; -typedef unsigned short WCHAR; - -/* These types must be 32-bit integer */ -typedef long LONG; -typedef unsigned long ULONG; -typedef unsigned long DWORD; - -#endif - -#endif diff --git a/lib/fatfs/source/ffconf.h b/lib/fatfs/source/ffconf.h index 80b20efa1..c99498cda 100644 --- a/lib/fatfs/source/ffconf.h +++ b/lib/fatfs/source/ffconf.h @@ -113,7 +113,7 @@ */ -#define FF_USE_LFN 0 +#define FF_USE_LFN 1 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / @@ -153,7 +153,7 @@ / on character encoding. When LFN is not enabled, these options have no effect. */ -#define FF_FS_RPATH 0 +#define FF_FS_RPATH 1 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. @@ -166,7 +166,7 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 1 +#define FF_VOLUMES 4 /* Number of volumes (logical drives) to be used. (1-10) */ -- cgit v1.3.1 From 083ed364ba6dcf5baa2fa2587f94060ef3b33a59 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 19 Nov 2022 13:56:33 +0700 Subject: add cd command --- examples/host/msc_file_explorer/src/msc_app.c | 50 +++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index a8603c9df..76308cf5b 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -57,6 +57,7 @@ static scsi_inquiry_resp_t inquiry_resp; //--------------------------------------------------------------------+ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); void cli_write_char(EmbeddedCli *cli, char c) { @@ -67,7 +68,7 @@ void cli_write_char(EmbeddedCli *cli, char c) void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command) { (void) cli; - printf("Unknown commands: %s\r\n", command->name); + printf("%s: command not found\r\n", command->name); } bool msc_app_init(void) @@ -90,14 +91,23 @@ bool msc_app_init(void) _cli->writeChar = cli_write_char; + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "cd", + "Usage: cd [DIR]...\r\n\tChange the current directory to DIR.", + true, + NULL, + cli_cmd_cd + }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { "ls", - "Usage: ls [FILE]...\r\n\tList information about the FILEs (the current directory by default).", + "Usage: ls [DIR]...\r\n\tList information about the FILEs (the current directory by default).", true, NULL, cli_cmd_ls }); + return true; } @@ -304,7 +314,11 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) uint16_t argc = embeddedCliGetTokenCount(args); // only support 1 argument - if ( argc > 1 ) return; + if ( argc > 1 ) + { + printf("invalid arguments\r\n"); + return; + } // default is current directory const char* dpath = "."; @@ -313,7 +327,7 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) DIR dir; if ( FR_OK != f_opendir(&dir, dpath) ) { - printf("cannot access '%s': No such file or directory", dpath); + printf("cannot access '%s': No such file or directory\r\n", dpath); return; } @@ -325,13 +339,37 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) if ( fno.fattrib & AM_DIR ) { // directory - printf("/%s\n", fno.fname); + printf("/%s\r\n", fno.fname); }else { - printf("%-40s%lu KB\n", fno.fname, fno.fsize / 1000); + printf("%-40s%lu KB\r\n", fno.fname, fno.fsize / 1000); } } } f_closedir(&dir); } + +void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; + (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + + // only support 1 argument + if ( argc != 1 ) + { + printf("invalid arguments\r\n"); + return; + } + + // default is current directory + const char* dpath = args; + + if ( FR_OK != f_chdir(dpath) ) + { + printf("%s: No such file or directory\r\n", dpath); + return; + } +} -- cgit v1.3.1 From 16e18388624bbb83f582c016cf4768875ed44b3d Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 19 Nov 2022 15:27:07 +0700 Subject: implement cat command --- examples/host/msc_file_explorer/src/msc_app.c | 75 +++++++++++++++++++++++---- lib/fatfs/source/ffconf.h | 2 +- 2 files changed, 67 insertions(+), 10 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 76308cf5b..83074d89a 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -23,6 +23,7 @@ * */ +#include #include "tusb.h" #include "ff.h" @@ -32,6 +33,7 @@ #define EMBEDDED_CLI_IMPL #include "embedded_cli.h" + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ @@ -58,6 +60,7 @@ static scsi_inquiry_resp_t inquiry_resp; void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context); void cli_write_char(EmbeddedCli *cli, char c) { @@ -91,6 +94,14 @@ bool msc_app_init(void) _cli->writeChar = cli_write_char; + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "cat", + "Usage: cat [FILE]...\r\n\tConcatenate FILE(s) to standard output..", + true, + NULL, + cli_cmd_cat + }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { "cd", "Usage: cd [DIR]...\r\n\tChange the current directory to DIR.", @@ -115,13 +126,16 @@ void msc_app_task(void) { if (!_cli) return; - int ch; - while( (ch = getchar()) > 0 ) + int ch = getchar(); + if ( ch > 0 ) { - embeddedCliReceiveChar(_cli, (char) ch); + while( ch > 0 ) + { + embeddedCliReceiveChar(_cli, (char) ch); + ch = getchar(); + } + embeddedCliProcess(_cli); } - - embeddedCliProcess(_cli); } //--------------------------------------------------------------------+ @@ -308,8 +322,7 @@ DRESULT disk_ioctl ( void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) { - (void) cli; - (void) context; + (void) cli; (void) context; uint16_t argc = embeddedCliGetTokenCount(args); @@ -352,8 +365,7 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) { - (void) cli; - (void) context; + (void) cli; (void) context; uint16_t argc = embeddedCliGetTokenCount(args); @@ -373,3 +385,48 @@ void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) return; } } + +void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + + // need at least 1 argument + if ( argc == 0 ) + { + printf("invalid arguments\r\n"); + return; + } + + for(uint16_t i=0; i 0) ) + { + for(size_t c = 0; c < count; c++) + { + const char ch = buf[c]; + if (isprint(ch) || iscntrl(ch)) + { + putchar(ch); + }else + { + putchar('.'); + } + } + } + } + + f_close(&fi); + } +} diff --git a/lib/fatfs/source/ffconf.h b/lib/fatfs/source/ffconf.h index c99498cda..9298ef897 100644 --- a/lib/fatfs/source/ffconf.h +++ b/lib/fatfs/source/ffconf.h @@ -237,7 +237,7 @@ / Note that enabling exFAT discards ANSI C (C89) compatibility. */ -#define FF_FS_NORTC 0 +#define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 #define FF_NORTC_YEAR 2022 -- cgit v1.3.1 From daeaea9556a8175f554375e5d6845bf0caaf3859 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 19 Nov 2022 15:37:23 +0700 Subject: add mkdir --- examples/host/msc_file_explorer/src/msc_app.c | 135 ++++++++++++++++---------- 1 file changed, 84 insertions(+), 51 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 83074d89a..415e7c94e 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -39,11 +39,11 @@ //--------------------------------------------------------------------+ //------------- embedded-cli -------------// -#define CLI_BUFFER_SIZE 256 +#define CLI_BUFFER_SIZE 512 #define CLI_RX_BUFFER_SIZE 16 #define CLI_CMD_BUFFER_SIZE 32 #define CLI_HISTORY_SIZE 32 -#define CLI_BINDING_COUNT 3 +#define CLI_BINDING_COUNT 8 static EmbeddedCli *_cli; static CLI_UINT cli_buffer[BYTES_TO_CLI_UINTS(CLI_BUFFER_SIZE)]; @@ -58,9 +58,10 @@ static scsi_inquiry_resp_t inquiry_resp; // //--------------------------------------------------------------------+ -void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context); void cli_write_char(EmbeddedCli *cli, char c) { @@ -89,6 +90,8 @@ bool msc_app_init(void) config->historyBufferSize = CLI_HISTORY_SIZE; config->maxBindingCount = CLI_BINDING_COUNT; + TU_ASSERT(embeddedCliRequiredSize(config) <= CLI_BUFFER_SIZE); + _cli = embeddedCliNew(config); TU_ASSERT(_cli != NULL); @@ -118,6 +121,13 @@ bool msc_app_init(void) cli_cmd_ls }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "mkdir", + "Usage: mkdir [DIR]...\r\n\tCreate the DIRECTORY(ies), if they do not already exist..", + true, + NULL, + cli_cmd_mkdir + }); return true; } @@ -320,6 +330,74 @@ DRESULT disk_ioctl ( // CLI Commands //--------------------------------------------------------------------+ +void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + + // need at least 1 argument + if ( argc == 0 ) + { + printf("invalid arguments\r\n"); + return; + } + + for(uint16_t i=0; i 0) ) + { + for(size_t c = 0; c < count; c++) + { + const char ch = buf[c]; + if (isprint(ch) || iscntrl(ch)) + { + putchar(ch); + }else + { + putchar('.'); + } + } + } + } + + f_close(&fi); + } +} + +void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + + // only support 1 argument + if ( argc != 1 ) + { + printf("invalid arguments\r\n"); + return; + } + + // default is current directory + const char* dpath = args; + + if ( FR_OK != f_chdir(dpath) ) + { + printf("%s: No such file or directory\r\n", dpath); + return; + } +} + void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) { (void) cli; (void) context; @@ -363,7 +441,7 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) f_closedir(&dir); } -void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) +void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context) { (void) cli; (void) context; @@ -379,54 +457,9 @@ void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) // default is current directory const char* dpath = args; - if ( FR_OK != f_chdir(dpath) ) + if ( FR_OK != f_mkdir(dpath) ) { - printf("%s: No such file or directory\r\n", dpath); + printf("%s: cannot create this directory\r\n", dpath); return; } } - -void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context) -{ - (void) cli; (void) context; - - uint16_t argc = embeddedCliGetTokenCount(args); - - // need at least 1 argument - if ( argc == 0 ) - { - printf("invalid arguments\r\n"); - return; - } - - for(uint16_t i=0; i 0) ) - { - for(size_t c = 0; c < count; c++) - { - const char ch = buf[c]; - if (isprint(ch) || iscntrl(ch)) - { - putchar(ch); - }else - { - putchar('.'); - } - } - } - } - - f_close(&fi); - } -} -- cgit v1.3.1 From bf69ffb8f7cf2068baff34a197b6770332ddb794 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 19 Nov 2022 15:53:55 +0700 Subject: add mv command --- examples/host/msc_file_explorer/src/msc_app.c | 176 ++++++++++++++++---------- 1 file changed, 111 insertions(+), 65 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 415e7c94e..f435e6b96 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -41,7 +41,7 @@ //------------- embedded-cli -------------// #define CLI_BUFFER_SIZE 512 #define CLI_RX_BUFFER_SIZE 16 -#define CLI_CMD_BUFFER_SIZE 32 +#define CLI_CMD_BUFFER_SIZE 64 #define CLI_HISTORY_SIZE 32 #define CLI_BINDING_COUNT 8 @@ -58,22 +58,7 @@ static scsi_inquiry_resp_t inquiry_resp; // //--------------------------------------------------------------------+ -void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); -void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context); -void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); -void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context); - -void cli_write_char(EmbeddedCli *cli, char c) -{ - (void) cli; - putchar((int) c); -} - -void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command) -{ - (void) cli; - printf("%s: command not found\r\n", command->name); -} +bool cli_init(void); bool msc_app_init(void) { @@ -81,53 +66,7 @@ bool msc_app_init(void) // disable stdout buffered for echoing typing command setbuf(stdout, NULL); - - EmbeddedCliConfig *config = embeddedCliDefaultConfig(); - config->cliBuffer = cli_buffer; - config->cliBufferSize = CLI_BUFFER_SIZE; - config->rxBufferSize = CLI_RX_BUFFER_SIZE; - config->cmdBufferSize = CLI_CMD_BUFFER_SIZE; - config->historyBufferSize = CLI_HISTORY_SIZE; - config->maxBindingCount = CLI_BINDING_COUNT; - - TU_ASSERT(embeddedCliRequiredSize(config) <= CLI_BUFFER_SIZE); - - _cli = embeddedCliNew(config); - TU_ASSERT(_cli != NULL); - - _cli->writeChar = cli_write_char; - - embeddedCliAddBinding(_cli, (CliCommandBinding) { - "cat", - "Usage: cat [FILE]...\r\n\tConcatenate FILE(s) to standard output..", - true, - NULL, - cli_cmd_cat - }); - - embeddedCliAddBinding(_cli, (CliCommandBinding) { - "cd", - "Usage: cd [DIR]...\r\n\tChange the current directory to DIR.", - true, - NULL, - cli_cmd_cd - }); - - embeddedCliAddBinding(_cli, (CliCommandBinding) { - "ls", - "Usage: ls [DIR]...\r\n\tList information about the FILEs (the current directory by default).", - true, - NULL, - cli_cmd_ls - }); - - embeddedCliAddBinding(_cli, (CliCommandBinding) { - "mkdir", - "Usage: mkdir [DIR]...\r\n\tCreate the DIRECTORY(ies), if they do not already exist..", - true, - NULL, - cli_cmd_mkdir - }); + cli_init(); return true; } @@ -330,6 +269,84 @@ DRESULT disk_ioctl ( // CLI Commands //--------------------------------------------------------------------+ +void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context); + +void cli_write_char(EmbeddedCli *cli, char c) +{ + (void) cli; + putchar((int) c); +} + +void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command) +{ + (void) cli; + printf("%s: command not found\r\n", command->name); +} + +bool cli_init(void) +{ + EmbeddedCliConfig *config = embeddedCliDefaultConfig(); + config->cliBuffer = cli_buffer; + config->cliBufferSize = CLI_BUFFER_SIZE; + config->rxBufferSize = CLI_RX_BUFFER_SIZE; + config->cmdBufferSize = CLI_CMD_BUFFER_SIZE; + config->historyBufferSize = CLI_HISTORY_SIZE; + config->maxBindingCount = CLI_BINDING_COUNT; + + TU_ASSERT(embeddedCliRequiredSize(config) <= CLI_BUFFER_SIZE); + + _cli = embeddedCliNew(config); + TU_ASSERT(_cli != NULL); + + _cli->writeChar = cli_write_char; + + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "cat", + "Usage: cat [FILE]...\r\n\tConcatenate FILE(s) to standard output..", + true, + NULL, + cli_cmd_cat + }); + + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "cd", + "Usage: cd [DIR]...\r\n\tChange the current directory to DIR.", + true, + NULL, + cli_cmd_cd + }); + + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "ls", + "Usage: ls [DIR]...\r\n\tList information about the FILEs (the current directory by default).", + true, + NULL, + cli_cmd_ls + }); + + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "mkdir", + "Usage: mkdir DIR...\r\n\tCreate the DIRECTORY(ies), if they do not already exist..", + true, + NULL, + cli_cmd_mkdir + }); + + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "mv", + "Usage: mv SOURCE DEST...\r\n\tRename SOURCE to DEST", + true, + NULL, + cli_cmd_mv + }); + + return true; +} + void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context) { (void) cli; (void) context; @@ -433,7 +450,14 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) printf("/%s\r\n", fno.fname); }else { - printf("%-40s%lu KB\r\n", fno.fname, fno.fsize / 1000); + printf("%-40s", fno.fname); + if (fno.fsize < 1024) + { + printf("%lu B\r\n", fno.fsize); + }else + { + printf("%lu KB\r\n", fno.fsize / 1024); + } } } } @@ -463,3 +487,25 @@ void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context) return; } } + +void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + if ( argc != 2 ) + { + printf("invalid arguments\r\n"); + return; + } + + // default is current directory + const char* src = embeddedCliGetToken(args, 1); + const char* dst = embeddedCliGetToken(args, 2); + + if ( FR_OK != f_rename(src, dst) ) + { + printf("cannot mv %s to %s\r\n", src, dst); + return; + } +} -- cgit v1.3.1 From 2312bfe3c4be116403974f922d08e5f5cf8a166c Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 20 Nov 2022 16:40:15 +0700 Subject: implement cp command --- examples/host/msc_file_explorer/src/msc_app.c | 61 ++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index f435e6b96..5b9b72d43 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -269,8 +269,9 @@ DRESULT disk_ioctl ( // CLI Commands //--------------------------------------------------------------------+ -void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context); void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context); void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context); @@ -320,6 +321,14 @@ bool cli_init(void) cli_cmd_cd }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "cp", + "Usage: cp SOURCE DEST\r\n\tCopy SOURCE to DEST.", + true, + NULL, + cli_cmd_cp + }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { "ls", "Usage: ls [DIR]...\r\n\tList information about the FILEs (the current directory by default).", @@ -370,7 +379,7 @@ void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context) printf("%s: No such file or directory\r\n", fpath); }else { - uint8_t buf[64]; + uint8_t buf[512]; size_t count = 0; while ( (FR_OK == f_read(&fi, buf, sizeof(buf), &count)) && (count > 0) ) { @@ -415,6 +424,54 @@ void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context) } } +void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + if ( argc != 2 ) + { + printf("invalid arguments\r\n"); + return; + } + + // default is current directory + const char* src = embeddedCliGetToken(args, 1); + const char* dst = embeddedCliGetToken(args, 2); + + FIL f_src; + FIL f_dst; + + if ( FR_OK != f_open(&f_src, src, FA_READ) ) + { + printf("cannot stat '%s': No such file or directory\r\n", src); + return; + } + + if ( FR_OK != f_open(&f_dst, dst, FA_WRITE | FA_CREATE_ALWAYS) ) + { + printf("cannot create '%s'\r\n", dst); + return; + }else + { + uint8_t buf[512]; + size_t rd_count = 0; + while ( (FR_OK == f_read(&f_src, buf, sizeof(buf), &rd_count)) && (rd_count > 0) ) + { + size_t wr_count = 0; + + if ( FR_OK != f_write(&f_dst, buf, rd_count, &wr_count) ) + { + printf("cannot write to '%s'\r\n", dst); + break; + } + } + } + + f_close(&f_src); + f_close(&f_dst); +} + void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) { (void) cli; (void) context; -- cgit v1.3.1 From 47bc269b50eb0fab9ac2f708cecdce2e2df601d9 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 21 Nov 2022 11:12:10 +0700 Subject: fix build with rp2040 and rx65 --- examples/host/msc_file_explorer/CMakeLists.txt | 7 ++++++- examples/host/msc_file_explorer/src/msc_app.c | 16 ++++++++-------- examples/make.mk | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt index fc4765cdc..5d443ea9b 100644 --- a/examples/host/msc_file_explorer/CMakeLists.txt +++ b/examples/host/msc_file_explorer/CMakeLists.txt @@ -16,11 +16,16 @@ add_executable(${PROJECT}) target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c + ${TOP}/lib/fatfs/source/ff.c + ${TOP}/lib/fatfs/source/ffsystem.c + ${TOP}/lib/fatfs/source/ffunicode.c ) # Example include target_include_directories(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src + ${TOP}/lib/fatfs/source + ${TOP}/lib/embedded-cli ) # Configure compilation flags and libraries for the example... see the corresponding function @@ -30,7 +35,7 @@ family_configure_host_example(${PROJECT}) # For rp2040, un-comment to enable pico-pio-usb family_add_pico_pio_usb(${PROJECT}) -# due to warnings from Pico-PIO-USB +# due to warnings from Pico-PIO-USB and fatfs target_compile_options(${PROJECT} PUBLIC -Wno-error=shadow -Wno-error=cast-align diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 5b9b72d43..a1822b422 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -205,7 +205,7 @@ DRESULT disk_read ( uint8_t const lun = 0; _disk_busy[pdrv] = true; - tuh_msc_read10(dev_addr, lun, buff, sector, count, disk_io_complete); + tuh_msc_read10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete); wait_for_disk_io(pdrv); return RES_OK; @@ -224,7 +224,7 @@ DRESULT disk_write ( uint8_t const lun = 0; _disk_busy[pdrv] = true; - tuh_msc_write10(dev_addr, lun, buff, sector, count, disk_io_complete); + tuh_msc_write10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete); wait_for_disk_io(pdrv); return RES_OK; @@ -247,11 +247,11 @@ DRESULT disk_ioctl ( return RES_OK; case GET_SECTOR_COUNT: - *((DWORD*) buff) = tuh_msc_get_block_count(dev_addr, lun); + *((DWORD*) buff) = (WORD) tuh_msc_get_block_count(dev_addr, lun); return RES_OK; case GET_SECTOR_SIZE: - *((WORD*) buff) = tuh_msc_get_block_size(dev_addr, lun); + *((WORD*) buff) = (WORD) tuh_msc_get_block_size(dev_addr, lun); return RES_OK; case GET_BLOCK_SIZE: @@ -380,10 +380,10 @@ void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context) }else { uint8_t buf[512]; - size_t count = 0; + UINT count = 0; while ( (FR_OK == f_read(&fi, buf, sizeof(buf), &count)) && (count > 0) ) { - for(size_t c = 0; c < count; c++) + for(UINT c = 0; c < count; c++) { const char ch = buf[c]; if (isprint(ch) || iscntrl(ch)) @@ -455,10 +455,10 @@ void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context) }else { uint8_t buf[512]; - size_t rd_count = 0; + UINT rd_count = 0; while ( (FR_OK == f_read(&f_src, buf, sizeof(buf), &rd_count)) && (rd_count > 0) ) { - size_t wr_count = 0; + UINT wr_count = 0; if ( FR_OK != f_write(&f_dst, buf, rd_count, &wr_count) ) { diff --git a/examples/make.mk b/examples/make.mk index 47520d660..73a39a8fe 100644 --- a/examples/make.mk +++ b/examples/make.mk @@ -113,7 +113,8 @@ CFLAGS += \ # Debugging/Optimization ifeq ($(DEBUG), 1) - CFLAGS += -Og + CFLAGS += -O0 + NO_LTO = 1 else CFLAGS += $(CFLAGS_OPTIMIZED) endif -- cgit v1.3.1 From 51873cd1be5291c15a24054e464d98d4953eebfa Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 21 Nov 2022 11:24:58 +0700 Subject: implement rm command --- examples/host/msc_file_explorer/src/msc_app.c | 35 ++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index a1822b422..4500aedd2 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -275,6 +275,7 @@ void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context); void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context); void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context); void cli_write_char(EmbeddedCli *cli, char c) { @@ -347,12 +348,20 @@ bool cli_init(void) embeddedCliAddBinding(_cli, (CliCommandBinding) { "mv", - "Usage: mv SOURCE DEST...\r\n\tRename SOURCE to DEST", + "Usage: mv SOURCE DEST...\r\n\tRename SOURCE to DEST.", true, NULL, cli_cmd_mv }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "rm", + "Usage: rm [FILE]...\r\n\tRemove (unlink) the FILE(s).", + true, + NULL, + cli_cmd_rm + }); + return true; } @@ -566,3 +575,27 @@ void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context) return; } } + +void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + + uint16_t argc = embeddedCliGetTokenCount(args); + + // need at least 1 argument + if ( argc == 0 ) + { + printf("invalid arguments\r\n"); + return; + } + + for(uint16_t i=0; i Date: Mon, 21 Nov 2022 11:52:51 +0700 Subject: add pwd --- examples/host/msc_file_explorer/src/main.c | 8 ++--- examples/host/msc_file_explorer/src/msc_app.c | 43 ++++++++++++++++++++++++--- lib/fatfs/source/ffconf.h | 2 +- 3 files changed, 43 insertions(+), 10 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c index f46e5092b..652986b7c 100644 --- a/examples/host/msc_file_explorer/src/main.c +++ b/examples/host/msc_file_explorer/src/main.c @@ -43,7 +43,7 @@ int main(void) { board_init(); - printf("TinyUSB Host MSC Explorer Example\r\n"); + printf("TinyUSB Host MassStorage Explorer Example\r\n"); // init host stack on configured roothub port tuh_init(BOARD_TUH_RHPORT); @@ -67,14 +67,12 @@ int main(void) void tuh_mount_cb(uint8_t dev_addr) { - // application set-up - printf("A device with address %d is mounted\r\n", dev_addr); + (void) dev_addr; } void tuh_umount_cb(uint8_t dev_addr) { - // application tear-down - printf("A device with address %d is unmounted \r\n", dev_addr); + (void) dev_addr; } diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 4500aedd2..6e5cb672a 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -108,7 +108,7 @@ bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size)); - printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + // printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); // For simplicity: we only mount 1 LUN per device uint8_t const drive_num = dev_addr-1; @@ -120,8 +120,15 @@ bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const puts("mount failed"); } - f_chdrive(drive_path); // change to newly mounted drive - f_chdir("/"); // root as current dir + // change to newly mounted drive + f_chdir(drive_path); + + // print the drive label +// char label[34]; +// if ( FR_OK == f_getlabel(drive_path, label, NULL) ) +// { +// puts(label); +// } return true; } @@ -137,7 +144,6 @@ void tuh_msc_mount_cb(uint8_t dev_addr) void tuh_msc_umount_cb(uint8_t dev_addr) { - (void) dev_addr; printf("A MassStorage device is unmounted\r\n"); uint8_t const drive_num = dev_addr-1; @@ -273,6 +279,7 @@ void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context); void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context); void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context); void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context); +void cli_cmd_pwd(EmbeddedCli *cli, char *args, void *context); void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context); void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context); void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context); @@ -338,6 +345,14 @@ bool cli_init(void) cli_cmd_ls }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { + "pwd", + "Usage: pwd\r\n\tPrint the name of the current working directory.", + true, + NULL, + cli_cmd_pwd + }); + embeddedCliAddBinding(_cli, (CliCommandBinding) { "mkdir", "Usage: mkdir DIR...\r\n\tCreate the DIRECTORY(ies), if they do not already exist..", @@ -531,6 +546,26 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) f_closedir(&dir); } +void cli_cmd_pwd(EmbeddedCli *cli, char *args, void *context) +{ + (void) cli; (void) context; + uint16_t argc = embeddedCliGetTokenCount(args); + + if (argc != 0) + { + printf("invalid arguments\r\n"); + return; + } + + char path[256]; + if (FR_OK != f_getcwd(path, sizeof(path))) + { + printf("cannot get current working directory\r\n"); + } + + puts(path); +} + void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context) { (void) cli; (void) context; diff --git a/lib/fatfs/source/ffconf.h b/lib/fatfs/source/ffconf.h index 9298ef897..96ff77155 100644 --- a/lib/fatfs/source/ffconf.h +++ b/lib/fatfs/source/ffconf.h @@ -153,7 +153,7 @@ / on character encoding. When LFN is not enabled, these options have no effect. */ -#define FF_FS_RPATH 1 +#define FF_FS_RPATH 2 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. -- cgit v1.3.1 From 53677d484419d292f1a4841a5c928baddeb1c28a Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 21 Nov 2022 12:28:33 +0700 Subject: house keeping --- examples/dual/host_hid_to_device_cdc/CMakeLists.txt | 2 +- examples/host/CMakeLists.txt | 2 ++ examples/host/bare_api/Makefile | 3 --- examples/host/cdc_msc_hid/Makefile | 9 +++++---- examples/host/hid_controller/Makefile | 3 --- examples/host/msc_file_explorer/Makefile | 3 --- 6 files changed, 8 insertions(+), 14 deletions(-) (limited to 'examples/host') diff --git a/examples/dual/host_hid_to_device_cdc/CMakeLists.txt b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt index fc9bbfc13..724d1e119 100644 --- a/examples/dual/host_hid_to_device_cdc/CMakeLists.txt +++ b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt @@ -27,7 +27,7 @@ target_include_directories(${PROJECT} PUBLIC # in hw/bsp/FAMILY/family.cmake for details. family_configure_dual_usb_example(${PROJECT}) -# due to warnings from other net source, we need to prevent error from some of the warnings options +# due to warnings from Pico-PIO-USB target_compile_options(${PROJECT} PUBLIC -Wno-error=shadow -Wno-error=cast-align diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt index 5c63ec0c0..758973ab2 100644 --- a/examples/host/CMakeLists.txt +++ b/examples/host/CMakeLists.txt @@ -6,5 +6,7 @@ project(tinyusb_host_examples) family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR}) # family_add_subdirectory will filter what to actually add based on selected FAMILY +family_add_subdirectory(bare_api) family_add_subdirectory(cdc_msc_hid) family_add_subdirectory(hid_controller) +family_add_subdirectory(msc_file_explorer) diff --git a/examples/host/bare_api/Makefile b/examples/host/bare_api/Makefile index 13e14df53..84555a889 100644 --- a/examples/host/bare_api/Makefile +++ b/examples/host/bare_api/Makefile @@ -11,9 +11,6 @@ EXAMPLE_SOURCE += \ SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) -# TODO: suppress warning caused by host stack -CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference - # TinyUSB Host Stack source SRC_C += \ src/class/cdc/cdc_host.c \ diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile index 272acbac8..ad28076a0 100644 --- a/examples/host/cdc_msc_hid/Makefile +++ b/examples/host/cdc_msc_hid/Makefile @@ -6,11 +6,12 @@ INC += \ $(TOP)/hw \ # Example source -EXAMPLE_SOURCE += $(wildcard src/*.c) -SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) +EXAMPLE_SOURCE = \ + src/hid_app.c \ + src/main.c \ + src/msc_app.c \ -# TODO: suppress warning caused by host stack -CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference +SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) # TinyUSB Host Stack source SRC_C += \ diff --git a/examples/host/hid_controller/Makefile b/examples/host/hid_controller/Makefile index 06dc56914..e7fbd741f 100644 --- a/examples/host/hid_controller/Makefile +++ b/examples/host/hid_controller/Makefile @@ -12,9 +12,6 @@ EXAMPLE_SOURCE += \ SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) -# TODO: suppress warning caused by host stack -CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference - # TinyUSB Host Stack source SRC_C += \ src/class/cdc/cdc_host.c \ diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile index 518d75063..b0f9959fc 100644 --- a/examples/host/msc_file_explorer/Makefile +++ b/examples/host/msc_file_explorer/Makefile @@ -22,9 +22,6 @@ SRC_C += \ $(FATFS_PATH)/ffsystem.c \ $(FATFS_PATH)/ffunicode.c \ -# TODO: suppress warning caused by host stack -CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference - # TinyUSB Host Stack source SRC_C += \ src/class/cdc/cdc_host.c \ -- cgit v1.3.1 From ba9f88f18c222d9e74e483340ade4a420ad49f01 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 21 Nov 2022 12:33:31 +0700 Subject: suppress fatfs cast-qual --- examples/host/msc_file_explorer/Makefile | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile index b0f9959fc..de2f9c01c 100644 --- a/examples/host/msc_file_explorer/Makefile +++ b/examples/host/msc_file_explorer/Makefile @@ -22,6 +22,9 @@ SRC_C += \ $(FATFS_PATH)/ffsystem.c \ $(FATFS_PATH)/ffunicode.c \ +# suppress warning caused by fatfs +CFLAGS += -Wno-error=cast-qual + # TinyUSB Host Stack source SRC_C += \ src/class/cdc/cdc_host.c \ -- cgit v1.3.1 From 460bef9dbb40d1c6990c1bfd2f8da48978550932 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 21 Nov 2022 15:49:38 +0700 Subject: host msc example work well with rp2040 pio-usb --- examples/device/board_test/src/main.c | 2 +- examples/host/cdc_msc_hid/CMakeLists.txt | 14 ++++++++++++- examples/host/cdc_msc_hid/src/main.c | 8 -------- examples/host/cdc_msc_hid/src/msc_app.c | 3 --- examples/host/cdc_msc_hid/src/tusb_config.h | 6 ++++++ examples/host/hid_controller/src/hid_app.c | 1 - examples/host/msc_file_explorer/src/main.c | 2 +- examples/host/msc_file_explorer/src/msc_app.c | 5 +++-- hw/bsp/board.h | 8 ++------ hw/bsp/rp2040/family.c | 29 +++++++++++++++------------ src/host/usbh.h | 2 +- 11 files changed, 43 insertions(+), 37 deletions(-) (limited to 'examples/host') diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c index 74beda55f..0289ca15f 100644 --- a/examples/device/board_test/src/main.c +++ b/examples/device/board_test/src/main.c @@ -69,7 +69,7 @@ int main(void) // echo uint8_t ch; - if ( board_uart_read(&ch, 1) ) + if ( board_uart_read(&ch, 1) > 0 ) { board_uart_write(&ch, 1); } diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index c4a4d8e63..5b44ef217 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -29,4 +29,16 @@ target_include_directories(${PROJECT} PUBLIC family_configure_host_example(${PROJECT}) # For rp2040, un-comment to enable pico-pio-usb -# family_add_pico_pio_usb(${PROJECT}) +family_add_pico_pio_usb(${PROJECT}) + +# due to warnings from Pico-PIO-USB +target_compile_options(${PROJECT} PUBLIC + -Wno-error=shadow + -Wno-error=cast-align + -Wno-error=cast-qual + -Wno-error=redundant-decls + -Wno-error=sign-conversion + -Wno-error=conversion + -Wno-error=sign-compare + -Wno-error=unused-function + ) diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 664cbf035..d26e41e8d 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -54,13 +54,8 @@ int main(void) tuh_task(); led_blinking_task(); -#if CFG_TUH_CDC cdc_task(); -#endif - -#if CFG_TUH_HID hid_app_task(); -#endif } return 0; @@ -69,7 +64,6 @@ int main(void) //--------------------------------------------------------------------+ // USB CDC //--------------------------------------------------------------------+ -#if CFG_TUH_CDC CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 }; // invoked ISR context @@ -90,8 +84,6 @@ void cdc_task(void) } -#endif - //--------------------------------------------------------------------+ // TinyUSB Callbacks //--------------------------------------------------------------------+ diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index 77a72052d..80a5eab6f 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -25,8 +25,6 @@ #include "tusb.h" -#if CFG_TUH_MSC - //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ @@ -103,4 +101,3 @@ void tuh_msc_umount_cb(uint8_t dev_addr) // } } -#endif diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 33f34315b..c515405cb 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -34,6 +34,12 @@ // Board Specific Configuration //--------------------------------------------------------------------+ +#if CFG_TUSB_MCU == OPT_MCU_RP2040 +// change to 1 if using pico-pio-usb as host controller for raspberry rp2040 +#define CFG_TUH_RPI_PIO_USB 0 +#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB +#endif + // RHPort number used for host can be defined by board.mk, default to port 0 #ifndef BOARD_TUH_RHPORT #define BOARD_TUH_RHPORT 0 diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c index 582e01959..75c91400e 100644 --- a/examples/host/hid_controller/src/hid_app.c +++ b/examples/host/hid_controller/src/hid_app.c @@ -162,7 +162,6 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); - } // check if different than 2 diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c index 652986b7c..ab2cfd498 100644 --- a/examples/host/msc_file_explorer/src/main.c +++ b/examples/host/msc_file_explorer/src/main.c @@ -35,6 +35,7 @@ //--------------------------------------------------------------------+ void led_blinking_task(void); +// from msc_app.c extern bool msc_app_init(void); extern void msc_app_task(void); @@ -75,7 +76,6 @@ void tuh_umount_cb(uint8_t dev_addr) (void) dev_addr; } - //--------------------------------------------------------------------+ // Blinking Task //--------------------------------------------------------------------+ diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 6e5cb672a..b7c9212ee 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -25,6 +25,7 @@ #include #include "tusb.h" +#include "bsp/board.h" #include "ff.h" #include "diskio.h" @@ -75,13 +76,13 @@ void msc_app_task(void) { if (!_cli) return; - int ch = getchar(); + int ch = board_uart_getchar(); if ( ch > 0 ) { while( ch > 0 ) { embeddedCliReceiveChar(_cli, (char) ch); - ch = getchar(); + ch = board_uart_getchar(); } embeddedCliProcess(_cli); } diff --git a/hw/bsp/board.h b/hw/bsp/board.h index 0826d7786..52c64a1cc 100644 --- a/hw/bsp/board.h +++ b/hw/bsp/board.h @@ -132,15 +132,11 @@ static inline void board_delay(uint32_t ms) } } +// stdio getchar() is blocking, this is non-blocking version for uart static inline int board_uart_getchar(void) { uint8_t c; - return board_uart_read(&c, 1) ? (int) c : (-1); -} - -static inline int board_uart_putchar(uint8_t c) -{ - return board_uart_write(&c, 1); + return ( board_uart_read(&c, 1) > 0 ) ? (int) c : (-1); } #ifdef __cplusplus diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c index ee5a73ff6..d78e2c754 100644 --- a/hw/bsp/rp2040/family.c +++ b/hw/bsp/rp2040/family.c @@ -121,16 +121,6 @@ static uart_inst_t *uart_inst; void board_init(void) { -#ifdef LED_PIN - bi_decl(bi_1pin_with_name(LED_PIN, "LED")); - gpio_init(LED_PIN); - gpio_set_dir(LED_PIN, GPIO_OUT); -#endif - - // Button -#ifndef BUTTON_BOOTSEL -#endif - #if CFG_TUH_RPI_PIO_USB || CFG_TUD_RPI_PIO_USB // Set the system clock to a multiple of 120mhz for bitbanging USB with pico-usb set_sys_clock_khz(120000, true); @@ -148,6 +138,16 @@ void board_init(void) tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg); #endif +#ifdef LED_PIN + bi_decl(bi_1pin_with_name(LED_PIN, "LED")); + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); +#endif + + // Button +#ifndef BUTTON_BOOTSEL +#endif + #if defined(UART_DEV) && defined(LIB_PICO_STDIO_UART) bi_decl(bi_2pins_with_func(UART_TX_PIN, UART_TX_PIN, GPIO_FUNC_UART)); uart_inst = uart_get_instance(UART_DEV); @@ -192,10 +192,13 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { #ifdef UART_DEV - for(int i=0;i Date: Mon, 21 Nov 2022 16:28:54 +0700 Subject: add board_getchar() for non-blocking getchar() --- examples/host/msc_file_explorer/src/msc_app.c | 4 ++-- hw/bsp/board.c | 7 +++++++ hw/bsp/board.h | 8 ++------ hw/bsp/rp2040/family.c | 5 +++++ 4 files changed, 16 insertions(+), 8 deletions(-) (limited to 'examples/host') diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index b7c9212ee..aa193f3ce 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -76,13 +76,13 @@ void msc_app_task(void) { if (!_cli) return; - int ch = board_uart_getchar(); + int ch = board_getchar(); if ( ch > 0 ) { while( ch > 0 ) { embeddedCliReceiveChar(_cli, (char) ch); - ch = board_uart_getchar(); + ch = board_getchar(); } embeddedCliProcess(_cli); } diff --git a/hw/bsp/board.c b/hw/bsp/board.c index a22b462d9..7e96735bd 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -106,6 +106,7 @@ TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) int rd = (int) SEGGER_RTT_Read(0, buf, count); return (rd > 0) ? rd : -1; } + #endif #elif defined(LOGGER_SWO) @@ -149,3 +150,9 @@ TU_ATTR_USED int sys_read (int fhdl, char *buf, size_t count) } #endif + +int board_getchar(void) +{ + char c; + return ( sys_read(0, &c, 1) > 0 ) ? (int) c : (-1); +} diff --git a/hw/bsp/board.h b/hw/bsp/board.h index 52c64a1cc..0a10294d0 100644 --- a/hw/bsp/board.h +++ b/hw/bsp/board.h @@ -132,12 +132,8 @@ static inline void board_delay(uint32_t ms) } } -// stdio getchar() is blocking, this is non-blocking version for uart -static inline int board_uart_getchar(void) -{ - uint8_t c; - return ( board_uart_read(&c, 1) > 0 ) ? (int) c : (-1); -} +// stdio getchar() is blocking, this is non-blocking version +int board_getchar(void); #ifdef __cplusplus } diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c index d78e2c754..26008168d 100644 --- a/hw/bsp/rp2040/family.c +++ b/hw/bsp/rp2040/family.c @@ -219,6 +219,11 @@ int board_uart_write(void const * buf, int len) #endif } +int board_getchar(void) +{ + return getchar_timeout_us(0); +} + //--------------------------------------------------------------------+ // USB Interrupt Handler // rp2040 implementation will install approriate handler when initializing -- cgit v1.3.1 From 21d552bbdff19abe3ab46b23468d719be5aa2a55 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Nov 2022 12:30:10 +0700 Subject: allow all host examples to use pico-pio-usb for rp2040 --- examples/host/bare_api/CMakeLists.txt | 17 +++++++++++++-- examples/host/bare_api/src/tusb_config.h | 6 ++++++ examples/host/cdc_msc_hid/CMakeLists.txt | 29 +++++++++++++------------- examples/host/hid_controller/CMakeLists.txt | 17 +++++++++++++-- examples/host/hid_controller/src/tusb_config.h | 6 ++++++ examples/host/msc_file_explorer/CMakeLists.txt | 29 +++++++++++++------------- 6 files changed, 72 insertions(+), 32 deletions(-) (limited to 'examples/host') diff --git a/examples/host/bare_api/CMakeLists.txt b/examples/host/bare_api/CMakeLists.txt index bc04b01a7..019adaacd 100644 --- a/examples/host/bare_api/CMakeLists.txt +++ b/examples/host/bare_api/CMakeLists.txt @@ -26,5 +26,18 @@ target_include_directories(${PROJECT} PUBLIC # in hw/bsp/FAMILY/family.cmake for details. family_configure_host_example(${PROJECT}) -# For rp2040, un-comment to enable pico-pio-usb -# family_add_pico_pio_usb(${PROJECT}) \ No newline at end of file +# For rp2040 enable pico-pio-usb +if(FAMILY STREQUAL "rp2040") + family_add_pico_pio_usb(${PROJECT}) + + # due to warnings from Pico-PIO-USB + target_compile_options(${PROJECT} PUBLIC + -Wno-error=shadow + -Wno-error=cast-align + -Wno-error=cast-qual + -Wno-error=redundant-decls + -Wno-error=sign-conversion + -Wno-error=conversion + -Wno-error=unused-function + ) +endif() \ No newline at end of file diff --git a/examples/host/bare_api/src/tusb_config.h b/examples/host/bare_api/src/tusb_config.h index ed0aaf7da..701aa6d90 100644 --- a/examples/host/bare_api/src/tusb_config.h +++ b/examples/host/bare_api/src/tusb_config.h @@ -34,6 +34,12 @@ // Board Specific Configuration //--------------------------------------------------------------------+ +#if CFG_TUSB_MCU == OPT_MCU_RP2040 +// change to 1 if using pico-pio-usb as host controller for raspberry rp2040 +#define CFG_TUH_RPI_PIO_USB 0 +#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB +#endif + // RHPort number used for host can be defined by board.mk, default to port 0 #ifndef BOARD_TUH_RHPORT #define BOARD_TUH_RHPORT 0 diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 5b44ef217..870134376 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -28,17 +28,18 @@ target_include_directories(${PROJECT} PUBLIC # in hw/bsp/FAMILY/family.cmake for details. family_configure_host_example(${PROJECT}) -# For rp2040, un-comment to enable pico-pio-usb -family_add_pico_pio_usb(${PROJECT}) - -# due to warnings from Pico-PIO-USB -target_compile_options(${PROJECT} PUBLIC - -Wno-error=shadow - -Wno-error=cast-align - -Wno-error=cast-qual - -Wno-error=redundant-decls - -Wno-error=sign-conversion - -Wno-error=conversion - -Wno-error=sign-compare - -Wno-error=unused-function - ) +# For rp2040 enable pico-pio-usb +if(FAMILY STREQUAL "rp2040") + family_add_pico_pio_usb(${PROJECT}) + + # due to warnings from Pico-PIO-USB + target_compile_options(${PROJECT} PUBLIC + -Wno-error=shadow + -Wno-error=cast-align + -Wno-error=cast-qual + -Wno-error=redundant-decls + -Wno-error=sign-conversion + -Wno-error=conversion + -Wno-error=unused-function + ) +endif() diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt index 6153d399a..aea99e404 100644 --- a/examples/host/hid_controller/CMakeLists.txt +++ b/examples/host/hid_controller/CMakeLists.txt @@ -27,5 +27,18 @@ target_include_directories(${PROJECT} PUBLIC # in hw/bsp/FAMILY/family.cmake for details. family_configure_host_example(${PROJECT}) -# For rp2040, un-comment to enable pico-pio-usb -# family_add_pico_pio_usb(${PROJECT}) +# For rp2040 enable pico-pio-usb +if(FAMILY STREQUAL "rp2040") + family_add_pico_pio_usb(${PROJECT}) + + # due to warnings from Pico-PIO-USB + target_compile_options(${PROJECT} PUBLIC + -Wno-error=shadow + -Wno-error=cast-align + -Wno-error=cast-qual + -Wno-error=redundant-decls + -Wno-error=sign-conversion + -Wno-error=conversion + -Wno-error=unused-function + ) +endif() \ No newline at end of file diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h index 475b9ca8f..e6d6f873d 100644 --- a/examples/host/hid_controller/src/tusb_config.h +++ b/examples/host/hid_controller/src/tusb_config.h @@ -34,6 +34,12 @@ // Board Specific Configuration //--------------------------------------------------------------------+ + #if CFG_TUSB_MCU == OPT_MCU_RP2040 +// change to 1 if using pico-pio-usb as host controller for raspberry rp2040 +#define CFG_TUH_RPI_PIO_USB 0 +#define BOARD_TUH_RHPORT CFG_TUH_RPI_PIO_USB +#endif + // RHPort number used for host can be defined by board.mk, default to port 0 #ifndef BOARD_TUH_RHPORT #define BOARD_TUH_RHPORT 0 diff --git a/examples/host/msc_file_explorer/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt index 5d443ea9b..e51a170d3 100644 --- a/examples/host/msc_file_explorer/CMakeLists.txt +++ b/examples/host/msc_file_explorer/CMakeLists.txt @@ -32,17 +32,18 @@ target_include_directories(${PROJECT} PUBLIC # in hw/bsp/FAMILY/family.cmake for details. family_configure_host_example(${PROJECT}) -# For rp2040, un-comment to enable pico-pio-usb -family_add_pico_pio_usb(${PROJECT}) - -# due to warnings from Pico-PIO-USB and fatfs -target_compile_options(${PROJECT} PUBLIC - -Wno-error=shadow - -Wno-error=cast-align - -Wno-error=cast-qual - -Wno-error=redundant-decls - -Wno-error=sign-conversion - -Wno-error=conversion - -Wno-error=sign-compare - -Wno-error=unused-function - ) +# For rp2040 enable pico-pio-usb +if(FAMILY STREQUAL "rp2040") + family_add_pico_pio_usb(${PROJECT}) + + # due to warnings from Pico-PIO-USB + target_compile_options(${PROJECT} PUBLIC + -Wno-error=shadow + -Wno-error=cast-align + -Wno-error=cast-qual + -Wno-error=redundant-decls + -Wno-error=sign-conversion + -Wno-error=conversion + -Wno-error=unused-function + ) +endif() -- cgit v1.3.1 From 7298923927c2955fd67227e3941bde74a2f0c689 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Nov 2022 16:01:48 +0700 Subject: rework tuh_msc_complete_cb_t signature to use new tuh_msc_complete_data_t add user arg to all scsi command API that support complete callback --- examples/host/cdc_msc_hid/src/msc_app.c | 42 ++-------------- examples/host/msc_file_explorer/src/msc_app.c | 15 +++--- src/class/msc/msc_host.c | 69 +++++++++++++++++---------- src/class/msc/msc_host.h | 23 +++++---- 4 files changed, 74 insertions(+), 75 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index 80a5eab6f..797d55f8a 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -30,8 +30,11 @@ //--------------------------------------------------------------------+ static scsi_inquiry_resp_t inquiry_resp; -bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + if (csw->status != 0) { printf("Inquiry failed\r\n"); @@ -57,47 +60,12 @@ void tuh_msc_mount_cb(uint8_t dev_addr) printf("A MassStorage device is mounted\r\n"); uint8_t const lun = 0; - tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb); -// -// //------------- file system (only 1 LUN support) -------------// -// uint8_t phy_disk = dev_addr-1; -// disk_initialize(phy_disk); -// -// if ( disk_is_ready(phy_disk) ) -// { -// if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK ) -// { -// puts("mount failed"); -// return; -// } -// -// f_chdrive(phy_disk); // change to newly mounted drive -// f_chdir("/"); // root as current dir -// -// cli_init(); -// } + tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0); } void tuh_msc_umount_cb(uint8_t dev_addr) { (void) dev_addr; printf("A MassStorage device is unmounted\r\n"); - -// uint8_t phy_disk = dev_addr-1; -// -// f_mount(phy_disk, NULL); // unmount disk -// disk_deinitialize(phy_disk); -// -// if ( phy_disk == f_get_current_drive() ) -// { // active drive is unplugged --> change to other drive -// for(uint8_t i=0; icbw; + msc_csw_t const* csw = cb_data->csw; + if (csw->status != 0) { printf("Inquiry failed\r\n"); @@ -140,7 +143,7 @@ void tuh_msc_mount_cb(uint8_t dev_addr) printf("A MassStorage device is mounted\r\n"); uint8_t const lun = 0; - tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb); + tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0); } void tuh_msc_umount_cb(uint8_t dev_addr) @@ -178,9 +181,9 @@ static void wait_for_disk_io(BYTE pdrv) } } -static bool disk_io_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool disk_io_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { - (void) dev_addr; (void) cbw; (void) csw; + (void) dev_addr; (void) cb_data; _disk_busy[dev_addr-1] = false; return true; } @@ -212,7 +215,7 @@ DRESULT disk_read ( uint8_t const lun = 0; _disk_busy[pdrv] = true; - tuh_msc_read10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete); + tuh_msc_read10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete, 0); wait_for_disk_io(pdrv); return RES_OK; @@ -231,7 +234,7 @@ DRESULT disk_write ( uint8_t const lun = 0; _disk_busy[pdrv] = true; - tuh_msc_write10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete); + tuh_msc_write10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete, 0); wait_for_disk_io(pdrv); return RES_OK; diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 934f79ff7..9e88ebc30 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -64,6 +64,7 @@ typedef struct uint8_t stage; void* buffer; tuh_msc_complete_cb_t complete_cb; + uintptr_t complete_arg; msc_cbw_t cbw; msc_csw_t csw; @@ -126,7 +127,7 @@ static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) cbw->lun = lun; } -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -137,13 +138,14 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu p_msc->stage = MSC_STAGE_CMD; p_msc->buffer = data; p_msc->complete_cb = complete_cb; + p_msc->complete_arg = arg; TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); return true; } -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -156,10 +158,10 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r cbw.cmd_len = sizeof(scsi_read_capacity10_t); cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -178,10 +180,10 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons }; memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -195,10 +197,10 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_ cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; cbw.command[1] = lun; // according to wiki TODO need verification - return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg); } -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msc_cbw_t cbw; cbw_init(&cbw, lun); @@ -215,10 +217,10 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb, arg); } -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -239,10 +241,10 @@ bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, memcpy(cbw.command, &cmd_read10, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg); } -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -263,7 +265,7 @@ bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_ memcpy(cbw.command, &cmd_write10, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb); + return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg); } #if 0 @@ -344,7 +346,17 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 // SCSI op is complete p_msc->stage = MSC_STAGE_IDLE; - if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw); + if (p_msc->complete_cb) + { + tuh_msc_complete_data_t const cb_data = + { + .cbw = cbw, + .csw = csw, + .scsi_data = p_msc->buffer, + .user_arg = p_msc->complete_arg + }; + p_msc->complete_cb(dev_addr, &cb_data); + } break; // unknown state @@ -359,9 +371,9 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 //--------------------------------------------------------------------+ static void config_get_maxlun_complete (tuh_xfer_t* xfer); -static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data); +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { @@ -446,37 +458,46 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) // TODO multiple LUN support TU_LOG2("SCSI Test Unit Ready\r\n"); uint8_t const lun = 0; - tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete); + tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); } -static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + if (csw->status == 0) { // Unit is ready, read its capacity TU_LOG2("SCSI Read Capacity\r\n"); - tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete); + tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); }else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries TU_LOG2("SCSI Request Sense\r\n"); - TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete)); + TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); } return true; } -static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + TU_ASSERT(csw->status == 0); - TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete)); + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete, 0)); return true; } -static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { + msc_cbw_t const* cbw = cb_data->cbw; + msc_csw_t const* csw = cb_data->csw; + TU_ASSERT(csw->status == 0); msch_interface_t* p_msc = get_itf(dev_addr); diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 8d95980f9..416e4318b 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -41,7 +41,14 @@ #define CFG_TUH_MSC_MAXLUN 4 #endif -typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +typedef struct { + msc_cbw_t const* cbw; // SCSI command + msc_csw_t const* csw; // SCSI status + void* scsi_data; // SCSI Data + uintptr_t user_arg; // user argument +}tuh_msc_complete_data_t; + +typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); //--------------------------------------------------------------------+ // Application API @@ -66,33 +73,33 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); // Perform a full SCSI command (cbw, data, csw) in non-blocking manner. // Complete callback is invoked when SCSI op is complete. // return true if success, false if there is already pending operation. -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Inquiry command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Test Unit Ready command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Request Sense 10 command // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Write 10 command. Write n blocks starting from LBA to device // Complete callback is invoked when SCSI op is complete. -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Read Capacity 10 command // Complete callback is invoked when SCSI op is complete. // Note: during enumeration, host stack already carried out this request. Application can retrieve capacity by // simply call tuh_msc_get_block_count() and tuh_msc_get_block_size() -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); //------------- Application Callback -------------// -- cgit v1.3.1 From 5785467016f4f2d0f5e52cec70f4f2328a5d326a Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 28 Nov 2022 23:21:17 +0700 Subject: update pico-pio-usb submodule and its warnings suppress --- examples/host/bare_api/CMakeLists.txt | 4 ---- examples/host/cdc_msc_hid/CMakeLists.txt | 4 ---- examples/host/hid_controller/CMakeLists.txt | 4 ---- examples/host/msc_file_explorer/CMakeLists.txt | 4 ---- hw/mcu/raspberry_pi/Pico-PIO-USB | 2 +- 5 files changed, 1 insertion(+), 17 deletions(-) (limited to 'examples/host') diff --git a/examples/host/bare_api/CMakeLists.txt b/examples/host/bare_api/CMakeLists.txt index 019adaacd..31a8aa222 100644 --- a/examples/host/bare_api/CMakeLists.txt +++ b/examples/host/bare_api/CMakeLists.txt @@ -32,12 +32,8 @@ if(FAMILY STREQUAL "rp2040") # due to warnings from Pico-PIO-USB target_compile_options(${PROJECT} PUBLIC - -Wno-error=shadow - -Wno-error=cast-align -Wno-error=cast-qual - -Wno-error=redundant-decls -Wno-error=sign-conversion -Wno-error=conversion - -Wno-error=unused-function ) endif() \ No newline at end of file diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 870134376..d84457bc9 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -34,12 +34,8 @@ if(FAMILY STREQUAL "rp2040") # due to warnings from Pico-PIO-USB target_compile_options(${PROJECT} PUBLIC - -Wno-error=shadow - -Wno-error=cast-align -Wno-error=cast-qual - -Wno-error=redundant-decls -Wno-error=sign-conversion -Wno-error=conversion - -Wno-error=unused-function ) endif() diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt index aea99e404..39adf9093 100644 --- a/examples/host/hid_controller/CMakeLists.txt +++ b/examples/host/hid_controller/CMakeLists.txt @@ -33,12 +33,8 @@ if(FAMILY STREQUAL "rp2040") # due to warnings from Pico-PIO-USB target_compile_options(${PROJECT} PUBLIC - -Wno-error=shadow - -Wno-error=cast-align -Wno-error=cast-qual - -Wno-error=redundant-decls -Wno-error=sign-conversion -Wno-error=conversion - -Wno-error=unused-function ) endif() \ No newline at end of file diff --git a/examples/host/msc_file_explorer/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt index e51a170d3..326286b3f 100644 --- a/examples/host/msc_file_explorer/CMakeLists.txt +++ b/examples/host/msc_file_explorer/CMakeLists.txt @@ -38,12 +38,8 @@ if(FAMILY STREQUAL "rp2040") # due to warnings from Pico-PIO-USB target_compile_options(${PROJECT} PUBLIC - -Wno-error=shadow - -Wno-error=cast-align -Wno-error=cast-qual - -Wno-error=redundant-decls -Wno-error=sign-conversion -Wno-error=conversion - -Wno-error=unused-function ) endif() diff --git a/hw/mcu/raspberry_pi/Pico-PIO-USB b/hw/mcu/raspberry_pi/Pico-PIO-USB index f78dc9b2c..52805e6d9 160000 --- a/hw/mcu/raspberry_pi/Pico-PIO-USB +++ b/hw/mcu/raspberry_pi/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit f78dc9b2c7fa9b82587e43babdc1d21294a32985 +Subproject commit 52805e6d92556e67d3738bd8fb10227a45b13a08 -- cgit v1.3.1 From 6a2cf6728906aa61b44ecfe43b4ceef287b29bf8 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Sun, 4 Dec 2022 13:58:47 +0700 Subject: Fix typos --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- docs/contributing/porting.rst | 4 ++-- docs/info/changelog.rst | 22 +++++++++++----------- examples/device/cdc_msc/src/main.c | 2 +- examples/device/cdc_msc_freertos/CMakeLists.txt | 2 +- examples/device/dfu_runtime/src/main.c | 2 +- examples/device/hid_boot_interface/src/main.c | 6 +++--- examples/host/cdc_msc_hid/src/hid_app.c | 2 +- hw/bsp/ansi_escape.h | 2 +- .../led_strip/src/led_strip_rmt_ws2812.c | 2 +- .../led_strip/src/led_strip_rmt_ws2812.c | 2 +- hw/bsp/family_support.cmake | 4 ++-- hw/bsp/gd32vf103/family.c | 2 +- hw/bsp/gd32vf103/system_gd32vf103.c | 2 +- .../evkmimxrt1010_flexspi_nor_config.h | 10 +++++----- .../evkmimxrt1015_flexspi_nor_config.h | 10 +++++----- .../evkmimxrt1020_flexspi_nor_config.h | 10 +++++----- .../evkbimxrt1050_flexspi_nor_config.h | 10 +++++----- .../evkmimxrt1060_flexspi_nor_config.h | 10 +++++----- .../evkmimxrt1064_flexspi_nor_config.h | 10 +++++----- .../boards/teensy_40/teensy40_flexspi_nor_config.h | 10 +++++----- .../boards/teensy_41/teensy41_flexspi_nor_config.h | 10 +++++----- hw/bsp/imxrt/family.mk | 2 +- hw/bsp/lpc54/family.c | 4 ++-- hw/bsp/lpc55/family.c | 4 ++-- hw/bsp/mm32/boards/mm32f327x_mb39/flash.ld | 2 +- hw/bsp/rp2040/family.c | 2 +- .../stm32f070rbnucleo/stm32F070rbtx_flash.ld | 2 +- .../boards/stm32f072disco/STM32F072RBTx_FLASH.ld | 2 +- .../boards/stm32f103_bluepill/STM32F103X8_FLASH.ld | 2 +- .../boards/stm32f103_mini_2/STM32F103XC_FLASH.ld | 2 +- hw/bsp/stm32f207nucleo/STM32F207ZGTx_FLASH.ld | 2 +- hw/bsp/stm32f303disco/STM32F303VCTx_FLASH.ld | 2 +- .../feather_stm32f405/STM32F405RGTx_FLASH.ld | 2 +- .../boards/pyboardv11/STM32F405RGTx_FLASH.ld | 2 +- .../stm32f401blackpill/STM32F401VCTx_FLASH.ld | 2 +- hw/bsp/stm32f4/boards/stm32f401blackpill/board.h | 2 +- .../boards/stm32f407disco/STM32F407VGTx_FLASH.ld | 2 +- .../stm32f411blackpill/STM32F411CEUx_FLASH.ld | 2 +- hw/bsp/stm32f4/boards/stm32f411blackpill/board.h | 2 +- .../boards/stm32f411disco/STM32F411VETx_FLASH.ld | 2 +- .../boards/stm32f412disco/STM32F412ZGTx_FLASH.ld | 2 +- .../boards/stm32f412nucleo/STM32F412ZGTx_FLASH.ld | 2 +- .../boards/stlinkv3mini/STM32F723xE_FLASH.ld | 2 +- .../boards/stm32f723disco/STM32F723xE_FLASH.ld | 2 +- .../boards/stm32f746disco/STM32F746ZGTx_FLASH.ld | 2 +- .../boards/stm32f746nucleo/STM32F746ZGTx_FLASH.ld | 2 +- .../boards/stm32f767nucleo/STM32F767ZITx_FLASH.ld | 2 +- .../boards/stm32f769disco/STM32F769ZITx_FLASH.ld | 2 +- hw/bsp/stm32g4/boards/stm32g474nucleo/board.h | 4 ++-- .../boards/stm32h743eval/stm32h743xx_flash.ld | 2 +- .../boards/stm32h743nucleo/stm32h743xx_flash.ld | 2 +- .../waveshare_openh743i/STM32H743IITX_FLASH.ld | 2 +- hw/bsp/stm32h7/boards/waveshare_openh743i/board.h | 2 +- .../boards/stm32l052dap52/STM32L052K8Ux_FLASH.ld | 2 +- hw/bsp/stm32l0538disco/STM32L053C8Tx_FLASH.ld | 2 +- .../boards/stm32l476disco/STM32L476VGTx_FLASH.ld | 2 +- .../boards/stm32l4r5nucleo/STM32L4RXxI_FLASH.ld | 2 +- hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h | 4 ++-- hw/bsp/tm4c123/family.c | 2 +- lib/SEGGER_RTT/RTT/SEGGER_RTT.c | 2 +- lib/networking/dnserver.c | 8 ++++---- lib/networking/ndis.h | 2 +- lib/networking/rndis_reports.c | 2 +- src/class/cdc/cdc.h | 2 +- src/class/cdc/cdc_rndis_host.c | 2 +- src/class/hid/hid_host.h | 2 +- src/class/msc/msc_host.c | 4 ++-- src/class/msc/msc_host.h | 2 +- src/class/net/ecm_rndis_device.c | 2 +- src/class/usbtmc/usbtmc.h | 2 +- src/class/usbtmc/usbtmc_device.h | 2 +- src/common/tusb_fifo.c | 8 ++++---- src/common/tusb_fifo.h | 4 ++-- src/device/usbd.h | 2 +- src/host/usbh.c | 4 ++-- src/portable/bridgetek/ft9xx/dcd_ft9xx.c | 6 +++--- src/portable/ehci/ehci.c | 4 ++-- src/portable/ehci/ehci.h | 10 +++++----- src/portable/espressif/esp32sx/dcd_esp32sx.c | 2 +- src/portable/microchip/pic32mz/usbhs_registers.h | 6 +++--- src/portable/microchip/samx7x/dcd_samx7x.c | 6 +++--- src/portable/nuvoton/nuc505/dcd_nuc505.c | 2 +- src/portable/ohci/ohci.c | 2 +- src/portable/ohci/ohci.h | 2 +- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 2 +- src/portable/sunxi/dcd_sunxi_musb.c | 2 +- src/portable/sunxi/musb_def.h | 2 +- src/portable/synopsys/dwc2/dcd_dwc2.c | 2 +- src/portable/synopsys/dwc2/dwc2_stm32.h | 2 +- 90 files changed, 160 insertions(+), 160 deletions(-) (limited to 'examples/host') diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2958d3b12..8c39b95e1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -64,7 +64,7 @@ body: placeholder: | Attach your debug log txt file here, where the issue occurred, best with comments to explain the actual events. - Note1: Please DO NOT paste your lengthy log contents here since it hurts the readibility. + Note1: Please DO NOT paste your lengthy log contents here since it hurts the readability. Note2: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h. More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md) validations: diff --git a/docs/contributing/porting.rst b/docs/contributing/porting.rst index 7e9e462f0..710af51c3 100644 --- a/docs/contributing/porting.rst +++ b/docs/contributing/porting.rst @@ -195,7 +195,7 @@ Others (like the nRF52) may need each USB packet queued individually. To make th some state for yourself and queue up an intermediate USB packet from the interrupt handler. Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion. -During transmission, the IN data buffer is guarenteed to remain unchanged in memory until the ``dcd_xfer_complete`` function is called. +During transmission, the IN data buffer is guaranteed to remain unchanged in memory until the ``dcd_xfer_complete`` function is called. The dcd_edpt_xfer function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required, then it must be explicitly sent by the stack calling dcd_edpt_xfer(), by calling dcd_edpt_xfer() a second time with len=0. @@ -238,4 +238,4 @@ Use `WireShark `_ or `a Beagle PORTMODE |= USBFSH_PORTMODE_DEV_ENABLE_MASK; CLOCK_DisableClock(kCLOCK_Usbhsl0); /* disable usb0 host clock */ @@ -182,7 +182,7 @@ void board_init(void) // Port1 is High Speed POWER_DisablePD(kPDRUNCFG_PD_USB1_PHY); - /*According to reference mannual, device mode setting has to be set by access usb host register */ + /*According to reference manual, device mode setting has to be set by access usb host register */ CLOCK_EnableClock(kCLOCK_Usbh1); /* enable usb1 host clock */ USBHSH->PORTMODE |= USBHSH_PORTMODE_DEV_ENABLE_MASK; CLOCK_DisableClock(kCLOCK_Usbh1); /* enable usb1 host clock */ diff --git a/hw/bsp/lpc55/family.c b/hw/bsp/lpc55/family.c index e7aed5759..5b6c56dd3 100644 --- a/hw/bsp/lpc55/family.c +++ b/hw/bsp/lpc55/family.c @@ -192,7 +192,7 @@ void board_init(void) CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false); CLOCK_AttachClk(kFRO_HF_to_USB0_CLK); - /*According to reference mannual, device mode setting has to be set by access usb host register */ + /*According to reference manual, device mode setting has to be set by access usb host register */ CLOCK_EnableClock(kCLOCK_Usbhsl0); // enable usb0 host clock USBFSH->PORTMODE |= USBFSH_PORTMODE_DEV_ENABLE_MASK; CLOCK_DisableClock(kCLOCK_Usbhsl0); // disable usb0 host clock @@ -213,7 +213,7 @@ void board_init(void) RESET_PeripheralReset(kUSB1_RST_SHIFT_RSTn); RESET_PeripheralReset(kUSB1RAM_RST_SHIFT_RSTn); - /* According to reference mannual, device mode setting has to be set by access usb host register */ + /* According to reference manual, device mode setting has to be set by access usb host register */ CLOCK_EnableClock(kCLOCK_Usbh1); // enable usb0 host clock USBHSH->PORTMODE = USBHSH_PORTMODE_SW_PDCOM_MASK; // Put PHY powerdown under software control diff --git a/hw/bsp/mm32/boards/mm32f327x_mb39/flash.ld b/hw/bsp/mm32/boards/mm32f327x_mb39/flash.ld index d96d6e43d..0b45ee7bd 100644 --- a/hw/bsp/mm32/boards/mm32f327x_mb39/flash.ld +++ b/hw/bsp/mm32/boards/mm32f327x_mb39/flash.ld @@ -126,7 +126,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c index 26008168d..f7ee56990 100644 --- a/hw/bsp/rp2040/family.c +++ b/hw/bsp/rp2040/family.c @@ -226,6 +226,6 @@ int board_getchar(void) //--------------------------------------------------------------------+ // USB Interrupt Handler -// rp2040 implementation will install approriate handler when initializing +// rp2040 implementation will install appropriate handler when initializing // tinyusb. There is no need to forward IRQ from application //--------------------------------------------------------------------+ diff --git a/hw/bsp/stm32f0/boards/stm32f070rbnucleo/stm32F070rbtx_flash.ld b/hw/bsp/stm32f0/boards/stm32f070rbnucleo/stm32F070rbtx_flash.ld index 59e18f375..4a6491510 100644 --- a/hw/bsp/stm32f0/boards/stm32f070rbnucleo/stm32F070rbtx_flash.ld +++ b/hw/bsp/stm32f0/boards/stm32f070rbnucleo/stm32F070rbtx_flash.ld @@ -165,7 +165,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f0/boards/stm32f072disco/STM32F072RBTx_FLASH.ld b/hw/bsp/stm32f0/boards/stm32f072disco/STM32F072RBTx_FLASH.ld index 8d31f6a00..f0879e929 100644 --- a/hw/bsp/stm32f0/boards/stm32f072disco/STM32F072RBTx_FLASH.ld +++ b/hw/bsp/stm32f0/boards/stm32f072disco/STM32F072RBTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f1/boards/stm32f103_bluepill/STM32F103X8_FLASH.ld b/hw/bsp/stm32f1/boards/stm32f103_bluepill/STM32F103X8_FLASH.ld index ca1804905..c434ca038 100644 --- a/hw/bsp/stm32f1/boards/stm32f103_bluepill/STM32F103X8_FLASH.ld +++ b/hw/bsp/stm32f1/boards/stm32f103_bluepill/STM32F103X8_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f1/boards/stm32f103_mini_2/STM32F103XC_FLASH.ld b/hw/bsp/stm32f1/boards/stm32f103_mini_2/STM32F103XC_FLASH.ld index da40d1eb2..da637d1b0 100644 --- a/hw/bsp/stm32f1/boards/stm32f103_mini_2/STM32F103XC_FLASH.ld +++ b/hw/bsp/stm32f1/boards/stm32f103_mini_2/STM32F103XC_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f207nucleo/STM32F207ZGTx_FLASH.ld b/hw/bsp/stm32f207nucleo/STM32F207ZGTx_FLASH.ld index 29e387f28..5010435ae 100644 --- a/hw/bsp/stm32f207nucleo/STM32F207ZGTx_FLASH.ld +++ b/hw/bsp/stm32f207nucleo/STM32F207ZGTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f303disco/STM32F303VCTx_FLASH.ld b/hw/bsp/stm32f303disco/STM32F303VCTx_FLASH.ld index ca9046d29..7f46c71b2 100644 --- a/hw/bsp/stm32f303disco/STM32F303VCTx_FLASH.ld +++ b/hw/bsp/stm32f303disco/STM32F303VCTx_FLASH.ld @@ -150,7 +150,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/feather_stm32f405/STM32F405RGTx_FLASH.ld b/hw/bsp/stm32f4/boards/feather_stm32f405/STM32F405RGTx_FLASH.ld index 57ef61e26..9eb53bcc0 100644 --- a/hw/bsp/stm32f4/boards/feather_stm32f405/STM32F405RGTx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/feather_stm32f405/STM32F405RGTx_FLASH.ld @@ -150,7 +150,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/pyboardv11/STM32F405RGTx_FLASH.ld b/hw/bsp/stm32f4/boards/pyboardv11/STM32F405RGTx_FLASH.ld index 57ef61e26..9eb53bcc0 100644 --- a/hw/bsp/stm32f4/boards/pyboardv11/STM32F405RGTx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/pyboardv11/STM32F405RGTx_FLASH.ld @@ -150,7 +150,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/stm32f401blackpill/STM32F401VCTx_FLASH.ld b/hw/bsp/stm32f4/boards/stm32f401blackpill/STM32F401VCTx_FLASH.ld index f51f1ab41..2bc5f6c14 100644 --- a/hw/bsp/stm32f4/boards/stm32f401blackpill/STM32F401VCTx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/stm32f401blackpill/STM32F401VCTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/stm32f401blackpill/board.h b/hw/bsp/stm32f4/boards/stm32f401blackpill/board.h index 0f820512c..e1fef7277 100644 --- a/hw/bsp/stm32f4/boards/stm32f401blackpill/board.h +++ b/hw/bsp/stm32f4/boards/stm32f401blackpill/board.h @@ -93,7 +93,7 @@ static inline void board_clock_init(void) static inline void board_vbus_sense_init(void) { - // Blackpill doens't use VBUS sense (B device) explicitly disable it + // Blackpill doesn't use VBUS sense (B device) explicitly disable it USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_NOVBUSSENS; USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_VBUSBSEN; USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_VBUSASEN; diff --git a/hw/bsp/stm32f4/boards/stm32f407disco/STM32F407VGTx_FLASH.ld b/hw/bsp/stm32f4/boards/stm32f407disco/STM32F407VGTx_FLASH.ld index c41602720..aac6577ea 100644 --- a/hw/bsp/stm32f4/boards/stm32f407disco/STM32F407VGTx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/stm32f407disco/STM32F407VGTx_FLASH.ld @@ -150,7 +150,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/stm32f411blackpill/STM32F411CEUx_FLASH.ld b/hw/bsp/stm32f4/boards/stm32f411blackpill/STM32F411CEUx_FLASH.ld index efea1e067..56dcea605 100644 --- a/hw/bsp/stm32f4/boards/stm32f411blackpill/STM32F411CEUx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/stm32f411blackpill/STM32F411CEUx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/stm32f411blackpill/board.h b/hw/bsp/stm32f4/boards/stm32f411blackpill/board.h index 0f820512c..e1fef7277 100644 --- a/hw/bsp/stm32f4/boards/stm32f411blackpill/board.h +++ b/hw/bsp/stm32f4/boards/stm32f411blackpill/board.h @@ -93,7 +93,7 @@ static inline void board_clock_init(void) static inline void board_vbus_sense_init(void) { - // Blackpill doens't use VBUS sense (B device) explicitly disable it + // Blackpill doesn't use VBUS sense (B device) explicitly disable it USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_NOVBUSSENS; USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_VBUSBSEN; USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_VBUSASEN; diff --git a/hw/bsp/stm32f4/boards/stm32f411disco/STM32F411VETx_FLASH.ld b/hw/bsp/stm32f4/boards/stm32f411disco/STM32F411VETx_FLASH.ld index 3a0ce526f..4477229ea 100644 --- a/hw/bsp/stm32f4/boards/stm32f411disco/STM32F411VETx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/stm32f411disco/STM32F411VETx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/stm32f412disco/STM32F412ZGTx_FLASH.ld b/hw/bsp/stm32f4/boards/stm32f412disco/STM32F412ZGTx_FLASH.ld index b00b5dbe0..2372cc1d9 100644 --- a/hw/bsp/stm32f4/boards/stm32f412disco/STM32F412ZGTx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/stm32f412disco/STM32F412ZGTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f4/boards/stm32f412nucleo/STM32F412ZGTx_FLASH.ld b/hw/bsp/stm32f4/boards/stm32f412nucleo/STM32F412ZGTx_FLASH.ld index b00b5dbe0..2372cc1d9 100644 --- a/hw/bsp/stm32f4/boards/stm32f412nucleo/STM32F412ZGTx_FLASH.ld +++ b/hw/bsp/stm32f4/boards/stm32f412nucleo/STM32F412ZGTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f7/boards/stlinkv3mini/STM32F723xE_FLASH.ld b/hw/bsp/stm32f7/boards/stlinkv3mini/STM32F723xE_FLASH.ld index 8645ce5c5..f4be85703 100644 --- a/hw/bsp/stm32f7/boards/stlinkv3mini/STM32F723xE_FLASH.ld +++ b/hw/bsp/stm32f7/boards/stlinkv3mini/STM32F723xE_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f7/boards/stm32f723disco/STM32F723xE_FLASH.ld b/hw/bsp/stm32f7/boards/stm32f723disco/STM32F723xE_FLASH.ld index 8645ce5c5..f4be85703 100644 --- a/hw/bsp/stm32f7/boards/stm32f723disco/STM32F723xE_FLASH.ld +++ b/hw/bsp/stm32f7/boards/stm32f723disco/STM32F723xE_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f7/boards/stm32f746disco/STM32F746ZGTx_FLASH.ld b/hw/bsp/stm32f7/boards/stm32f746disco/STM32F746ZGTx_FLASH.ld index 045ec76f9..eeb0e29f3 100644 --- a/hw/bsp/stm32f7/boards/stm32f746disco/STM32F746ZGTx_FLASH.ld +++ b/hw/bsp/stm32f7/boards/stm32f746disco/STM32F746ZGTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f7/boards/stm32f746nucleo/STM32F746ZGTx_FLASH.ld b/hw/bsp/stm32f7/boards/stm32f746nucleo/STM32F746ZGTx_FLASH.ld index b434a01b7..e1e60bc78 100644 --- a/hw/bsp/stm32f7/boards/stm32f746nucleo/STM32F746ZGTx_FLASH.ld +++ b/hw/bsp/stm32f7/boards/stm32f746nucleo/STM32F746ZGTx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f7/boards/stm32f767nucleo/STM32F767ZITx_FLASH.ld b/hw/bsp/stm32f7/boards/stm32f767nucleo/STM32F767ZITx_FLASH.ld index 0b6d5a494..3785f9cbf 100644 --- a/hw/bsp/stm32f7/boards/stm32f767nucleo/STM32F767ZITx_FLASH.ld +++ b/hw/bsp/stm32f7/boards/stm32f767nucleo/STM32F767ZITx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32f7/boards/stm32f769disco/STM32F769ZITx_FLASH.ld b/hw/bsp/stm32f7/boards/stm32f769disco/STM32F769ZITx_FLASH.ld index 378ed80dd..520a75539 100644 --- a/hw/bsp/stm32f7/boards/stm32f769disco/STM32F769ZITx_FLASH.ld +++ b/hw/bsp/stm32f7/boards/stm32f769disco/STM32F769ZITx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32g4/boards/stm32g474nucleo/board.h b/hw/bsp/stm32g4/boards/stm32g474nucleo/board.h index eab0bd5f0..aa2bf20bb 100644 --- a/hw/bsp/stm32g4/boards/stm32g474nucleo/board.h +++ b/hw/bsp/stm32g4/boards/stm32g474nucleo/board.h @@ -66,7 +66,7 @@ static inline void board_clock_init(void) // Configure the main internal regulator output voltage HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); - // Initializes the CPU, AHB and APB busses clocks + // Initializes the CPU, AHB and APB buses clocks RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; @@ -79,7 +79,7 @@ static inline void board_clock_init(void) RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; HAL_RCC_OscConfig(&RCC_OscInitStruct); - // Initializes the CPU, AHB and APB busses clocks + // Initializes the CPU, AHB and APB buses clocks RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/stm32h743xx_flash.ld b/hw/bsp/stm32h7/boards/stm32h743eval/stm32h743xx_flash.ld index 59b9ff4df..7ee40671c 100644 --- a/hw/bsp/stm32h7/boards/stm32h743eval/stm32h743xx_flash.ld +++ b/hw/bsp/stm32h7/boards/stm32h743eval/stm32h743xx_flash.ld @@ -134,7 +134,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32h7/boards/stm32h743nucleo/stm32h743xx_flash.ld b/hw/bsp/stm32h7/boards/stm32h743nucleo/stm32h743xx_flash.ld index 59b9ff4df..7ee40671c 100644 --- a/hw/bsp/stm32h7/boards/stm32h743nucleo/stm32h743xx_flash.ld +++ b/hw/bsp/stm32h7/boards/stm32h743nucleo/stm32h743xx_flash.ld @@ -134,7 +134,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32h7/boards/waveshare_openh743i/STM32H743IITX_FLASH.ld b/hw/bsp/stm32h7/boards/waveshare_openh743i/STM32H743IITX_FLASH.ld index 73d2dedb2..e99bb977b 100644 --- a/hw/bsp/stm32h7/boards/waveshare_openh743i/STM32H743IITX_FLASH.ld +++ b/hw/bsp/stm32h7/boards/waveshare_openh743i/STM32H743IITX_FLASH.ld @@ -138,7 +138,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32h7/boards/waveshare_openh743i/board.h b/hw/bsp/stm32h7/boards/waveshare_openh743i/board.h index 09442c233..2b072e07c 100644 --- a/hw/bsp/stm32h7/boards/waveshare_openh743i/board.h +++ b/hw/bsp/stm32h7/boards/waveshare_openh743i/board.h @@ -186,7 +186,7 @@ static inline void timer_board_delay(TIM_HandleTypeDef* tim_hdl, uint32_t ms) static inline void board_stm32h7_post_init(void) { - // walkaround for reseting the ULPI PHY using Timer since systick is not + // walkaround for resetting the ULPI PHY using Timer since systick is not // available when RTOS is used. // Init timer diff --git a/hw/bsp/stm32l0/boards/stm32l052dap52/STM32L052K8Ux_FLASH.ld b/hw/bsp/stm32l0/boards/stm32l052dap52/STM32L052K8Ux_FLASH.ld index 1bc16cc7b..dfefe59f1 100644 --- a/hw/bsp/stm32l0/boards/stm32l052dap52/STM32L052K8Ux_FLASH.ld +++ b/hw/bsp/stm32l0/boards/stm32l052dap52/STM32L052K8Ux_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32l0538disco/STM32L053C8Tx_FLASH.ld b/hw/bsp/stm32l0538disco/STM32L053C8Tx_FLASH.ld index 787418e09..79427d80b 100644 --- a/hw/bsp/stm32l0538disco/STM32L053C8Tx_FLASH.ld +++ b/hw/bsp/stm32l0538disco/STM32L053C8Tx_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32l4/boards/stm32l476disco/STM32L476VGTx_FLASH.ld b/hw/bsp/stm32l4/boards/stm32l476disco/STM32L476VGTx_FLASH.ld index 98f468ac0..d6865f49d 100644 --- a/hw/bsp/stm32l4/boards/stm32l476disco/STM32L476VGTx_FLASH.ld +++ b/hw/bsp/stm32l4/boards/stm32l476disco/STM32L476VGTx_FLASH.ld @@ -144,7 +144,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32l4/boards/stm32l4r5nucleo/STM32L4RXxI_FLASH.ld b/hw/bsp/stm32l4/boards/stm32l4r5nucleo/STM32L4RXxI_FLASH.ld index f93a16041..f77c72d1b 100644 --- a/hw/bsp/stm32l4/boards/stm32l4r5nucleo/STM32L4RXxI_FLASH.ld +++ b/hw/bsp/stm32l4/boards/stm32l4r5nucleo/STM32L4RXxI_FLASH.ld @@ -130,7 +130,7 @@ SECTIONS . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss secion */ + /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) diff --git a/hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h b/hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h index f42c7d6dd..ea975df03 100644 --- a/hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h +++ b/hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h @@ -59,7 +59,7 @@ static inline void board_clock_init(void) RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; - // Initializes the CPU, AHB and APB busses clocks + // Initializes the CPU, AHB and APB buses clocks RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; @@ -72,7 +72,7 @@ static inline void board_clock_init(void) RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV3; HAL_RCC_OscConfig(&RCC_OscInitStruct); - // Initializes the CPU, AHB and APB busses clocks + // Initializes the CPU, AHB and APB buses clocks RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; diff --git a/hw/bsp/tm4c123/family.c b/hw/bsp/tm4c123/family.c index b0947d6c4..87b94289b 100644 --- a/hw/bsp/tm4c123/family.c +++ b/hw/bsp/tm4c123/family.c @@ -39,7 +39,7 @@ static void board_uart_init (void) UART0->LCRH = (0x3 << 5); // 8-bit, no parity, 1 stop bit UART0->CC = 0x0; // Configure the UART clock source as system clock - UART0->CTL = (1 << 0) | (1 << 8) | (1 << 9); // UART0 Enable, Transmit Enable, Recieve Enable + UART0->CTL = (1 << 0) | (1 << 8) | (1 << 9); // UART0 Enable, Transmit Enable, Receive Enable } static void initialize_board_led (GPIOA_Type *port, uint8_t PinMsk, uint8_t dirmsk) diff --git a/lib/SEGGER_RTT/RTT/SEGGER_RTT.c b/lib/SEGGER_RTT/RTT/SEGGER_RTT.c index 3ad2b1a12..a7ae013dd 100644 --- a/lib/SEGGER_RTT/RTT/SEGGER_RTT.c +++ b/lib/SEGGER_RTT/RTT/SEGGER_RTT.c @@ -1404,7 +1404,7 @@ int SEGGER_RTT_GetKey(void) { * SEGGER_RTT_WaitKey * * Function description -* Waits until at least one character is avaible in the SEGGER RTT buffer. +* Waits until at least one character is available in the SEGGER RTT buffer. * Once a character is available, it is read and this function returns. * * Return value diff --git a/lib/networking/dnserver.c b/lib/networking/dnserver.c index e4e7c3492..539cc2cea 100644 --- a/lib/networking/dnserver.c +++ b/lib/networking/dnserver.c @@ -93,11 +93,11 @@ static uint16_t get_uint16(const uint8_t *pnt) static int parse_next_query(void *data, int size, dns_query_t *query) { int len; - int lables; + int labels; uint8_t *ptr; len = 0; - lables = 0; + labels = 0; ptr = (uint8_t *)data; while (true) @@ -107,7 +107,7 @@ static int parse_next_query(void *data, int size, dns_query_t *query) lable_len = *ptr++; size--; if (lable_len == 0) break; - if (lables > 0) + if (labels > 0) { if (len == DNS_MAX_HOST_NAME_LEN) return -2; query->name[len++] = '.'; @@ -118,7 +118,7 @@ static int parse_next_query(void *data, int size, dns_query_t *query) len += lable_len; ptr += lable_len; size -= lable_len; - lables++; + labels++; } if (size < 4) return -1; diff --git a/lib/networking/ndis.h b/lib/networking/ndis.h index 1c737574c..06258e6bb 100644 --- a/lib/networking/ndis.h +++ b/lib/networking/ndis.h @@ -22,7 +22,7 @@ * ntddndis.h modified by Benedikt Spranger * * Thanks to the cygwin development team, - * espacially to Casper S. Hornstrup + * especially to Casper S. Hornstrup * * THIS SOFTWARE IS NOT COPYRIGHTED * diff --git a/lib/networking/rndis_reports.c b/lib/networking/rndis_reports.c index ee611c883..d129466c8 100644 --- a/lib/networking/rndis_reports.c +++ b/lib/networking/rndis_reports.c @@ -220,7 +220,7 @@ static void rndis_handle_set_msg(void) case OID_802_3_MULTICAST_LIST: break; - /* Power Managment: fails for now */ + /* Power Management: fails for now */ case OID_PNP_ADD_WAKE_UP_PATTERN: case OID_PNP_REMOVE_WAKE_UP_PATTERN: case OID_PNP_ENABLE_WAKE_UP: diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index e345139ea..c428af865 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -193,7 +193,7 @@ typedef enum }cdc_management_request_t; //--------------------------------------------------------------------+ -// Management Elemenent Notification (Notification Endpoint) +// Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ /// 6.3 Notification Codes diff --git a/src/class/cdc/cdc_rndis_host.c b/src/class/cdc/cdc_rndis_host.c index 8f28f51ac..44de85b45 100644 --- a/src/class/cdc/cdc_rndis_host.c +++ b/src/class/cdc/cdc_rndis_host.c @@ -117,7 +117,7 @@ void rndish_init(void) //------------- Task creation -------------// - //------------- semaphore creation for notificaiton pipe -------------// + //------------- semaphore creation for notification pipe -------------// for(uint8_t i=0; iMSC0CFG = SYS->MSC0CFG | MASK_SYS_MSC0CFG_DEV_RMWAKEUP; - // Atleast 2 ms of delay needed for RESUME Data K state. + // At least 2 ms of delay needed for RESUME Data K state. delayms(2); SYS->MSC0CFG &= ~MASK_SYS_MSC0CFG_DEV_RMWAKEUP; @@ -720,7 +720,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc) else total_ram = USBD_RAMTOTAL_OUT; // Work out how much has been allocated to existing endpoints. - // The total RAM allocated shoudl alsyes be a positive number as this + // The total RAM allocated should always be a positive number as this // algorithm should not let it go below zero. for (int i = 1; i < USBD_MAX_ENDPOINT_COUNT; i++) { @@ -976,7 +976,7 @@ void dcd_int_handler(uint8_t rhport) USBD_EP_SR_REG(USBD_EP_0) = MASK_USBD_EP0SR_STALL; } - // Host has sent a SETUP packet. Recieve this into the setup packet store. + // Host has sent a SETUP packet. Receive this into the setup packet store. _ft90x_dusb_out(USBD_EP_0, (uint8_t *)_ft90x_setup_packet, sizeof(USB_device_request)); // Send the packet to tinyusb. diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 76ba2a921..80f616478 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -199,7 +199,7 @@ static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr) #pragma GCC diagnostic pop if ( qhd->dev_addr == dev_addr ) { - // TODO deactive all TD, wait for QHD to inactive before removal + // TODO deactivate all TD, wait for QHD to inactive before removal prev->address = qhd->next.address; // EHCI 4.8.2 link the removed qhd to async head (which always reachable by Host Controller) @@ -839,7 +839,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c if (TUSB_SPEED_HIGH == p_qhd->ep_speed) { TU_ASSERT( interval <= 16, ); - if ( interval < 4) // sub milisecond interval + if ( interval < 4) // sub millisecond interval { p_qhd->interval_ms = 0; p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) : diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h index ff9ae12e7..36f8649be 100644 --- a/src/portable/ehci/ehci.h +++ b/src/portable/ehci/ehci.h @@ -114,7 +114,7 @@ typedef struct volatile uint32_t current_page : 3 ; ///< Index into the qTD buffer pointer list uint32_t int_on_complete : 1 ; ///< Interrupt on complete volatile uint32_t total_bytes : 15 ; ///< Transfer bytes, decreased during transaction - volatile uint32_t data_toggle : 1 ; ///< Data Toogle bit + volatile uint32_t data_toggle : 1 ; ///< Data Toggle bit /// Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page @@ -160,7 +160,7 @@ typedef struct TU_ATTR_ALIGNED(32) uint8_t used; uint8_t removing; // removed from asyn list, waiting for async advance uint8_t pid; - uint8_t interval_ms; // polling interval in frames (or milisecond) + uint8_t interval_ms; // polling interval in frames (or millisecond) uint16_t total_xferred_bytes; // number of bytes xferred until a qtd with ioc bit set uint8_t reserved2[2]; @@ -225,7 +225,7 @@ typedef struct TU_ATTR_ALIGNED(32) uint16_t reserved ; ///< reserved // Word 3: siTD Transfer Status and Control - // Status [7:0] TODO indentical to qTD Token'status --> refractor later + // Status [7:0] TODO identical to qTD Token'status --> refactor later volatile uint32_t : 1 ; // reserved volatile uint32_t split_state : 1 ; volatile uint32_t missed_uframe : 1 ; @@ -350,8 +350,8 @@ typedef volatile struct uint32_t periodic_status : 1 ; ///< Periodic schedule status uint32_t async_status : 1 ; ///< Async schedule status uint32_t : 2 ; - uint32_t nxp_int_async : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the asynchronous schedule. This bit is also set by the Host when a short packet is detected andthe packet is on the asynchronous schedule. - uint32_t nxp_int_period : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set andthe TD was from the periodic schedule. + uint32_t nxp_int_async : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set and the TD was from the asynchronous schedule. This bit is also set by the Host when a short packet is detected and the packet is on the asynchronous schedule. + uint32_t nxp_int_period : 1 ; ///< NXP customized: This bit is set by the Host Controller when the cause of an interrupt is a completion of a USB transaction where the Transfer Descriptor (TD) has an interrupt on complete (IOC) bit set and the TD was from the periodic schedule. uint32_t : 12 ; }status_bm; }; diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c index 0b75af627..41240f737 100644 --- a/src/portable/espressif/esp32sx/dcd_esp32sx.c +++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c @@ -741,7 +741,7 @@ static void handle_epin_ints(void) // XFER Timeout if (USB0.in_ep_reg[n].diepint & USB_D_TIMEOUT0_M) { - // Clear interrupt or enpoint will hang. + // Clear interrupt or endpoint will hang. USB0.in_ep_reg[n].diepint = USB_D_TIMEOUT0_M; // Maybe retry? } diff --git a/src/portable/microchip/pic32mz/usbhs_registers.h b/src/portable/microchip/pic32mz/usbhs_registers.h index 757e3f083..93b552322 100644 --- a/src/portable/microchip/pic32mz/usbhs_registers.h +++ b/src/portable/microchip/pic32mz/usbhs_registers.h @@ -21,16 +21,16 @@ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. *******************************************************************************/ /******************************************************************************* - USBHS Peripheral Library Register Defintions + USBHS Peripheral Library Register Definitions File Name: usbhs_registers.h Summary: - USBHS PLIB Register Defintions + USBHS PLIB Register Definitions Description: - This file contains the constants and defintions which are required by the + This file contains the constants and definitions which are required by the the USBHS library. *******************************************************************************/ diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c index 7507c0f69..24657872b 100644 --- a/src/portable/microchip/samx7x/dcd_samx7x.c +++ b/src/portable/microchip/samx7x/dcd_samx7x.c @@ -42,7 +42,7 @@ # define USE_SOF 0 #endif -// Dual bank can imporve performance, but need 2 times bigger packet buffer +// Dual bank can improve performance, but need 2 times bigger packet buffer // As SAM7x has only 4KB packet buffer, use with caution ! // Enable in FS mode as packets are smaller #ifndef USE_DUAL_BANK @@ -644,7 +644,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } __set_PRIMASK(irq_state); - // Here a ZLP has been recieved + // Here a ZLP has been received // and the DMA transfer must be not started. // It is the end of transfer return false; @@ -734,7 +734,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 } __set_PRIMASK(irq_state); - // Here a ZLP has been recieved + // Here a ZLP has been received // and the DMA transfer must be not started. // It is the end of transfer return false; diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index 886720e33..3fa7c1ec1 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -181,7 +181,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep) ep->EPINTEN = USBD_EPINTEN_TXPKIEN_Msk; } - /* provided buffers are thankfully 32-bit aligned, allowing most data to be transfered as 32-bit */ + /* provided buffers are thankfully 32-bit aligned, allowing most data to be transferred as 32-bit */ #if 0 // TODO support dcd_edpt_xfer_fifo API if (xfer->ff) { diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 3e523ebc2..228da6ae0 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -165,7 +165,7 @@ bool hcd_init(uint8_t rhport) //------------- Data Structure init -------------// tu_memclr(&ohci_data, sizeof(ohci_data_t)); for(uint8_t i=0; i<32; i++) - { // assign all interrupt pointes to period head ed + { // assign all interrupt pointers to period head ed ohci_data.hcca.interrupt_table[i] = (uint32_t) &ohci_data.period_head_ed; } diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index 9fc954c8f..f40ae24cc 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -34,7 +34,7 @@ //--------------------------------------------------------------------+ // OHCI CONFIGURATION & CONSTANTS //--------------------------------------------------------------------+ -#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed +#define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enabled #define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS) // TODO merge OHCI with EHCI diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index c88a8a3a2..54c3c95e7 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -122,7 +122,7 @@ (TU_CHECK_MCU(OPT_MCU_STM32L4) && defined(STM32L4_FSDEV)) \ ) -// In order to reduce the dependance on HAL, we undefine this. +// In order to reduce the dependence on HAL, we undefine this. // Some definitions are copied to our private include file. #undef USE_HAL_DRIVER diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index a0be846a5..2d0e379ad 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -243,7 +243,7 @@ static void USBC_Dev_SetAddress(u8 address) static void __USBC_Dev_Tx_SendStall(void) { - //send stall, and fifo is flushed automaticly + //send stall, and fifo is flushed automatically USBC_REG_set_bit_w(USBC_BP_TXCSR_D_SEND_STALL, USBC_REG_TXCSR(USBC0_BASE)); } static u32 __USBC_Dev_Tx_IsEpStall(void) diff --git a/src/portable/sunxi/musb_def.h b/src/portable/sunxi/musb_def.h index 602b4f113..53da5ded2 100644 --- a/src/portable/sunxi/musb_def.h +++ b/src/portable/sunxi/musb_def.h @@ -93,7 +93,7 @@ #define USBC1_BASE 0x01c14000 #define USBC2_BASE 0x01c1E000 -//Some reg whithin musb +//Some reg within musb #define USBPHY_CLK_REG 0x01c200CC #define USBPHY_CLK_RST_BIT 0 #define USBPHY_CLK_GAT_BIT 1 diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index f5ecdfe4f..b53735a5e 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1003,7 +1003,7 @@ static void handle_rxflvl_irq(uint8_t rhport) switch ( pktsts ) { - // Global OUT NAK: do nothign + // Global OUT NAK: do nothing case GRXSTS_PKTSTS_GLOBALOUTNAK: break; case GRXSTS_PKTSTS_SETUPRX: diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index ea786362e..b63d1fcd0 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -116,7 +116,7 @@ static const dwc2_controller_t _dwc2_controller[] = // //--------------------------------------------------------------------+ -// SystemCoreClock is alrady included by family header +// SystemCoreClock is already included by family header // extern uint32_t SystemCoreClock; TU_ATTR_ALWAYS_INLINE -- cgit v1.3.1 From 4f0369508450883504e377b40aaec8860c8cb256 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Dec 2022 16:52:28 +0700 Subject: adding tuh_cdc_mount_cb/tuh_cdc_umount_cb start adding cdc_app.c to example --- examples/host/cdc_msc_hid/CMakeLists.txt | 3 +- examples/host/cdc_msc_hid/Makefile | 3 +- examples/host/cdc_msc_hid/src/cdc_app.c | 51 ++++++++++++++++++++++++++++++++ examples/host/cdc_msc_hid/src/main.c | 11 ++----- src/class/cdc/cdc_host.c | 12 ++++++++ src/class/cdc/cdc_host.h | 17 +++++++---- 6 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 examples/host/cdc_msc_hid/src/cdc_app.c (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index d84457bc9..2e89817a5 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -14,8 +14,9 @@ add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c ) diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile index ad28076a0..9adccfa3a 100644 --- a/examples/host/cdc_msc_hid/Makefile +++ b/examples/host/cdc_msc_hid/Makefile @@ -7,7 +7,8 @@ INC += \ # Example source EXAMPLE_SOURCE = \ - src/hid_app.c \ + src/cdc_app.c \ + src/hid_app.c \ src/main.c \ src/msc_app.c \ diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c new file mode 100644 index 000000000..29da02abc --- /dev/null +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + + +//------------- IMPLEMENTATION -------------// + +void cdc_app_task(void) +{ + +} + +void tuh_cdc_mount_cb(uint8_t dev_addr) +{ + (void) dev_addr; + printf("A CDC device is mounted\r\n"); +} + +void tuh_cdc_umount_cb(uint8_t dev_addr) +{ + (void) dev_addr; + printf("A CDC device is unmounted\r\n"); +} diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index d26e41e8d..465e457f7 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -35,7 +35,7 @@ //--------------------------------------------------------------------+ void led_blinking_task(void); -extern void cdc_task(void); +extern void cdc_app_task(void); extern void hid_app_task(void); /*------------- MAIN -------------*/ @@ -52,9 +52,9 @@ int main(void) { // tinyusb host task tuh_task(); - led_blinking_task(); - cdc_task(); + led_blinking_task(); + cdc_app_task(); hid_app_task(); } @@ -79,11 +79,6 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data } -void cdc_task(void) -{ - -} - //--------------------------------------------------------------------+ // TinyUSB Callbacks //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ee824cb4e..aa3a7e1e5 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -239,6 +239,8 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) { (void) dev_addr; (void) itf_num; + + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(dev_addr); return true; } @@ -254,6 +256,16 @@ void cdch_close(uint8_t dev_addr) TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); cdch_data_t * p_cdc = get_itf(dev_addr); + + // Invoke application callback + if (tuh_cdc_umount_cb) + { + if (p_cdc->ep_out || p_cdc->ep_in || p_cdc->ep_notif) + { + tuh_cdc_umount_cb(dev_addr); + } + } + tu_memclr(p_cdc, sizeof(cdch_data_t)); } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 33dbd2efb..c3b601b34 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -34,13 +34,18 @@ #endif //--------------------------------------------------------------------+ -// CDC APPLICATION PUBLIC API +// Application API //--------------------------------------------------------------------+ -/** \ingroup ClassDriver_CDC Communication Device Class (CDC) - * \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Host Host - * @{ */ + + +//------------- Application Callback -------------// + +// Invoked when a device with CDC interface is mounted +TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t dev_addr); + +// Invoked when a device with CDC interface is unmounted +TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t dev_addr); + bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); -- cgit v1.3.1 From 854e5222aea570a2be2201d8c460f54b87c9108a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 00:26:46 +0700 Subject: finalizing cdc host, has a working read/write TODO: first character seems not to get echoed. set control line state seems to failed with LOG < 2 --- examples/host/cdc_msc_hid/src/main.c | 18 -- src/class/cdc/cdc_host.c | 458 +++++++++++++++++++++++++++-------- src/class/cdc/cdc_host.h | 84 +++++-- 3 files changed, 419 insertions(+), 141 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 465e457f7..b34810252 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -61,24 +61,6 @@ int main(void) return 0; } -//--------------------------------------------------------------------+ -// USB CDC -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 }; - -// invoked ISR context -void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes) -{ - (void) event; - (void) pipe_id; - (void) xferred_bytes; - - printf(serial_in_buffer); - tu_memclr(serial_in_buffer, sizeof(serial_in_buffer)); - - tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data -} - //--------------------------------------------------------------------+ // TinyUSB Callbacks //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 482ccf4be..bdfbe3e74 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -36,52 +36,157 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -#if 0 typedef struct { tu_fifo_t ff; + + // mutex: read if ep rx, write if e tx OSAL_MUTEX_DEF(ff_mutex); + + // TODO xfer_fifo can skip this buffer + uint8_t* ep_buf; + uint16_t ep_bufsize; + uint8_t ep_addr; }tu_edpt_stream_t; -uint32_t tud_cdc_read_available (void); -uint32_t tud_cdc_read (void *buffer, uint32_t bufsize); -void tud_cdc_read_flush (void); -bool tud_cdc_peek (uint8_t *ui8); +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool use_wr_mutex, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, + uint8_t* ep_buf, uint16_t ep_bufsize) +{ + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + (void) new_mutex; -uint32_t tud_cdc_write (void const *buffer, uint32_t bufsize); -uint32_t tud_cdc_write_flush (void); -uint32_t tud_cdc_write_available (void); + tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); + tu_fifo_config_mutex(&s->ff, use_wr_mutex ? new_mutex : NULL, use_wr_mutex ? NULL : new_mutex); -//-------------------------------------------------------- -tu_edpt_stream_write() -#endif + s->ep_buf = ep_buf; + s->ep_bufsize = ep_bufsize; + + return true; +} + +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) +{ + return tu_fifo_clear(&s->ff); +} + +uint32_t tud_edpt_stream_write_flush(uint8_t dev_addr, tu_edpt_stream_t* s) +{ + // No data to send + if ( !tu_fifo_count(&s->ff) ) return 0; + + // Claim the endpoint + // uint8_t const rhport = 0; + // TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + TU_VERIFY( usbh_edpt_claim(dev_addr, s->ep_addr) ); + + // Pull data from FIFO -> EP buf + uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); + + if ( count ) + { + //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + TU_ASSERT( usbh_edpt_xfer(dev_addr, s->ep_addr, s->ep_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + // Note: data is dropped if terminal is not connected + //usbd_edpt_release(rhport, p_cdc->ep_in); + + usbh_edpt_release(dev_addr, s->ep_addr); + return 0; + } +} + +uint32_t tu_edpt_stream_write(uint8_t daddr, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) +{ + uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if queue more than packet size + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) + /* || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) */ ) + { + tud_edpt_stream_write_flush(daddr, s); + } + + return ret; +} + +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) +{ + tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); +} + +uint32_t tu_edpt_stream_read_xfer(uint8_t daddr, tu_edpt_stream_t* s) +{ + uint16_t available = tu_fifo_remaining(&s->ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + TU_VERIFY(available >= bulk_packet_size); + + // claim endpoint + TU_VERIFY(usbh_edpt_claim(daddr, s->ep_addr), 0); + + // fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if ( available >= bulk_packet_size ) + { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & (bulk_packet_size -1)); + count = tu_min16(count, s->ep_bufsize); + + TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, s->ep_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + usbh_edpt_release(daddr, s->ep_addr); + return 0; + } +} + +uint32_t tu_edpt_stream_read(uint8_t daddr, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) +{ + uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); + tu_edpt_stream_read_xfer(daddr, s); + return num_read; +} + +uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_count(&s->ff); +} typedef struct { uint8_t daddr; - uint8_t itf_num; - uint8_t itf_protocol; - - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; + uint8_t bInterfaceNumber; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; cdc_acm_capability_t acm_capability; + uint8_t ep_notif; // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - // uint8_t line_state; + uint8_t line_state; - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; + tuh_xfer_cb_t user_control_cb; - uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; - OSAL_MUTEX_DEF(rx_ff_mutex); - OSAL_MUTEX_DEF(tx_ff_mutex); + uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_CDC_RX_EPSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_CDC_TX_EPSIZE]; + uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; + } stream; } cdch_interface_t; @@ -92,19 +197,33 @@ typedef struct { CFG_TUSB_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; -static inline cdch_interface_t* get_itf(uint8_t dev_addr) +static inline cdch_interface_t* get_itf(uint8_t idx) { - for(size_t i=0; idaddr != 0) ? p_cdc : NULL; +} + +static inline cdch_interface_t* get_itf_by_ep_addr(uint8_t daddr, uint8_t ep_addr) +{ + for(uint8_t i=0; idaddr == daddr) && + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) + { + return p_cdc; + } } return NULL; } + static cdch_interface_t* find_new_itf(void) { - for(size_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; + } + + return TUSB_INDEX_INVALID; +} + +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_cdc_itf_info_t* info) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && info); + + info->daddr = p_cdc->daddr; + info->bInterfaceNumber = p_cdc->bInterfaceNumber; + info->bInterfaceSubClass = p_cdc->bInterfaceSubClass; + info->bInterfaceProtocol = p_cdc->bInterfaceProtocol; + + return true; +} + +bool tuh_cdc_mounted(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); return p_cdc != NULL; } -uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize) +bool tuh_cdc_get_dtr(uint8_t idx) { - (void) dev_addr; - (void) buffer; - (void) bufsize; + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return 0; + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) +bool tuh_cdc_get_rts(uint8_t idx) { - // TODO consider all AT Command as serial candidate - return tuh_cdc_mounted(dev_addr) && - (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify) +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_data != NULL && length); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize); +} - uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; - if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; +uint32_t tuh_cdc_write_flush(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length); + return tud_edpt_stream_write_flush(p_cdc->daddr, &p_cdc->stream.tx); } -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify) +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_buffer != NULL && length ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; - if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; + return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize); +} - return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length); +uint32_t tuh_cdc_read_available(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { - cdch_interface_t const * p_cdc = get_itf(dev_addr); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + if (xfer->result == XFER_RESULT_SUCCESS) + { + switch(xfer->setup->bRequest) + { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb(xfer); +} + +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = @@ -176,19 +356,20 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xf .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))), - .wIndex = tu_htole16(p_cdc->itf_num), + .wValue = tu_htole16(line_state), + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), .wLength = 0 }; + p_cdc->user_control_cb = complete_cb; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb, - .user_data = 0 + .complete_cb = cdch_internal_control_complete, + .user_data = user_data }; return tuh_control_xfer(&xfer); @@ -202,32 +383,79 @@ void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); -// for(size_t i=0; istream.tx, true, false, + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + + tu_edpt_stream_init(&p_cdc->stream.rx, false, false, + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + } } -void cdch_close(uint8_t dev_addr) +void cdch_close(uint8_t daddr) { - cdch_interface_t * p_cdc = get_itf(dev_addr); - TU_VERIFY(p_cdc, ); - - // Invoke application callback - if (tuh_cdc_umount_cb) + for(uint8_t idx=0; idxdaddr == daddr) + { + // Invoke application callback + if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); + + //tu_memclr(p_cdc, sizeof(cdch_interface_t)); + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + tu_edpt_stream_clear(&p_cdc->stream.tx); + tu_edpt_stream_clear(&p_cdc->stream.rx); + } } - - tu_memclr(p_cdc, sizeof(cdch_interface_t)); } -bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { - (void) ep_addr; - tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + // TODO handle stall response, retry failed transfer ... + TU_ASSERT(event == XFER_RESULT_SUCCESS); + + cdch_interface_t * p_cdc = get_itf_by_ep_addr(daddr, ep_addr); + TU_ASSERT(p_cdc); + + if ( ep_addr == p_cdc->stream.tx.ep_addr ) + { + if ( 0 == tud_edpt_stream_write_flush(daddr, &p_cdc->stream.tx) ) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP Packet size and not zero + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + if ( !tu_fifo_count(&p_cdc->stream.tx.ff) && xferred_bytes && (0 == (xferred_bytes & (bulk_packet_size-1))) ) + { + if ( usbh_edpt_claim(daddr, p_cdc->stream.tx.ep_addr) ) + { + usbh_edpt_xfer(daddr, p_cdc->stream.tx.ep_addr, NULL, 0); + } + } + } + } + else if ( ep_addr == p_cdc->stream.rx.ep_addr ) + { + tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + + // invoke receive callback + + // prepare for next transfer if needed + tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); + }else if ( ep_addr == p_cdc->ep_notif ) + { + // TODO handle notification endpoint + }else + { + TU_ASSERT(false); + } + return true; } @@ -238,7 +466,6 @@ bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - (void) max_len; // Only support ACM subclass // Protocol 0xFF can be RNDIS device for windows XP @@ -246,19 +473,22 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && 0xFF != itf_desc->bInterfaceProtocol); + uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; + cdch_interface_t * p_cdc = find_new_itf(); TU_VERIFY(p_cdc); - p_cdc->daddr = dev_addr; - p_cdc->itf_num = itf_desc->bInterfaceNumber; - p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; + p_cdc->daddr = dev_addr; + p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; + p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; + p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; + p_cdc->line_state = 0; //------------- Control Interface -------------// - uint16_t drv_len = tu_desc_len(itf_desc); uint8_t const * p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) { if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) { @@ -266,7 +496,6 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } @@ -279,7 +508,6 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); p_cdc->ep_notif = desc_ep->bEndpointAddress; - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } @@ -288,42 +516,72 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) { // next to endpoint descriptor - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs for(uint32_t i=0; i<2; i++) { tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) { - p_cdc->ep_in = desc_ep->bEndpointAddress; + p_cdc->stream.rx.ep_addr = desc_ep->bEndpointAddress; }else { - p_cdc->ep_out = desc_ep->bEndpointAddress; + p_cdc->stream.tx.ep_addr = desc_ep->bEndpointAddress; } - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next( p_desc ); + p_desc = tu_desc_next(p_desc); } } return true; } -bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +static void config_cdc_complete(uint8_t daddr, uint8_t itf_num) { - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(dev_addr); + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + + if (idx != TUSB_INDEX_INVALID) + { + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); + + // Prepare for incoming data + cdch_interface_t* p_cdc = get_itf(idx); + tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); + } // notify usbh that driver enumeration is complete // itf_num+1 to account for data interface as well - usbh_driver_set_config_complete(dev_addr, itf_num+1); + usbh_driver_set_config_complete(daddr, itf_num+1); +} + +#if CFG_TUH_CDC_SET_DTRRTS_ON_ENUM +static void config_set_dtr_rts_complete (tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + config_cdc_complete(xfer->daddr, itf_num); +} + +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) +{ + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + return tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_SET_DTRRTS_ON_ENUM, config_set_dtr_rts_complete, 0); +} + +#else + +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) +{ + config_cdc_complete(daddr, itf_num); return true; } #endif + +#endif diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index b2e75902d..54e082e7d 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,6 +37,11 @@ // Class Driver Configuration //--------------------------------------------------------------------+ +// Set DTR ( bit 0), RTS (bit 1) on enumeration/mounted +#ifndef CFG_TUH_CDC_SET_DTRRTS_ON_ENUM +#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0 +#endif + // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX @@ -61,43 +66,76 @@ // Application API //--------------------------------------------------------------------+ -bool tuh_cdc_mounted(uint8_t dev_addr); +typedef struct +{ + uint8_t daddr; + uint8_t bInterfaceNumber; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; +} tuh_cdc_itf_info_t; + +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID (0xFF) if not found +uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); + +// Get Interface information +// return true if index is correct and interface is currently mounted +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_cdc_itf_info_t* info); + +// Check if a interface is mounted +bool tuh_cdc_mounted(uint8_t idx); + +// Get current DTR status +bool tuh_cdc_get_dtr(uint8_t idx); + +// Get current RTS status +bool tuh_cdc_get_rts(uint8_t idx); + +// Check if interface is connected (DTR active) +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) +{ + return tuh_cdc_get_dtr(idx); +} + +// Write to cdc interface +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); + +// Force sending data if possible, return number of forced bytes +uint32_t tuh_cdc_write_flush(uint8_t idx); + +// Read from cdc interface +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); -uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize); -//uint32_t tuh_cdc_read(uint8_t dev_addr, void* buffer, uint32_t bufsize); +// Get the number of bytes available for reading +uint32_t tuh_cdc_read_available(uint8_t idx); //--------------------------------------------------------------------+ // Control Endpoint (Request) API //--------------------------------------------------------------------+ -// Set Control Line State (DTR, RTS) -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); +// Send control request to Set Control Line State: DTR (bit 0), RTS (bit 1) +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Connect by set both DTR, RTS +static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); + return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } -static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Disconnect by clear both DTR, RTS +static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); + return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } //------------- Application Callback -------------// // Invoked when a device with CDC interface is mounted -TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t dev_addr); +// idx is index of cdc interface in the internal pool. +TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx); // Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t dev_addr); - - -/** \brief Check if device support CDC Serial interface or not - * \param[in] dev_addr device address - * \retval true if device supports - * \retval false if device does not support or is not mounted - */ -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); +TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx); /** \brief Check if the interface is currently busy or not * \param[in] dev_addr device address @@ -108,7 +146,7 @@ bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); * can be scheduled. User needs to make sure the corresponding interface is mounted * (by \ref tuh_cdc_serial_is_mounted) before calling this function. */ -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); +// bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); /** \brief Perform USB OUT transfer to device * \param[in] dev_addr device address @@ -121,7 +159,7 @@ bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. */ -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); +// bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); /** \brief Perform USB IN transfer to get data from device * \param[in] dev_addr device address @@ -134,7 +172,7 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. */ -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); +// bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS @@ -151,7 +189,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. * \note */ -void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); +// void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); /// @} // group CDC_Serial_Host /// @} -- cgit v1.3.1 From b3e63c335af9345e505575e5bc8ba0281ac73692 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 11:47:07 +0700 Subject: updat cdc host app --- examples/host/cdc_msc_hid/src/cdc_app.c | 55 +++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 29da02abc..123cb33f0 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -25,6 +25,7 @@ */ #include "tusb.h" +#include "bsp/board.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -33,19 +34,61 @@ //------------- IMPLEMENTATION -------------// +size_t get_console_inputs(uint8_t* buf, size_t bufsize) +{ + size_t count = 0; + while (count < bufsize) + { + int ch = board_getchar(); + if ( ch <= 0 ) break; + + buf[count] = (uint8_t) ch; + count++; + } + + return count; +} + void cdc_app_task(void) { + uint8_t buf[64+1]; // +1 for extra null character + memset(buf, 0, sizeof(buf)); + size_t count = get_console_inputs(buf, sizeof(buf)-1); + + // loop over all mounted interfaces + for(size_t idx=0; idx cdc interfaces + if (count) + { + tuh_cdc_write(idx, buf, count); + tuh_cdc_write_flush(idx); + } + + // cdc interfaces -> console + if ( tuh_cdc_read_available(idx) ) + { + printf((char*) buf); + } + } + } } -void tuh_cdc_mount_cb(uint8_t dev_addr) +void tuh_cdc_mount_cb(uint8_t idx) { - (void) dev_addr; - printf("A CDC device is mounted\r\n"); + tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_get_info(idx, &itf_info); + + printf("CDC Interface is mounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); } -void tuh_cdc_umount_cb(uint8_t dev_addr) +void tuh_cdc_umount_cb(uint8_t idx) { - (void) dev_addr; - printf("A CDC device is unmounted\r\n"); + tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_get_info(idx, &itf_info); + + printf("CDC Interface is unmounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); } -- cgit v1.3.1 From badb30a6c3d0748b52d7c9db5a48b7bef21b4c1a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:25:13 +0700 Subject: correct cdc host app --- examples/host/cdc_msc_hid/src/cdc_app.c | 17 +++++++++++------ src/class/cdc/cdc_host.c | 3 ++- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 123cb33f0..db652efde 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -52,26 +52,31 @@ size_t get_console_inputs(uint8_t* buf, size_t bufsize) void cdc_app_task(void) { uint8_t buf[64+1]; // +1 for extra null character - memset(buf, 0, sizeof(buf)); + uint32_t const bufsize = sizeof(buf)-1; - size_t count = get_console_inputs(buf, sizeof(buf)-1); + uint32_t console_count = get_console_inputs(buf, bufsize); + buf[console_count] = 0; // loop over all mounted interfaces - for(size_t idx=0; idx cdc interfaces - if (count) + if (console_count) { - tuh_cdc_write(idx, buf, count); + tuh_cdc_write(idx, buf, console_count); tuh_cdc_write_flush(idx); } // cdc interfaces -> console if ( tuh_cdc_read_available(idx) ) { - printf((char*) buf); + uint8_t buf_cdc[64+1]; + uint32_t cdc_count = tuh_cdc_read(idx, buf_cdc, sizeof(buf_cdc)-1); + buf_cdc[cdc_count] = 0; + + printf((char*) buf_cdc); } } } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f8d996e17..326567689 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -459,7 +459,8 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { - tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + // skip if ZLP + if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback -- cgit v1.3.1 From 84a483f5ea7446a5cc1a9fe957379dd1f0a6fd4c Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:47:00 +0700 Subject: add more host cdc API tuh_cdc_write_available(), tuh_cdc_read_flush(), tuh_cdc_rx_cb() callback --- examples/host/cdc_msc_hid/src/cdc_app.c | 31 +++++++++-------- src/class/cdc/cdc_host.c | 34 ++++++++++++++++++ src/class/cdc/cdc_host.h | 62 +++++++++++---------------------- 3 files changed, 72 insertions(+), 55 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index db652efde..23ea05b2b 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -54,8 +54,8 @@ void cdc_app_task(void) uint8_t buf[64+1]; // +1 for extra null character uint32_t const bufsize = sizeof(buf)-1; - uint32_t console_count = get_console_inputs(buf, bufsize); - buf[console_count] = 0; + uint32_t count = get_console_inputs(buf, bufsize); + buf[count] = 0; // loop over all mounted interfaces for(uint8_t idx=0; idx cdc interfaces - if (console_count) + if (count) { - tuh_cdc_write(idx, buf, console_count); + tuh_cdc_write(idx, buf, count); tuh_cdc_write_flush(idx); } - - // cdc interfaces -> console - if ( tuh_cdc_read_available(idx) ) - { - uint8_t buf_cdc[64+1]; - uint32_t cdc_count = tuh_cdc_read(idx, buf_cdc, sizeof(buf_cdc)-1); - buf_cdc[cdc_count] = 0; - - printf((char*) buf_cdc); - } } } } +// Invoked when received new data +void tuh_cdc_rx_cb(uint8_t idx) +{ + uint8_t buf[64+1]; // +1 for extra null character + uint32_t const bufsize = sizeof(buf)-1; + + // forward cdc interfaces -> console + uint32_t count = tuh_cdc_read(idx, buf, bufsize); + buf[count] = 0; + + printf((char*) buf); +} + void tuh_cdc_mount_cb(uint8_t idx) { tuh_cdc_itf_info_t itf_info; diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 326567689..ba2e9e1b7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -185,6 +185,17 @@ uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) return (uint32_t) tu_fifo_count(&s->ff); } +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_remaining(&s->ff); +} + +void tu_edpt_stream_read_clear(uint8_t daddr, tu_edpt_stream_t* s) +{ + tu_fifo_clear(&s->ff); + tu_edpt_stream_read_xfer(daddr, s); +} + typedef struct { uint8_t daddr; uint8_t bInterfaceNumber; @@ -227,6 +238,12 @@ static inline cdch_interface_t* get_itf(uint8_t idx) return (p_cdc->daddr != 0) ? p_cdc : NULL; } +TU_ATTR_ALWAYS_INLINE +static inline uint8_t itf2idx(cdch_interface_t* p_cdc) +{ + return (uint8_t) (p_cdc - cdch_data); +} + static inline cdch_interface_t* get_itf_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr, &p_cdc->stream.tx); } +uint32_t tuh_cdc_write_available(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_available(&p_cdc->stream.tx); +} + uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); @@ -336,6 +361,14 @@ uint32_t tuh_cdc_read_available(uint8_t idx) return tu_edpt_stream_read_available(&p_cdc->stream.rx); } +void tuh_cdc_read_flush (uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc, ); + + tu_edpt_stream_read_clear(p_cdc->daddr, &p_cdc->stream.rx); +} + //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ @@ -463,6 +496,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback + if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(itf2idx(p_cdc)); // prepare for next transfer if needed tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 54e082e7d..dd8ae80ce 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -97,18 +97,32 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) return tuh_cdc_get_dtr(idx); } +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ + +// Get the number of bytes available for writing +uint32_t tuh_cdc_write_available(uint8_t idx); + // Write to cdc interface uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); // Force sending data if possible, return number of forced bytes uint32_t tuh_cdc_write_flush(uint8_t idx); -// Read from cdc interface -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); +//--------------------------------------------------------------------+ +// Read API +//--------------------------------------------------------------------+ // Get the number of bytes available for reading uint32_t tuh_cdc_read_available(uint8_t idx); +// Read from cdc interface +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); + +// Clear the received FIFO +void tuh_cdc_read_flush (uint8_t idx); + //--------------------------------------------------------------------+ // Control Endpoint (Request) API //--------------------------------------------------------------------+ @@ -132,47 +146,13 @@ static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, ui // Invoked when a device with CDC interface is mounted // idx is index of cdc interface in the internal pool. -TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx); +TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx); // Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx); - -/** \brief Check if the interface is currently busy or not - * \param[in] dev_addr device address - * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe. - * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device - * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device - * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer - * can be scheduled. User needs to make sure the corresponding interface is mounted - * (by \ref tuh_cdc_serial_is_mounted) before calling this function. - */ -// bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); - -/** \brief Perform USB OUT transfer to device - * \param[in] dev_addr device address - * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -// bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); - -/** \brief Perform USB IN transfer to get data from device - * \param[in] dev_addr device address - * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -// bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); +TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); + +// Invoked when received new data +TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS -- cgit v1.3.1 From cd9008e5a9c8da81d9736f7e0bf72c5ba409a7f1 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 13:05:45 +0700 Subject: add tuh_cdc_tx_complete_cb() callback --- examples/host/cdc_msc_hid/src/cdc_app.c | 4 ++-- src/class/cdc/cdc_host.c | 20 +++++++++----------- src/class/cdc/cdc_host.h | 3 +++ 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 23ea05b2b..dd3196146 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -87,7 +87,7 @@ void tuh_cdc_rx_cb(uint8_t idx) void tuh_cdc_mount_cb(uint8_t idx) { - tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); printf("CDC Interface is mounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); @@ -95,7 +95,7 @@ void tuh_cdc_mount_cb(uint8_t idx) void tuh_cdc_umount_cb(uint8_t idx) { - tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); printf("CDC Interface is unmounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ba2e9e1b7..ce0efe6e3 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -238,13 +238,7 @@ static inline cdch_interface_t* get_itf(uint8_t idx) return (p_cdc->daddr != 0) ? p_cdc : NULL; } -TU_ATTR_ALWAYS_INLINE -static inline uint8_t itf2idx(cdch_interface_t* p_cdc) -{ - return (uint8_t) (p_cdc - cdch_data); -} - -static inline cdch_interface_t* get_itf_by_ep_addr(uint8_t daddr, uint8_t ep_addr) +static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr == daddr) && (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { - return p_cdc; + return i; } } - return NULL; + return TUSB_INDEX_INVALID; } @@ -478,11 +472,15 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // TODO handle stall response, retry failed transfer ... TU_ASSERT(event == XFER_RESULT_SUCCESS); - cdch_interface_t * p_cdc = get_itf_by_ep_addr(daddr, ep_addr); + uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); + cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc); if ( ep_addr == p_cdc->stream.tx.ep_addr ) { + // invoke tx complete callback to possibly refill tx fifo + if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); + if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) { // If there is no data left, a ZLP should be sent if needed @@ -496,7 +494,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback - if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(itf2idx(p_cdc)); + if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); // prepare for next transfer if needed tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index dd8ae80ce..476431cc5 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -154,6 +154,9 @@ TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); // Invoked when received new data TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); +// Invoked when a TX is complete and therefore space becomes available in TX buffer +TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); + //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS //--------------------------------------------------------------------+ -- cgit v1.3.1 From 11233e4d3e04ceab1ad6e33d37a166aa48c436de Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 11:43:57 +0700 Subject: minor clean up --- examples/host/cdc_msc_hid/src/tusb_config.h | 4 ++++ src/class/cdc/cdc_host.h | 28 +++++----------------------- 2 files changed, 9 insertions(+), 23 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index c515405cb..e3d9356f6 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -108,6 +108,10 @@ #define CFG_TUH_HID_EPIN_BUFSIZE 64 #define CFG_TUH_HID_EPOUT_BUFSIZE 64 +//------------- CDC -------------// +// Set both DTR ( bit 0), RTS (bit 1) on enumeration/mounted +#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0x03 + #ifdef __cplusplus } #endif diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 02ae69111..5407c646d 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -49,7 +49,7 @@ // RX Endpoint size #ifndef CFG_TUH_CDC_RX_EPSIZE -#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX #endif // TX FIFO size @@ -59,7 +59,7 @@ // TX Endpoint size #ifndef CFG_TUH_CDC_TX_EPSIZE -#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX #endif //--------------------------------------------------------------------+ @@ -145,7 +145,9 @@ static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, ui return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } -//------------- Application Callback -------------// +//--------------------------------------------------------------------+ +// CDC APPLICATION CALLBACKS +//--------------------------------------------------------------------+ // Invoked when a device with CDC interface is mounted // idx is index of cdc interface in the internal pool. @@ -160,26 +162,6 @@ TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); // Invoked when a TX is complete and therefore space becomes available in TX buffer TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); -//--------------------------------------------------------------------+ -// CDC APPLICATION CALLBACKS -//--------------------------------------------------------------------+ - -/** \brief Callback function that is invoked when an transferring event occurred - * \param[in] dev_addr Address of device - * \param[in] event an value from \ref xfer_result_t - * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe - * \param[in] xferred_bytes Number of bytes transferred via USB bus - * \note event can be one of following - * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. - * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. - * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. - * \note - */ -// void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); - -/// @} // group CDC_Serial_Host -/// @} - //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -- cgit v1.3.1 From 05c119ce975668eff814c78d5306589fc2d24530 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 18:28:06 +0700 Subject: cdc host, add set line coding API --- examples/host/cdc_msc_hid/src/tusb_config.h | 11 ++- src/class/cdc/cdc.h | 28 ++++-- src/class/cdc/cdc_host.c | 129 +++++++++++++++++++++------- src/class/cdc/cdc_host.h | 16 +++- 4 files changed, 143 insertions(+), 41 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index e3d9356f6..139a921d1 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -109,8 +109,15 @@ #define CFG_TUH_HID_EPOUT_BUFSIZE 64 //------------- CDC -------------// -// Set both DTR ( bit 0), RTS (bit 1) on enumeration/mounted -#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0x03 + +// Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +// bit rate = 115200, 1 stop bit, no parity, 8 bit data width +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } + #ifdef __cplusplus } diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 6a9669cf2..9a3fc21ee 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -198,6 +198,22 @@ enum CDC_CONTROL_LINE_STATE_RTS = 0x02, }; +enum +{ + CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit + CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits + CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits +}; + +enum +{ + CDC_LINE_CODING_PARITY_NONE = 0, + CDC_LINE_CODING_PARITY_ODD = 1, + CDC_LINE_CODING_PARITY_EVEN = 2, + CDC_LINE_CODING_PARITY_MARK = 3, + CDC_LINE_CODING_PARITY_SPACE = 4, +}; + //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ @@ -207,13 +223,13 @@ typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. - CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, - CDC_NOTIF_RING_DETECT = 0x09, - CDC_NOTIF_SERIAL_STATE = 0x20, - CDC_NOTIF_CALL_STATE_CHANGE = 0x28, - CDC_NOTIF_LINE_STATE_CHANGE = 0x29, + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,///< CDC_NOTIF_AUX_JACK_HOOK_STATE + CDC_NOTIF_RING_DETECT = 0x09,///< CDC_NOTIF_RING_DETECT + CDC_NOTIF_SERIAL_STATE = 0x20,///< CDC_NOTIF_SERIAL_STATE + CDC_NOTIF_CALL_STATE_CHANGE = 0x28,///< CDC_NOTIF_CALL_STATE_CHANGE + CDC_NOTIF_LINE_STATE_CHANGE = 0x29,///< CDC_NOTIF_LINE_STATE_CHANGE CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred - CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,///< CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION }cdc_notification_request_t; //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index de1466cb1..fcabb922a 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,8 +52,8 @@ typedef struct { cdc_acm_capability_t acm_capability; uint8_t ep_notif; - // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - uint8_t line_state; + cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + uint8_t line_state; // DTR (bit0), RTS (bit1) tuh_xfer_cb_t user_control_cb; @@ -240,6 +240,13 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); break; + case CDC_REQUEST_SET_LINE_CODING: + { + uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); + memcpy(&p_cdc->line_coding, xfer->buffer, len); + } + break; + default: break; } } @@ -265,7 +272,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, .wValue = tu_htole16(line_state), - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -283,6 +290,46 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c return tuh_control_xfer(&xfer); } +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request); + + TU_LOG_CDCH("CDC Set Line Conding\r\n"); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_LINE_CODING, + .wValue = 0, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + }; + + // use usbh enum buf to hold line coding since user line_coding variable may not live long enough + // for the transfer to complete + uint8_t* enum_buf = usbh_get_enum_buf(); + memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + + p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = + { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = cdch_internal_control_complete, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + //--------------------------------------------------------------------+ // CLASS-USBH API //--------------------------------------------------------------------+ @@ -448,46 +495,70 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return true; } -static void config_cdc_complete(uint8_t daddr, uint8_t itf_num) +enum { - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + CONFIG_SET_CONTROL_LINE_STATE, + CONFIG_SET_LINE_CODING, + CONFIG_COMPLETE +}; - if (idx != TUSB_INDEX_INVALID) +static void process_cdc_config(tuh_xfer_t* xfer) +{ + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + TU_ASSERT(idx != TUSB_INDEX_INVALID, ); + + switch(state) { - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); + case CONFIG_SET_CONTROL_LINE_STATE: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT( tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, process_cdc_config, CONFIG_SET_LINE_CODING), ); + break; + #endif + TU_ATTR_FALLTHROUGH; - // Prepare for incoming data - cdch_interface_t* p_cdc = get_itf(idx); - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - } + case CONFIG_SET_LINE_CODING: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + { + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, 0), ); + break; + } + #endif + TU_ATTR_FALLTHROUGH; - // notify usbh that driver enumeration is complete - // itf_num+1 to account for data interface as well - usbh_driver_set_config_complete(daddr, itf_num+1); -} + case CONFIG_COMPLETE: + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); -#if CFG_TUH_CDC_SET_DTRRTS_ON_ENUM + // Prepare for incoming data + cdch_interface_t* p_cdc = get_itf(idx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); -static void config_set_dtr_rts_complete (tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - config_cdc_complete(xfer->daddr, itf_num); + // notify usbh that driver enumeration is complete + // itf_num+1 to account for data interface as well + usbh_driver_set_config_complete(xfer->daddr, itf_num+1); + break; + + default: break; + } } bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - return tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_SET_DTRRTS_ON_ENUM, config_set_dtr_rts_complete, 0); -} + // fake transfer to kick-off process + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); -#else + tuh_xfer_t xfer; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = CONFIG_SET_CONTROL_LINE_STATE; + + process_cdc_config(&xfer); -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) -{ - config_cdc_complete(daddr, itf_num); return true; } #endif - -#endif diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 5407c646d..9bf5af46c 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,11 +37,16 @@ // Class Driver Configuration //--------------------------------------------------------------------+ -// Set DTR ( bit 0), RTS (bit 1) on enumeration/mounted -#ifndef CFG_TUH_CDC_SET_DTRRTS_ON_ENUM -#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0 +// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) +#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 #endif +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM +//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +//#endif + // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX @@ -130,9 +135,12 @@ bool tuh_cdc_read_clear (uint8_t idx); // Control Endpoint (Request) API //--------------------------------------------------------------------+ -// Send control request to Set Control Line State: DTR (bit 0), RTS (bit 1) +// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// Request to Set Line Coding +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + // Connect by set both DTR, RTS static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -- cgit v1.3.1 From f33883c308959aa2ca08ef55282c82c54f929226 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 19:41:39 +0700 Subject: add tuh_cdc_get_local_line_coding() --- examples/host/cdc_msc_hid/src/cdc_app.c | 15 +++++++++++++-- src/class/cdc/cdc_host.c | 22 ++++++++++++++++++++-- src/class/cdc/cdc_host.h | 12 ++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index dd3196146..b1b137e0e 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -90,7 +90,18 @@ void tuh_cdc_mount_cb(uint8_t idx) tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is mounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); + printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); + +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration + // otherwise you need to call tuh_cdc_set_line_coding() first + cdc_line_coding_t line_coding = { 0 }; + if ( tuh_cdc_get_local_line_coding(idx, &line_coding) ) + { + printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); + printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity , line_coding.data_bits); + } +#endif } void tuh_cdc_umount_cb(uint8_t idx) @@ -98,5 +109,5 @@ void tuh_cdc_umount_cb(uint8_t idx) tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is unmounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); + printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 05e0bdfc7..17dc877f8 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,8 +52,8 @@ typedef struct { cdc_acm_capability_t acm_capability; uint8_t ep_notif; - cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width - uint8_t line_state; // DTR (bit0), RTS (bit1) + cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + uint8_t line_state; // DTR (bit0), RTS (bit1) tuh_xfer_cb_t user_control_cb; @@ -162,6 +162,20 @@ bool tuh_cdc_get_rts(uint8_t idx) return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + *line_coding = p_cdc->line_coding; + + return true; +} + +//--------------------------------------------------------------------+ +// Write +//--------------------------------------------------------------------+ + uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); @@ -194,6 +208,10 @@ uint32_t tuh_cdc_write_available(uint8_t idx) return tu_edpt_stream_write_available(&p_cdc->stream.tx); } +//--------------------------------------------------------------------+ +// Read +//--------------------------------------------------------------------+ + uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 9bf5af46c..502ad430d 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -102,6 +102,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) return tuh_cdc_get_dtr(idx); } +// Get local (saved/cached) version of line coding. +// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() +// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. +// NOTE: This function does not make any USB transfer request to device. +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); + //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ @@ -133,6 +139,7 @@ bool tuh_cdc_read_clear (uint8_t idx); //--------------------------------------------------------------------+ // Control Endpoint (Request) API +// Each Function will make a USB transfer request to/from device //--------------------------------------------------------------------+ // Request to Set Control Line State: DTR (bit 0), RTS (bit 1) @@ -141,6 +148,11 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c // Request to Set Line Coding bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// Request to Get Line Coding +// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and +// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined +// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding); + // Connect by set both DTR, RTS static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -- cgit v1.3.1 From 396716cc2c29b151556d554c560307afcadd7252 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 20:26:32 +0700 Subject: clean up --- examples/host/cdc_msc_hid/CMakeLists.txt | 2 +- src/class/cdc/cdc.h | 22 ++++++---------------- 2 files changed, 7 insertions(+), 17 deletions(-) (limited to 'examples/host') diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 2e89817a5..7af6b738e 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -15,8 +15,8 @@ add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c ) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 9a3fc21ee..2fecde3ca 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -41,16 +41,6 @@ /** \defgroup ClassDriver_CDC_Common Common Definitions * @{ */ -// TODO remove -/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In) -typedef enum -{ - CDC_PIPE_NOTIFICATION , ///< Notification pipe - CDC_PIPE_DATA_IN , ///< Data in pipe - CDC_PIPE_DATA_OUT , ///< Data out pipe - CDC_PIPE_ERROR , ///< Invalid Pipe ID -}cdc_pipeid_t; - //--------------------------------------------------------------------+ // CDC Communication Interface Class //--------------------------------------------------------------------+ @@ -223,13 +213,13 @@ typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. - CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,///< CDC_NOTIF_AUX_JACK_HOOK_STATE - CDC_NOTIF_RING_DETECT = 0x09,///< CDC_NOTIF_RING_DETECT - CDC_NOTIF_SERIAL_STATE = 0x20,///< CDC_NOTIF_SERIAL_STATE - CDC_NOTIF_CALL_STATE_CHANGE = 0x28,///< CDC_NOTIF_CALL_STATE_CHANGE - CDC_NOTIF_LINE_STATE_CHANGE = 0x29,///< CDC_NOTIF_LINE_STATE_CHANGE + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, + CDC_NOTIF_RING_DETECT = 0x09, + CDC_NOTIF_SERIAL_STATE = 0x20, + CDC_NOTIF_CALL_STATE_CHANGE = 0x28, + CDC_NOTIF_LINE_STATE_CHANGE = 0x29, CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred - CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,///< CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, }cdc_notification_request_t; //--------------------------------------------------------------------+ -- cgit v1.3.1