From b94c8f3bf36a468564a6a37c1dfc999dc804e912 Mon Sep 17 00:00:00 2001 From: savelij13 Date: Thu, 11 Sep 2025 09:17:24 +0300 Subject: [PATCH] fatfs v0.06 Apr 01, 2008: - 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. --- doc/00index_e.html | 22 +- doc/00index_j.html | 21 +- doc/css_e.css | 4 +- doc/css_j.css | 6 +- doc/en/appnote.html | 34 +-- doc/en/chmod.html | 12 +- doc/en/dinit.html | 2 +- doc/en/dioctl.html | 5 +- doc/en/dread.html | 4 +- doc/en/dstat.html | 4 +- doc/en/dwrite.html | 4 +- doc/en/filename.html | 4 +- doc/en/forward.html | 135 +++++++++++ doc/en/getfree.html | 8 +- doc/en/gets.html | 58 +++++ doc/en/lseek.html | 10 +- doc/en/mkdir.html | 2 - doc/en/mkfs.html | 8 +- doc/en/mount.html | 4 +- doc/en/open.html | 16 +- doc/en/opendir.html | 4 +- doc/en/printf.html | 72 ++++++ doc/en/putc.html | 54 +++++ doc/en/puts.html | 54 +++++ doc/en/read.html | 6 +- doc/en/readdir.html | 10 +- doc/en/rename.html | 2 +- doc/en/sfatfs.html | 4 +- doc/en/sfile.html | 4 +- doc/en/sync.html | 4 +- doc/en/truncate.html | 4 +- doc/en/unlink.html | 2 +- doc/en/utime.html | 2 +- doc/en/write.html | 7 +- doc/img/rw_ata.jpeg | Bin 66954 -> 0 bytes doc/img/rw_cfc.jpeg | Bin 32242 -> 0 bytes doc/img/rw_mmc.jpeg | Bin 29612 -> 0 bytes doc/img/rwtest.png | Bin 20474 -> 19068 bytes doc/img/rwtest2.png | Bin 0 -> 7547 bytes doc/ja/appnote.html | 32 +-- doc/ja/chmod.html | 10 +- doc/ja/dioctl.html | 7 +- doc/ja/dread.html | 2 +- doc/ja/dwrite.html | 2 +- doc/ja/filename.html | 2 +- doc/ja/forward.html | 134 +++++++++++ doc/ja/getfree.html | 8 +- doc/ja/gets.html | 58 +++++ doc/ja/lseek.html | 8 +- doc/ja/mkdir.html | 2 - doc/ja/mkfs.html | 8 +- doc/ja/mount.html | 2 +- doc/ja/open.html | 20 +- doc/ja/opendir.html | 2 - doc/ja/printf.html | 71 ++++++ doc/ja/putc.html | 54 +++++ doc/ja/puts.html | 54 +++++ doc/ja/read.html | 4 +- doc/ja/readdir.html | 10 +- doc/ja/sfatfs.html | 4 +- doc/ja/sfile.html | 4 +- doc/ja/stat.html | 3 +- doc/ja/write.html | 7 +- doc/updates.txt | 5 + patches.txt | 63 ++++++ src/00readme.txt | 84 ++++--- src/diskio.h | 4 +- src/ff.c | 498 ++++++++++++++++++++++++++++------------- src/ff.h | 32 ++- src/integer.h | 6 +- src/tff.c | 520 ++++++++++++++++++++++++++++++------------- src/tff.h | 28 ++- 72 files changed, 1804 insertions(+), 536 deletions(-) create mode 100644 doc/en/forward.html create mode 100644 doc/en/gets.html create mode 100644 doc/en/printf.html create mode 100644 doc/en/putc.html create mode 100644 doc/en/puts.html delete mode 100644 doc/img/rw_ata.jpeg delete mode 100644 doc/img/rw_cfc.jpeg delete mode 100644 doc/img/rw_mmc.jpeg create mode 100644 doc/img/rwtest2.png create mode 100644 doc/ja/forward.html create mode 100644 doc/ja/gets.html create mode 100644 doc/ja/printf.html create mode 100644 doc/ja/putc.html create mode 100644 doc/ja/puts.html create mode 100644 patches.txt diff --git a/doc/00index_e.html b/doc/00index_e.html index 33e84f5..82fc65a 100644 --- a/doc/00index_e.html +++ b/doc/00index_e.html @@ -3,8 +3,6 @@ - - ELM - FAT File System Module @@ -39,8 +37,8 @@

Application Interface

FatFs/Tiny-FatFs module provides following functions.

@@ -79,16 +83,18 @@

Resources

The FatFs/Tiny-FatFs module is a free software and is opened for education, research and development. You can use, modify and/or republish it for personal, non-profit or commercial use without any restriction under your responsibility.


-

FatFs Home Page

+

Return

diff --git a/doc/00index_j.html b/doc/00index_j.html index bd200d3..28a40e8 100644 --- a/doc/00index_j.html +++ b/doc/00index_j.html @@ -3,8 +3,6 @@ - - ELM - 汎用FATファイルシステム・モジュール @@ -22,8 +20,8 @@
  • ファイル・システム用とファイルI/O用バッファを分離し、複数ファイルの高速アクセスに適する
  • 複数ドライブ、複数パーテーションをサポート
  • FAT12, FAT16, FAT32に対応
  • -
  • 8.3形式ファイル名に対応(LFN未対応)
  • -
  • FDISKフォーマットおよびSFDフォーマットに対応
  • +
  • 8.3形式ファイル名に対応(LFNは未対応)
  • +
  • 2種類のパーテーショニング形式(FDISKおよびSFD)に対応
  • 8/16ビットマイコン向けにコードを最適化
  • Tiny-FatFsの特徴(FatFsとの相違)

    @@ -56,6 +54,11 @@
  • f_utime - ファイル/ディレクトリのタイムスタンプの変更
  • f_rename - ファイル/ディレクトリの名前変更・移動
  • f_mkfs - ディスクのフォーマット
  • +
  • f_forward - ファイル・データをストリーム関数に直接転送する
  • +
  • fgets - 文字列の読み込み
  • +
  • fputc - 文字の書き込み
  • +
  • fputs - 文字列の書き込み
  • +
  • fprintf - 書式化文字列の書き込み
  • @@ -78,16 +81,18 @@

    資料

    FatFs/Tiny-FatFsモジュールはフリー・ソフトウェアとして教育・研究・開発用に公開しています。どのような利用目的(個人・非商用・商用)でも使用・改変・配布について一切の制限はありませんが、全て利用者の責任の下での利用とします。


    -

    FatFs Home Page

    +

    戻る

    diff --git a/doc/css_e.css b/doc/css_e.css index 79f7848..9159576 100644 --- a/doc/css_e.css +++ b/doc/css_e.css @@ -38,8 +38,8 @@ p.hdd {float: right; text-align: right; margin-top: 0.5em;} hr.hds {clear: both; margin-bottom: 1em;} h2 {font-size: 1.5em; font-family: sans-serif; margin: 0 0 0.5em;} -h3 {font-size: 1.5em; font-family: sans-serif; margin: 2em 0 0.5em;} -h4 {font-size: 1.2em; font-family: sans-serif; margin: 1.5em 0 0.2em;} +h3 {font-size: 1.5em; font-family: sans-serif; margin: 1.5em 0 0.5em;} +h4 {font-size: 1.2em; font-family: sans-serif; margin: 1em 0 0.2em;} h5 {font-size: 1em; font-family: sans-serif; margin: 0.5em 0 0em;} small {font-size: 80%;} .indent {margin-left: 2em;} diff --git a/doc/css_j.css b/doc/css_j.css index a6346db..a49a2e4 100644 --- a/doc/css_j.css +++ b/doc/css_j.css @@ -2,7 +2,7 @@ /* Common style sheet for Tech Notes */ * {margin: 0; padding: 0; border-width: 0;} -body {margin: 8px; background-color: #e0ffff; font-color: black; line-height: 133%; letter-spacing: 1px; max-width: 1024px;} +body {margin: 8px; background-color: #e0ffff; font-color: black; line-height: 150%; letter-spacing: 1px; max-width: 1024px;} a:link {color: blue;} a:visited {color: darkmagenta;} a:hover {background-color: #a0ffff;} @@ -41,8 +41,8 @@ p.hdd {float: right; text-align: right; margin-top: 0.5em;} hr.hds {clear: both; margin-bottom: 1em;} h2 {font-size: 1.5em; font-family: sans-serif; margin: 0 0 0.5em;} -h3 {font-size: 1.5em; font-family: sans-serif; margin: 2em 0 0.5em;} -h4 {font-size: 1.2em; font-family: sans-serif; margin: 1.5em 0 0.2em;} +h3 {font-size: 1.5em; font-family: sans-serif; margin: 1.5em 0 0.5em;} +h4 {font-size: 1.2em; font-family: sans-serif; margin: 1em 0 0.2em;} h5 {font-size: 1em; font-family: sans-serif; margin: 0.5em 0 0em;} small {font-size: 80%;} .indent {margin-left: 2em;} diff --git a/doc/en/appnote.html b/doc/en/appnote.html index 8f63215..69ff944 100644 --- a/doc/en/appnote.html +++ b/doc/en/appnote.html @@ -24,24 +24,24 @@ These correspondence are defined in integer.h. This will not be a problem on mos
    -

    Memory Usage (R0.05a)

    +

    Memory Usage (R0.06)

    These are the memory usage on some target systems. The memory sizes are in unit of byte, D means number of logical drives and F means number of open files. All samples are optimezed in code size.

    - - - - - - - - - - - - - - - + + + + + + + + + + + + + + +
    AVRH8/300HPICMSP430TLCS-870/CV850ESSH2
    CompilergccCH38C30(gcc)CL430CC870CCA850SHC
    _MCU_ENDIAN1222112
    FatFs Code
    (Full, R/W)
    91469218915566627430
    FatFs Code
    (Minimum, R/W)
    58245756586140964710
    FatFs Code
    (Full, R/O)
    42684116418729863382
    FatFs Code
    (Minimum, R/O)
    30763134314322002610
    FatFs Work (Static)D*2+2D*4+2D*2+2D*4+2D*4+2
    FatFs Work (Dynamic)D*554+F*544D*554+F*550D*554+F*544D*554+F*550D*554+F*550
    Tiny-FatFs Code
    (Full, R/W)
    7566762673716894931459266580
    Tiny-FatFs Code
    (Minimum, R/W)
    4730481446834306628536704236
    Tiny-FatFs Code
    (Full, R/O)
    3564353235223226438926783022
    Tiny-FatFs Code
    (Minimum, R/O)
    2554267425952372337618562300
    Tiny-FatFs Wrok (Static)4644466
    Tiny-FatFs Work (Dynamic)544+F*28544+F*32544+F*28544+F*28544+F*28544+F*32544+F*32
    AVRH8/300HPICMSP430TLCS-870/CV850ESSH2ARM7
    Compilergcc(WinAVR)CH38gcc(C30)CL430CC870CCA850SHCgcc(WinARM)
    _MCU_ENDIAN12221122
    FatFs Code (Full, R/W)9280934893876728753811820
    FatFs Code (Min, R/W)58145798591340944742
    FatFs Code (Full, R/O)44024236437130543474
    FatFs Code (Min, R/O)30663158321321722630
    FatFs Work (Static)D*2+2D*4+2D*2+2D*4+2D*4+2
    FatFs Work (Dynamic)D*554+F*544D*554+F*550D*554+F*544D*554+F*550D*554+F*550D*554+F*550
    Tiny-FatFs Code (Full, R/W)7628766875607108950159786640
    Tiny-FatFs Code (Min, R/W)4684482046984390632236784236
    Tiny-FatFs Code (Full, R/O)3634360036183382455427223072
    Tiny-FatFs Code (Min, R/O)2524270026012398339018622300
    Tiny-FatFs Wrok (Static)4644466
    Tiny-FatFs Work (Dynamic)544+F*28544+F*32544+F*28544+F*28544+F*28544+F*32544+F*32544+F*32
    @@ -111,7 +111,7 @@ Currently the file object structure is held by application layer. This is not a
  • Efficient sector buffer management
    The FatFs module has only one sector buffer per logical drive. There is an ineffciency on random file access with many files simultanesously. When additional memory for the sector buffer is available, the file access performance will able to be improved with an advanced cache mechanism.
  • Long file name
    -There is an extended feature to handle long file name (LFN) up to 255 characters, in addition to 8.3 format file name, on FAT file system. To support this, 512 byte string buffer for file name and UCS-2 - Shift_JIS mutual conversion table are required. Therefore memory consumption of code and work area will be increased drastically. The FatFs module does not support this feature. The LFN on the FAT file system is a patent of Microsoft. When support it on the commercial products, you have to be licensed.
  • +There is an extended feature to handle long file name (LFN) up to 255 characters in addition to 8.3 format file name on the FAT file system. To support this feature, 512 byte string buffer for file name and Unicode - Local code mutual conversion table which occupies 256KB is required. Therefore memory consumption of code and work area will be increased drastically. The FatFs module currently does not support this feature. The LFN on the FAT file system is a patent of Microsoft. When use it on the commercial products, you have to be licensed.
  • Porting to RTOS
    When use FatFs module from only one task, no consideration is needed. However when make access to a logical drive from two or more tasks simultanesously, any exclusion control will be required. The FatFs module is also ported to a free RTOS based on μITRON by TOPPERS Project.
  • diff --git a/doc/en/chmod.html b/doc/en/chmod.html index 88758d4..c587dbf 100644 --- a/doc/en/chmod.html +++ b/doc/en/chmod.html @@ -23,18 +23,18 @@ FRESULT f_chmod (
    -

    Parameter

    +

    Parameters

    FileName
    Pointer to the null-terminated string that specifies a file or directory to be changed
    Attribute
    Attribute flags to be set in one or more combination of the following flags. The specified flags are set and others are cleard.
    - - - - - + + + + +
    AttributeDescription
    AM_RDORead only
    AM_ARCArchive
    AM_SYSSystem
    AM_HIDHidden
    AttributeDescription
    AM_RDORead only
    AM_ARCArchive
    AM_SYSSystem
    AM_HIDHidden
    AttributeMask
    diff --git a/doc/en/dinit.html b/doc/en/dinit.html index 939e505..f488b01 100644 --- a/doc/en/dinit.html +++ b/doc/en/dinit.html @@ -21,7 +21,7 @@ DSTATUS disk_initialize (
    -

    Parameters

    +

    Parameter

    Drive
    Specifies the physical drive number to initialize.
    diff --git a/doc/en/dioctl.html b/doc/en/dioctl.html index 3536040..aa19c4a 100644 --- a/doc/en/dioctl.html +++ b/doc/en/dioctl.html @@ -53,9 +53,10 @@ DRESULT disk_ioctl (

    Description

    The FatFs module uses only device independent commands described below. Any device dependent function is not used.

    +

    In read-only configuration, the disk_ioctl function is not needed.

    - - + +
    CommandDescription
    CTRL_SYNCMake sure that the disk drive has finished pending write process. When the disk I/O module has a write back cache, flush the dirty sector immediately. In read-only configuration, this command is not needed.
    CommandDescription
    CTRL_SYNCMake sure that the disk drive has finished pending write process. When the disk I/O module has a write back cache, flush the dirty sector immediately.
    GET_SECTOR_COUNTReturns total sectors on the drive into the DWORD variable pointed by Buffer. This command is used in only f_mkfs function.
    GET_BLOCK_SIZEReturns erase block size of the memory array in unit of sector into the DWORD variable pointed by Buffer. When the erase block size is unknown or magnetic disk device, return 1. This command is used in only f_mkfs function.
    diff --git a/doc/en/dread.html b/doc/en/dread.html index 8766939..d0f1015 100644 --- a/doc/en/dread.html +++ b/doc/en/dread.html @@ -17,7 +17,7 @@ DRESULT disk_read ( BYTE Drive, /* Physical drive number */ BYTE* Buffer, /* Pointer to the read data buffer */ - DWORD SectorNumber, /* Sector number to read from */ + DWORD SectorNumber, /* Start sector number */ BYTE SectorCount /* Number of sectros to read */ ); @@ -44,7 +44,7 @@ DRESULT disk_read (
    RES_OK (0)
    The function succeeded.
    RES_ERROR
    -
    Any error occured during the read operation.
    +
    Any hard error occured during the read operation and could not recover it.
    RES_PARERR
    Invalid parameter.
    RES_NOTRDY
    diff --git a/doc/en/dstat.html b/doc/en/dstat.html index b0cfb58..14560a7 100644 --- a/doc/en/dstat.html +++ b/doc/en/dstat.html @@ -21,7 +21,7 @@ DSTATUS disk_status (
    -

    Parameters

    +

    Parameter

    Drive
    Specifies the physical drive number to be confirmed.
    @@ -34,7 +34,7 @@ DSTATUS disk_status (

    The disk status is returned in combination of following flags.

    STA_NOINIT
    -
    Indicates that the disk drive has not been initialiezed. This flag is set on: system reset, disk removal and disk_initialize function failed, and cleared on: disk_initialize function succeeded.
    +
    Indicates that the disk drive has not been initialized. This flag is set on: system reset, disk removal and disk_initialize function failed, and cleared on: disk_initialize function succeeded.
    STA_NODISK
    Indicates that no medium in the drive. This is always cleared on fixed disk drive.
    STA_PROTECTED
    diff --git a/doc/en/dwrite.html b/doc/en/dwrite.html index 4d8b87c..7178dc8 100644 --- a/doc/en/dwrite.html +++ b/doc/en/dwrite.html @@ -30,7 +30,7 @@ DRESULT disk_write (
    Specifies the physical drive number.
    Buffer
    Pointer to the data to be written.
    -
    SectorNumber +
    SectorNumber
    Specifies the start sector number in logical block address (LBA).
    SectorCount
    Specifies the number of sectors to write. The value can be 1 to 255.
    @@ -44,7 +44,7 @@ DRESULT disk_write (
    RES_OK (0)
    The function succeeded.
    RES_ERROR
    -
    Any error occured during the write operation.
    +
    Any hard error occured during the write operation and could not recover it.
    RES_WRPRT
    The disk is write protected.
    RES_PARERR
    diff --git a/doc/en/filename.html b/doc/en/filename.html index ab54249..9157a23 100644 --- a/doc/en/filename.html +++ b/doc/en/filename.html @@ -12,7 +12,7 @@

    File and Path name on the FatFs module

    -

    The format of file and path name on the FatFs module is similer to MS-DOS. However it does not have a concept of current directory, all objects on the drive are specified in full path name from the root directory.

    +

    The format of file and path name on the FatFs module is similer to MS-DOS. However it does not have a concept of current directory like OS oriented file system. All objects on the drive are specified in full path name from the root directory.

     
      "[drive#:][/]directory/file"
    @@ -28,7 +28,7 @@
     
     

    The FatFs module supports only 8.3 format file name and long file name is currentry not supported. For directory separator, a '/' is used, not a '\'. Heading '/' is ignored and can be omitted.

    -

    The logical drive number is specified in a numeral with a colon. When the drive number is omitted, it means the default drive (0). As for the Tiny-FatFs, it has only one logical drive and always works as drive 0. Any drive number cannot be contained in the path name.

    +

    The logical drive number is specified in a numeral with a colon. When the drive number is omitted, it is assumed default drive (0:). As for the Tiny-FatFs, it has only one logical drive and always works as drive 0. Any drive number cannot be contained in the path name.


    diff --git a/doc/en/forward.html b/doc/en/forward.html new file mode 100644 index 0000000..22bfc79 --- /dev/null +++ b/doc/en/forward.html @@ -0,0 +1,135 @@ + + + + + + + +FatFs - f_forward + + + + +
    +

    f_forward

    +

    The f_forward function reads the file data and forward it to the data streaming device.

    +
    +FRESULT f_forward (
    +  FIL* FileObject,                 /* File object */
    +  UINT (*Func)(const BYTE*,UINT),  /* Data streaming function */
    +  UINT ByteToFwd,                  /* Number of bytes to forward */
    +  UINT* ByteFwd                    /* Number of bytes forwarded */
    +);
    +
    +
    + +
    +

    Parameters

    +
    +
    FileObject
    +
    Pointer to the open file object.
    +
    Func
    +
    Pointer to the user-defined data streaming function. For details, refer to the sample code.
    +
    ByteToFwd
    +
    Number of bytes to forward in range of UINT.
    +
    ByteFwd
    +
    Pointer to the UINT variable to return number of bytes forwarded.
    +
    +
    + + +
    +

    Return Values

    +
    +
    FR_OK (0)
    +
    The function succeeded.
    +
    FR_DENIED
    +
    The function denied due to the file has been opened in non-read mode.
    +
    FR_RW_ERROR
    +
    The function failed due to a disk error or an internal error.
    +
    FR_NOT_READY
    +
    The disk drive cannot work due to no medium in the drive or any other reason.
    +
    FR_INVALID_OBJECT
    +
    The file object is invalid.
    +
    +
    + + +
    +

    Description

    +

    The f_forward() is for only Tiny-FatFs and not supported on FatFs. It reads the data from the file and forward it to the outgoing stream without data buffer. This is suitable for small memory system because it does not require any data buffer at application module. The file pointer of the file object increases in number of bytes forwarded. In case of *ByteFwd < ByteToFwd without error, it means the requested bytes could not be transferred due to end of file or stream goes busy during transfering process.

    +

    This function is available when _USE_FORWARD == 1.

    +
    + + +
    +

    Example (Audio playback)

    +
    +/*-----------------------------------------------------------------------*/
    +/* Sample code of data transfer function to be called from f_forward     */
    +/*-----------------------------------------------------------------------*/
    +
    +UINT out_stream (   /* Returns number of bytes sent or stream status */
    +    const BYTE *p,  /* Pointer to the data block to be sent */
    +    UINT btf        /* >0: Transfer call (Number of bytes to be sent). 0: Sense call */
    +)
    +{
    +    UINT cnt = 0;
    +
    +
    +    if (btf == 0) {     /* Sense call */
    +        /* Return stream status (0: Busy, 1: Ready) */
    +        /* When once it returned ready to sense call, it must accept a byte at least */
    +        /* at subsequent transfer call, or f_forward will result FR_RW_ERROR. */
    +        if (FIFO_READY) cnt = 1;
    +    }
    +    else {              /* Transfer call */
    +        do {    /* Repeat while there is any data to be sent and the stream is ready */
    +            FIFO_PORT = *p++;
    +            cnt++;
    +        } while (cnt < btf && FIFO_READY);
    +    }
    +
    +    return cnt;
    +}
    +
    +
    +/*-----------------------------------------------------------------------*/
    +/* Sample code using f_forward function                                  */
    +/*-----------------------------------------------------------------------*/
    +
    +FRESULT play_file (
    +    char *fn        /* Pointer to the audio file name to be played */
    +)
    +{
    +    FRESULT rc;
    +    FIL fil;
    +    UINT dmy;
    +
    +    /* Open the audio file in read only mode */
    +    rc = f_open(&fil, fn, FA_READ);
    +
    +    /* Repeat until the file pointer reaches end of the file */
    +    while (rc == FR_OK && fil.fptr < fil.fsize) {
    +
    +        /* any other processes... */
    +
    +        /* Fill output stream periodicaly or on-demand */
    +        rc = f_forward(&fil, out_stream, 1000, &dmy);
    +    }
    +
    +    /* The read-only file object may be discarded without close */
    +    return rc;
    +}
    +
    +
    + + +
    +

    References

    +

    f_open, fgets, f_write, f_close, FIL

    +
    + +

    Return

    + + diff --git a/doc/en/getfree.html b/doc/en/getfree.html index ab91028..a721b96 100644 --- a/doc/en/getfree.html +++ b/doc/en/getfree.html @@ -56,7 +56,7 @@ FRESULT f_getfree (

    Descriptions

    -

    The f_getfree function gets number of free clusters on the drive. The sects_clust member in the file system object is refreting number of sectors per cluster, so that the free space in unit of sector can be calcurated with this. When _USE_FSINFO option is enabled, this function might return an inaccurate free cluster count on FAT32 volume. When it is disabled, this function will take a time on FAT32 volume.

    +

    The f_getfree function gets number of free clusters on the drive. The member csize in the file system object is refreting number of sectors per cluster, so that the free space in unit of sector can be calcurated with this. When _USE_FSINFO option is enabled, this function might return an inaccurate free cluster count on FAT32 volume. When it is disabled, this function will take a time on FAT32 volume.

    This function is not supported in read-only configuration and minimization level of >= 1.

    @@ -69,14 +69,14 @@ FRESULT f_getfree ( // Get free clusters - res = f_getfree("", &clust, &fs); + res = f_getfree("", &clust, &fs); if (res) die(res); // Get free space printf("%lu KB total disk space.\n" "%lu KB available on the disk.\n", - (DWORD)(fs->max_clust - 2) * fs->sects_clust / 2, - clust * fs->sects_clust / 2); + (DWORD)(fs->max_clust - 2) * fs->csize / 2, + clust * fs->csize / 2);
    diff --git a/doc/en/gets.html b/doc/en/gets.html new file mode 100644 index 0000000..9b4b218 --- /dev/null +++ b/doc/en/gets.html @@ -0,0 +1,58 @@ + + + + + + + +FatFs - fgets + + + + +
    +

    fgets

    +

    The fgets reads a string from the file.

    +
    +char* fgets (
    +  char* Str,        /* Read buffer */
    +  int Size,         /* Size of the read buffer */
    +  FIL* FileObject   /* File object */
    +);
    +
    +
    + +
    +

    Parameters

    +
    +
    Str
    +
    Pointer to read buffer to store the read string.
    +
    Size
    +
    Size of the read buffer.
    +
    FileObject
    +
    Pointer to the open file object structure.
    +
    +
    + + +
    +

    Return Values

    +

    When the function succeeded, Str will be returuned.

    +
    + + +
    +

    Description

    +

    The fgets() is a wrapper function of f_read(). The read operation continues until a '\n' is stored, reached end of file or buffer is filled with Size - 1 characters. The read string is terminated with a '\0'. When the file is already reached end of file or any error occured during read operation, fgets() returns a NULL. The EOF status can be examined with feof() macro.

    +

    This function is available when _USE_STRFUNC is 1 or 2. When it is set to 2, '\r' contained in the file is stripped.

    +
    + + +
    +

    References

    +

    f_open, f_read, fputc, fputs, fprintf, f_close, FIL

    +
    + +

    Return

    + + diff --git a/doc/en/lseek.html b/doc/en/lseek.html index 0a81d71..e90e4a2 100644 --- a/doc/en/lseek.html +++ b/doc/en/lseek.html @@ -50,7 +50,7 @@ FRESULT f_lseek (

    Description

    -

    The f_lseek function moves the file R/W pointer of an open file. The offset can be specified in only origin from top of the file. When an offset above the file size is specified in write mode, the file size is extended to the offset and the data in the extended area is undefined. This is suitable to create a large file quickly, for fast write operation without cluster allocation delay. After the f_lseek function succeeded, member fptr in the file object should be checked in order to make sure the R/W pointer has been moved correctry. In case of fptr is less than Offset, any of the followings has been occured.

    +

    The f_lseek function moves the file R/W pointer of an open file. The offset can be specified in only origin from top of the file. When an offset above the file size is specified in write mode, the file size is extended to the offset and the data in the extended area is undefined. This is suitable to create a large file quickly, for fast write operation without cluster allocation delay. After the f_lseek function succeeded, member fptr in the file object should be checked in order to make sure the R/W pointer has been moved correctry. In case of fptr is less than expected value, any of the followings has been occured.

    • In read-only mode, the Offset was clipped in file size.
    • The drive gets full during the file extending process.
    • @@ -63,16 +63,16 @@ FRESULT f_lseek (

      Example

           // Move to offset of 5000 from top of the file.
      -    res = f_lseek(&file, 5000);
      +    res = f_lseek(&file, 5000);
       
           // Forward 3000 bytes
      -    res = f_lseek(&file, file.fptr + 3000);
      +    res = f_lseek(&file, file.fptr + 3000);
       
           // Rewind 2000 bytes (take care on overflow)
      -    res = f_lseek(&file, file.fptr - 2000);
      +    res = f_lseek(&file, file.fptr - 2000);
       
           // Move to end of the file to append data
      -    res = f_lseek(&file, file.fsize);
      +    res = f_lseek(&file, file.fsize);
       
    diff --git a/doc/en/mkdir.html b/doc/en/mkdir.html index b0bd73d..dbb9c92 100644 --- a/doc/en/mkdir.html +++ b/doc/en/mkdir.html @@ -61,8 +61,6 @@ FRESULT f_mkdir (

    Description

    The f_mkdir function creates a new directory. This function is not supported in read-only configuration and minimization level of >= 1.

    -

    -

    diff --git a/doc/en/mkfs.html b/doc/en/mkfs.html index 1c98f57..dde6dda 100644 --- a/doc/en/mkfs.html +++ b/doc/en/mkfs.html @@ -30,7 +30,7 @@ FRESULT f_mkfs (
    PartitioningRule
    When 0 is given, a partition table is created into first sector on the drive and then the file system is created on the partition. This is called FDISK format. When 1 is given, the file system starts from the first sector without partition table. This is often called super floppy (SFD) format.
    AllocSize
    -
    Specifies allocation unit size (number of bytes per cluster). The value must be power of 2 in range of from 512 to 32768.
    +
    Specifies allocation unit size in number of bytes per cluster. The value must be power of 2 in range of from 512 to 32768. FAT64 (64KB/cluster on FAT16) is not supported.
    @@ -62,9 +62,9 @@ FRESULT f_mkfs (

    Description

    -

    The f_mkfs function creates a FAT file system on the drive. There are two partitioning rules, FDISK and SFD, for removable media. It can be selected with an argument. The FDISK format is recommended for most case. This function currently does not support multiple partition, so that existing partitions on the physical dirve will be deleted and re-created a partition occupies entire disk space.

    -

    The FAT sub-type, FAT12/FAT16/FAT32, is determined by only how many clusters on the drive and nothing else, according to the FAT specification issued by Microsoft. Thus which FAT sub-type is selected, is depends on the drive size and specified cluster size. The cluster size affects performance of file system and large cluster increases the performance, so that 32768 bytes per cluster is recommended for most case except for small drive.

    -

    This function is supported on only FatFs with _USE_MKFS option.

    +

    The f_mkfs function creates a FAT file system on the drive. There are two partitioning rules, FDISK and SFD, for removable media. It can be selected with an argument. The FDISK format is recommended for most case. This function currently does not support multiple partition, so that existing partitions on the physical dirve will be deleted and re-created a new partition occupies entire disk space.

    +

    The FAT sub-type, FAT12/FAT16/FAT32, is determined by number of clusters on the drive and nothing else, according to the FAT specification issued by Microsoft. Thus which FAT sub-type is selected, is depends on the drive size and the specified cluster size. The cluster size affects performance of file system and large cluster increases the performance, so that 32768 bytes per cluster is recommended for most case except for small drive.

    +

    This function is supported on only FatFs with _USE_MKFS option.

    diff --git a/doc/en/mount.html b/doc/en/mount.html index aed5691..7865690 100644 --- a/doc/en/mount.html +++ b/doc/en/mount.html @@ -44,8 +44,8 @@ FRESULT f_mount (

    Description

    -

    The f_mount function registers/unregisters a work area to the FatFs module. The work area must be given to the logical drive with this function before any other file function. To unregister a work area, specify a NULL to the FileSystemObject, and then the work area can be discarded.

    -

    This function only initializes the work area and registers its address to the internal table, any access to the disk I/O layer does not occure. The actual mounting process is performed depends on requirement in any other file funcitons with path name.

    +

    The f_mount function registers/unregisters a work area to the FatFs module. The work area must be given to the logical drive with this function prior to any other file function. To unregister a work area, specify a NULL to the FileSystemObject, and then the work area can be discarded.

    +

    This function only initializes the given work area and registers its address to the internal table, any access to the disk I/O layer does not occure. The volume mount process is performed on first file access after f_mount or media change.

    diff --git a/doc/en/open.html b/doc/en/open.html index c44488b..3d281e7 100644 --- a/doc/en/open.html +++ b/doc/en/open.html @@ -81,7 +81,7 @@ FRESULT f_open (

    Description

    -

    The created file object is used for subsequent calls to refer to the file. When close an open file object, use f_close function. If modified file is not closed correctly, the file will be collapsed.

    +

    The created file object is used for subsequent calls to refer to the file. When close an open file object, use f_close function. If modified file is not closed correctly, the file may be collapsed.

    Before using any file function, a work area (file system object) must be given to the logical drive with f_mount function. All file functions can work after this procedure.

    The mode flags, FA_WRITE, FA_CREATE_ALWAYS, FA_CREATE_NEW, FA_OPEN_ALWAYS, are not supported in read-only configuration.

    @@ -100,27 +100,27 @@ void main () // Register a work area for logical drive 0 - f_mount(0, &fs); + f_mount(0, &fs); // Open source file - res = f_open(&fsrc, "srcfile.dat", FA_OPEN_EXISTING | FA_READ); + res = f_open(&fsrc, "srcfile.dat", FA_OPEN_EXISTING | FA_READ); if (res) die(res); // Create destination file - res = f_open(&fdst, "dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE); + res = f_open(&fdst, "dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE); if (res) die(res); // Copy source to destination for (;;) { - res = f_read(&fsrc, buffer, sizeof(buffer), &br); + res = f_read(&fsrc, buffer, sizeof(buffer), &br); if (res || br == 0) break; // error or eof - res = f_write(&fdst, buffer, br, &bw); + res = f_write(&fdst, buffer, br, &bw); if (res || bw < br) break; // error or disk full } // Close all files - f_close(&fsrc); - f_close(&fdst); + f_close(&fsrc); + f_close(&fdst); // Unregister a work area before discard it f_mount(0, NULL); diff --git a/doc/en/opendir.html b/doc/en/opendir.html index 2e2ff39..0ab74ee 100644 --- a/doc/en/opendir.html +++ b/doc/en/opendir.html @@ -22,7 +22,7 @@ FRESULT f_opendir (
    -

    Parameter

    +

    Parameters

    DirObject
    Pointer to the blank directory object to be created.
    @@ -37,8 +37,6 @@ FRESULT f_opendir (
    FR_OK (0)
    The function succeeded and the directory object is created. It is used for subsequent calls to read the directory entries.
    -
    FR_NO_FILE
    -
    Could not find the directory.
    FR_NO_PATH
    Could not find the path.
    FR_INVALID_NAME
    diff --git a/doc/en/printf.html b/doc/en/printf.html new file mode 100644 index 0000000..d5857a3 --- /dev/null +++ b/doc/en/printf.html @@ -0,0 +1,72 @@ + + + + + + + +FatFs - fprintf + + + + +
    +

    fprintf

    +

    The fprintf function writes formatted string to the file.

    +
    +int fprintf (
    +  FIL* FileObject,     /* File object */
    +  const char* Foramt,  /* Format stirng */
    +  ...
    +);
    +
    +
    + +
    +

    Parameters

    +
    +
    FileObject
    +
    Pointer to the open file object structure.
    +
    Format
    +
    Pointer to the null-terminated format string.
    +
    ...
    +
    Optional arguments.
    + +
    +
    + + +
    +

    Return Values

    +

    When the function succeeded, number of characters written is returned. When the function failed due to disk full or any error, an EOF will be returned.

    +
    + + +
    +

    Description

    +

    The fprintf() is a wrapper function of fputc() and fputs(). The format control directive is a sub-set of standard library. It supports c s d u X for the data type, l for the precision and 0 for the flags.

    +

    This function is available when read-write configuration and _USE_STRFUNC is 1 or 2.

    +
    + + +
    +

    Example

    +
    +    fprintf(&fil, "%6d", -200);         // "  -200"
    +    fprintf(&fil, "%02u", 5);           // "05"
    +    fprintf(&fil, "%ld", 12345678L);    // "12345678"
    +    fprintf(&fil, "%08lX", 1194684UL);  // "00123ABC"
    +    fprintf(&fil, "%s", "String");      // "String"
    +    fprintf(&fil, "%c", 'a');           // "a"
    +
    +
    + + +
    +

    References

    +

    f_open, fputc, fputs, fgets, f_close, FIL

    +
    + +

    Return

    + + diff --git a/doc/en/putc.html b/doc/en/putc.html new file mode 100644 index 0000000..882d2a5 --- /dev/null +++ b/doc/en/putc.html @@ -0,0 +1,54 @@ + + + + + + + +FatFs - fputc + + + + +
    +

    fputc

    +

    The fputc funciton puts a character to the file.

    +
    +int fputc (
    +  int Chr,          /* A character to put */
    +  FIL* FileObject   /* File object */
    +);
    +
    +
    + +
    +

    Parameters

    +
    +
    Chr
    +
    A character to be put.
    +
    FileObject
    +
    Pointer to the open file object structuer.
    +
    +
    + + +
    +

    Return Values

    +

    When the character was written successfuly, the function returns the character. When the function failed due to disk full or any error, an EOF will be returned.

    +
    + + +
    +

    Description

    +

    The fputc() is a wrapper function of f_write(). This function is available when read-write configuration and _USE_STRFUNC is 1 or 2. When it is set 2, a '\n' is extended to "\r\n".

    +
    + + +
    +

    Reference

    +

    f_open, fputs, fprintf, fgets, f_close, FIL

    +
    + +

    Return

    + + diff --git a/doc/en/puts.html b/doc/en/puts.html new file mode 100644 index 0000000..32faae7 --- /dev/null +++ b/doc/en/puts.html @@ -0,0 +1,54 @@ + + + + + + + +FatFs - fputs + + + + +
    +

    fputs

    +

    The fputs function writes a string to the file.

    +
    +int fputs (
    +  const char* Str,  /* String */
    +  FIL* FileObject   /* File object */
    +);
    +
    +
    + +
    +

    Parameters

    +
    +
    Str
    +
    Pointer to the null terminated string to be written. The null character will not be written.
    +
    FileObject
    +
    Pointer to the open file object structure.
    +
    +
    + + +
    +

    Return Value

    +

    When the function succeeded, number of characters written (not minus value) is returned. When the function failed due to disk full or any error, an EOF will be returned.

    +
    + + +
    +

    Description

    +

    The fputs() is a wrapper function of fputc(). This function is available when read-write configuration and _USE_STRFUNC is 1 or 2. When it is set 2, a '\n' is extended to "\r\n".

    +
    + + +
    +

    Reference

    +

    f_open, fputc, fprintf, fgets, f_close, FIL

    +
    + +

    Return

    + + diff --git a/doc/en/read.html b/doc/en/read.html index fa4984e..a843200 100644 --- a/doc/en/read.html +++ b/doc/en/read.html @@ -34,7 +34,7 @@ FRESULT f_read (
    Number of bytes to read in range of UINT.
    ByteRead
    Pointer to the UINT variable to return number of bytes read.
    - +
    @@ -57,13 +57,13 @@ FRESULT f_read (

    Description

    -

    The file pointer in the file object increases in number of bytes read. The ByteRead will become less than ByteToRead when the read pointer reached to end of the file or any error occured during the read operation.

    +

    The file pointer of the file object increases in number of bytes read. After the function succeeded, *ByteRead should be checked to detect end of file. In case of *ByteRead < ByteToRead, it means the R/W pointer reached end of file during read operation.

    References

    -

    f_open, f_write, f_close, FIL

    +

    f_open, fgets, f_write, f_close, FIL

    Return

    diff --git a/doc/en/readdir.html b/doc/en/readdir.html index 996d683..97d21fb 100644 --- a/doc/en/readdir.html +++ b/doc/en/readdir.html @@ -62,15 +62,15 @@ void scan_files (char* path) DIR dirs; int i; - if (f_opendir(&dirs, path) == FR_OK) { + if (f_opendir(&dirs, path) == FR_OK) { i = strlen(path); - while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0]) { - if (finfo.fattrib & AM_DIR) { - sprintf(&path[i], "/%s", &finfo.fname[0]); + while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0]) { + if (finfo.fattrib & AM_DIR) { + sprintf(&path[i], "/%s", &finfo.fname[0]); scan_files(path); path[i] = 0; } else { - printf("%s/%s\n", path, &finfo.fname[0]); + printf("%s/%s\n", path, &finfo.fname[0]); } } } diff --git a/doc/en/rename.html b/doc/en/rename.html index 503b896..e38ca10 100644 --- a/doc/en/rename.html +++ b/doc/en/rename.html @@ -22,7 +22,7 @@ FRESULT f_rename (
    -

    Parameter

    +

    Parameters

    OldName
    Pointer to a null-terminated string specifies the old file/directory name to be renamed.
    diff --git a/doc/en/sfatfs.html b/doc/en/sfatfs.html index 72a70a0..18c14bc 100644 --- a/doc/en/sfatfs.html +++ b/doc/en/sfatfs.html @@ -27,7 +27,7 @@ typedef struct _FATFS { DWORD last_clust; /* Last allocated cluster */ DWORD free_clust; /* Number of free clusters */ BYTE fs_type; /* FAT type (0:Not mounted) */ - BYTE sects_clust; /* Sectors per cluster */ + BYTE csize; /* Sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ BYTE drive; /* Physical drive number */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ @@ -50,7 +50,7 @@ typedef struct _FATFS { CLUST last_clust; /* Last allocated cluster */ CLUST free_clust; /* Number of free clusters */ BYTE fs_type; /* FAT type (0:Not mounted) */ - BYTE sects_clust; /* Sectors per cluster */ + BYTE csize; /* Sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ BYTE win[512]; /* Disk access window for Directory/FAT/File */ diff --git a/doc/en/sfile.html b/doc/en/sfile.html index 1b50210..2b2ed67 100644 --- a/doc/en/sfile.html +++ b/doc/en/sfile.html @@ -19,7 +19,7 @@ typedef struct _FIL { WORD id; /* Owner file system mount ID (inverted) */ BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ + BYTE csect; /* Sector address in the cluster */ FATFS* fs; /* Pointer to the owner file system object */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ @@ -37,7 +37,7 @@ typedef struct _FIL { typedef struct _FIL { WORD id; /* Owner file system mount ID (inverted) */ BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ + BYTE csect; /* Sector address in the cluster */ FATFS* fs; /* Pointer to owner file system */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ diff --git a/doc/en/sync.html b/doc/en/sync.html index de93af1..a6e304d 100644 --- a/doc/en/sync.html +++ b/doc/en/sync.html @@ -12,7 +12,7 @@

    f_sync

    -

    The f_sync function flushes the cached information of a wriiting file.

    +

    The f_sync function flushes the cached information of a writing file.

     FRESULT f_sync (
       FIL* FileObject     /* Pointer to the file object */
    @@ -21,7 +21,7 @@ FRESULT f_sync (
     
    -

    Parameters

    +

    Parameter

    FileObject
    Pointer to the open file object to be flushed.
    diff --git a/doc/en/truncate.html b/doc/en/truncate.html index 847f3b1..f0fb55e 100644 --- a/doc/en/truncate.html +++ b/doc/en/truncate.html @@ -21,7 +21,7 @@ FRESULT f_truncate (
    -

    Parameters

    +

    Parameter

    FileObject
    Pointer to the open file object to be truncated.
    @@ -48,7 +48,7 @@ FRESULT f_truncate (

    Description

    -

    The f_truncate function truncates the file size to the current file R/W point. When the file R/W pointer is pointing end of the file, there is no effect. This function is not supported in read-only configuration and minimization level of >=1.

    +

    The f_truncate function truncates the file size to the current file R/W point. When the file R/W pointer is already pointing end of the file, there is no effect. This function is not supported in read-only configuration and minimization level of >=1.

    diff --git a/doc/en/unlink.html b/doc/en/unlink.html index 33a0e73..6cfa50b 100644 --- a/doc/en/unlink.html +++ b/doc/en/unlink.html @@ -21,7 +21,7 @@ FRESULT f_unlink (
    -

    Parameters

    +

    Parameter

    FileName
    Pointer to the null-terminated string that specifies a file or directory to be removed.
    diff --git a/doc/en/utime.html b/doc/en/utime.html index b203581..0bea3a8 100644 --- a/doc/en/utime.html +++ b/doc/en/utime.html @@ -22,7 +22,7 @@ FRESULT f_utime (
    -

    Parameter

    +

    Parameters

    FileName
    Pointer to the null-terminated string that specifies a file or directory to be changed.
    diff --git a/doc/en/write.html b/doc/en/write.html index 3e14a5b..58cf54b 100644 --- a/doc/en/write.html +++ b/doc/en/write.html @@ -24,7 +24,7 @@ FRESULT f_write (
    -

    Parameter

    +

    Parameters

    FileObject
    Pointer to the open file object structure.
    @@ -57,13 +57,14 @@ FRESULT f_write (

    Description

    -

    The read/write pointer in the file object is increased in number of bytes written. The ByteWritten will become less than ByteToWrite when the drive gets full during the write operation. This function is not supported in read-only configuration.

    +

    The read/write pointer in the file object is increased in number of bytes written. After the function succeeded, *ByteWritten should be checked to detect disk full. In case of *ByteWritten < ByteToWrite, it means the disk got full during write operation.

    +

    This function is not supported in read-only configuration.

    Return

    diff --git a/doc/img/rw_ata.jpeg b/doc/img/rw_ata.jpeg deleted file mode 100644 index 2b97d93690b095440359d5e9f4685be51b7f9ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66954 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

    >&+MCz+nP&VF9^t<`VuE%MI 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 diff --git a/doc/img/rw_cfc.jpeg b/doc/img/rw_cfc.jpeg deleted file mode 100644 index c92d5fe882e6ff751a258ac4c1237fc31bcbd88c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32242 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
    A!|GbfO;bh8X!(ZB^a%r{mIAIP9|YQ2P5r zk&*1~mD&!$EmfEitzn@yvXaMD8*sNZQo z#Y)pz%4kl>zqwS!@9InS4|@ix$8Ks0FCZR`^AXrlmHRwL3d=#_#d9l12^1>z&Zd7T zL4I8Qc$Q=QlP@=m{lX#v`X`CMy-L&0xrHlbq3{0VcyB+!m?Nqx$pLxsP|P&&6T~b4 z)NT7U4)?M%MYVP;A8#!3BUI*Rk+hM6vP%OKsn^c9*~Ei?YXudhHo-L7_mR;j1a{Y{W3jfCtcr0NYDZWF-t; zXk_mu@G9QMSVtPHv1MTFRT=m8pZLvnw8dd0wB^;;>m)_!?A7G;tGm_Aj&DY z&YNqS7;+im2FuhljGPk|FfJSp@3R1lt+UouQ+2}?h|6~@Jll4i^Oz=yK;j9K?EcK` z%Av-g=3}QbRnwl9d6gYbAs(E@Hyz-DRH!Jn8^cnL{me1R_l=uwRpp6I#Web$E(mu4 z+P_#9zEkx-_s`S={m1GHkHZmJr`z>E)<6I!xnHOPfk%q{Ozge2m=V8d`rciG0xENK zn2+U0V+5ebu-pNFUD(Mi3F*o<-L<-yKpl-lkwS30e&JXF?mxLpwXb*qQT$Hgp0hKE_vU}K4MKOE$El9txXdZU?>SBSDs%4;1{p|3 zRIVo^Hx06}9miJ?uX$RPj*jELoW@kB87DmgFx(jSh7joQ4M&NEL;9StgSk`x*+nUi A0{{R3 diff --git a/doc/img/rw_mmc.jpeg b/doc/img/rw_mmc.jpeg deleted file mode 100644 index 5f8115e1d82dc70eda06d6831b344f3a6f6a5a7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29612 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 PM?`lB&PeVPf`9+nLqPee diff --git a/doc/img/rwtest.png b/doc/img/rwtest.png index f3cacfbb41ca313729086cc9a93bee4d55f026db..a34bf06212fb214689ab3e6600041c9c7751713f 100644 GIT binary patch literal 19068 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 DAZV+8 literal 20474 zcmbq*bzBr*-}bUg!?FtqQo_9=3kVB{tfV4>64FwV(jg7f z64FYiq|`gR`n&J@jpvW&dH>+UXNH+GXU@!=>wCo^O!KZXl#+!K1Oh=-RZ!X>5Cj4I zlo3OKJ+lwiNq}FMHPv-*0>95dpgVW&*xA|n`T0G6{v6m&Oiawp&8@GmZ*6TI=S0(bOV8Cn(;qGae_3gAP@qiic-+^N?NP={!pyFW`Q|> z#Aip*D4;>-6RhH?4-17TL}D$7*iC%hlBXw6G-M#s&;4UWjj>E*xSZL&;fJ@AYK&fS zHg|RRn{oGf1U(SBtzN!`k?rIj`~Jk`+K1C;emt^S>DpW4UPm`?)#_PUTU$Td4s+S( z&M2;BU}i|^z&bql`v__kFa^JaJ_@?S~8`87PwL%8j~J>FG$G1|+$e)!>J7;WqH#uihf#x^&_(t5Oy z>zWX(HBI|T8JuTTT~FnOIyLBrT<3m@c2?Us<-s1>5MOoZoJv(up19^rzfIFSMp_?4 z+US-V<@u^Bso5~)Cspv*9ja<{=)B}{nr9nDeZz;zI|3wuF6T0*N%kiScjCQ=zn%Xf z0WN;PwqYpX=4;#{|AZuw1FjF6!kqwTCONmitLawbyU)<)X0f6hdx z=D=muxA)4gZJ5>WXymeb(c88O!`!b6`M2FjxU#W6M>E)C+{y2%6YkT7Cf-HI!m0-@ zF(=oFifcwJKZjimii-EYpvKLU7UaIC?;NNVdaPJefA;jwX}(N}zlPj=&ynoRxq^_? ziPvMty$rQ6@4fGr(i&Rpis&=Ii8IUTUt0zYXIDaIb|rFSX~@sSE#zU}I7NpK&y*hb z1>QJ~Gvx~`p}+$5(K+ zc}X{V#o&gsEGk@X1y4L2`b;o>-Et@5f(g78{PNG%a}I*e>+Cas#$r}}ys<8OSg)GI z4gaEHU_nVfP-Pd}V;=TU5=tCHUw1d%O^RYZS<-4_DJJ}cyZ431`;(2Lj%Abq!(5Mp zfZM(ybmmxW;Z_YSQ!uEY{SZ21e*e1ha?}{gPtQg5EJvItsFT6$J$0d$?fjRwP<17+ zH*1wz{}YANfr?IzONPZlm1N0mhRZPKo9o9sK6-jLm#c<|i`}cFxX!dBmp8~$CMMOb zKmP2@I|R>gM3qOi`oRR>rQPwb;l6FH;$x~W6#J9|b94@8kTfCiffKWHD5?KSdX{UE zSS_C4lh2$bVpcZcjy5&buPv+cj~0rNhcUQ4lwb#5{2ST3%-* zPA*ETfA?6eRc>KY0@nngaWsa|wgh%()ppQ{3UG`1=oPOas!VQy^A2W_g9S`*eGXw+ z2SnZ>5y|`ruEWHv+|BHVM0s$~7SUPyEH~MvIm)R3jdiH3X<=Owrimbagg|8yk>U_l z+V#=hV7hal$I2qZ9DUoBtIWk~qTXw9T_$em!o&kjvnSjBTia)T*%&NU!unM~?0}vb z%dG~p7%vtI#4Pn_x2zIr45n~7Cg7}n7&1Ek6^S%MZLS3|s91lLM(`l2ImN^$HT=d7 z&8$leSNwRSXC+s4awLNFey0wKdOdp@R_ZYrvO{kuhGBcaS}bhASp`)9>zd5x7z`i_ zIf}*ktj0lf?=})k72CV?$b(NjD|^dNv7gy}`Z{NhF(!py(B>3jW~4`ct^%SFAHALn z@}v^$il=q>ZPtH`?a_ZOW`W!k$o+1SptCIy@d_#N%{jav#Hx$FGLpr8HQS|$eUyV6 zS8y2i{7Tt(-Jf6LOsyXw!n6adQ6djP+u?C976o@)RHMu{a$W>sZ%u5|v|KoQkNGq@ zQZ6jo^MvIJqC7{V|0OhLJrn`=R(NO5aN+q4?;cw2cm`xb%EfOMszK+1~fX?>6nH|?kr z;=-P3&DWU`YD8+Lf1}b|o}2T|AT4%vAlG2Ss?gAV6-&DY{igMs7MEq&X1NXw(a4o~ z)2TRx{o_34cSmn*B^!ojI1XTC(CnsLqE$gA*b2t^iwb8<|8!F2#*<=tk?9G*9$v^pVJ(PIX zh73G2s?+)aI{4_S+t7FTjBVTK%#SUt6eMeWfx+)h!P6k8l7L?yi5!QB@l{O{v>G&9-q_|yRr*Sf$h++=b8jf%CuqspW?dvFqN8zxuI>A>^yanT zx9i^n+`If&x7TcvILVqTz-=Uts~mcAU*Y>S zr-DMbrshx@#><^N2L6@PuXFtagDyo}Abp)Y+8SZVO?^UJg_Rt}>M# zO}&Z)KQfXbK}dbMOdP>W%EKSWgv--b0kz-eBjWj7ao8CnOM%emp@KxmT%%XHD@#lF z=Gn+d6?L&-`gPoDv>0Z-^co*-^%@jxY-5pgUPX7zySCn8rnFd`A?;$xN*)s~DLS@v zG*}lzLwWAd=3X3gP9BIalS{-qthA$e*zbeG8WX8L!Y04W6~Xxp^J*wD2+0=_ zaN=$*be1!0bH(?G_uBK(^PROF#eCegCowvz9@K6XV^`_Vo=5~4)chO%|Bkpf;zhO* zqB%FOFi2Y#9+6Qmj2RQ!^LIOmcfeE^mHfI8(E@qx`1*nh!m?vFl$egx!LDWu%MeL+ zbyS-H_Z38U|J)ttV0M-7$Q^qe1&^87V6uf%yl<$`MT&XpX_)8!%>KOWm1muCUd{$G zhKgl}!72{?ezy;TCa+{*7O%U3*j2QsZiAPI{XWEX`*QspyRmSsYLkkOa<*@dj0UyJ zMwb*ItX&12(Xt^5CMFyVI!uZ)$@HxAJE6YosdQz8Ct$`gfmMGx9zuIVG^JsoJ@om| z1^W^$GIQ%YP73XZVItt`7In>fS{3Z|K4PVyCFHk;w-+eq_USKqA>!_7g4?FTQv*!A zTY7MFu9j|}IMGSl3!d$UXR|_@H}*-F&NafLBc-z<1YzkFBpG~%v(_G;rR452=vLJD zmkW>M+?*?yBn6kmtV`vmR6MwyE_wqN>z+fIrv z7e-7X*QzJbz54v=KQXao@5FE-xlRYM-Y1tUj1#UowlD3!b87^yV|bzIoL{j}*KphFSYPz0Sk4O_+Q+8;;N$Q$&f%Tl&0O zmY2AuLIx?DV@Gv>cPm>cYb-Qc+gG5}FcH?Q?5k$1$&Te_Jf|gp2!(AAY$;IH@^OU6 z-Jcfu8bE4sNvAevprN^ib^FWM`Ci!h{Lb0yxamiSHb*(0JEFN3;ze6p@6IOJ9wAPs z8u!&z)*|1kw>P*wKnp*;1^;%g)b=w=#0ql$o=_?yI|U4Uvar7~u26wGQ!RjSr?(0% z&vuh>LF%?$4HfR|3?{ER2z`WjTMhO7a9%Js0vb1{em;~U@9TapIJZ@v+b_z$fPMdC zgy$@CD#nTgb4Sa!EVt-7HA>w_!Jo3w(_g8~nza#=C9lymfbe6K`E!DeDK&XYV zA*wHP&(Xm05fk>h61)ENkie6(hiZ9zUog`t3Fi|ODoQJF9);c&Iek^r0bmiLL=c1QhmANl;ateb`X*H<6PCO&YUR+FIp@K8SZg^)WV!>4aw3 z$T|5(Rt06|JDazMnj4X4hlLH8q_;5-E!4Fb6I+b4pfBAz+SiWPxd`L>8QGx{#Uy8C%kVE$-NFER9Y)x9a$uqBO_=|pV-nDj7KvWy3JeSk7 z@Z$b^WsxIP{$09p`LV3I?uc0m3U5S)aMsQ46FG_tr5sr-YQHe^6FR*(vgova6Gj76;3H$tY+lp|YCv9cc$>PvG77`TADzu3C(xZ@RRq!eG6gf-RN;f&`jYQXozslVTjvuv`!BMv> z7>3zxP$Rqa6uRxy%d%vHNQCY{qG{@SsflH9v%?jG@AAA3o{}OQx{~rfbTxc?ow`TO zSSUt`mFkzy`v48Q75iJl%7?^oW`DE?o{V~@y=&X{NjplTrD@|Dh+-D$$9gqiH;o-u z*Gr0$HF}oqgV0e0s|HWmf>J-EQKTNWKV`l8*#?xVci)2rmhS2h*IZ1A)wi&hgLAA2 zJ1GE2{pT|v+}sb$b&LPeF1-_|K*X~#o$T&@KZHy32xU86X{Pp@AMQk{WEY!B>n>^G zC({WMu7`;dK#l7Qk0vsqt=&+bEp=l0rAO0p_aL@f9Gm&h77ij#4c%<(8}P>*Wn*M0 z5uPZ=9i_)KwqWx26GcQYHtaVks~b~cneQ@50)-H#)R*iO+NCB(Mx$CGU{B%e-(l^X zY}iW{Eve6}NSpzn`L)gLm;7qoNK}-f3c7{-Q2ve>cVxS&T%kJ6P;kF-7c@))-zw$5 zKz^g5MCrk?zsxgg1ksCQ-akb_r7_<|(;8LLQ*S0`#}^XBI2}0(KB*P+Boc>(Nkp7t z6_jE(eFW%*qXGqad7ib``!d+?nZ4iN%N&(@D(9Bd-592Oo>2ODtEv!f>FGbBx*fZj zTNkqae&WKfzh^Y65zwsmQfR2tqgN>9qs5mvia_C zmOLNJt{A*j{s>K|33|Yl#-ZzB-<(r|?lBsCeC}E&#P&G*e9^DR5V<#(mFl9bCP|}ebGad_!HeW1g3$-{h0(*bMA@!T}7?a+H zR?z#WP`-Ud09LuGU90Rx+6Q68syG)G#W`avwtw~ ziBQ#j0r#EY#NeCAa6`>splIqkUj&u2(vIPbrD2P37G)2dyCREa*XxrcyV83C%AX?_ z5v5>nqh=g50rnrrPCm`V@2?iYx9YXI& zby&X<2q1XK@rGjd;XQprD#}h5lmv6+DG8>4eDx%Qx0N(9D)7x(uG#)vd&I26p`D98 z6(xq+z!)yl7r<4R>dY|dQtYsR-d_oX+xk=W>-Sh zjaFj*9`*h7rs%}jL^Sfni^E#i1c-Mjr4(`pE_J~rg^s+z+5?&Yi9Y;S2!3J*+Vl-_ zm8Xt}5Y0bOU5)wSS9XJ0MXYZ36H+k=Ne^-r77%gh^$=$a#S}g?DZW7JdjxJ9y0Lxr zRSM@^2GP9OvX8FIO{5|W1z~osR}!Q?xOcrQx06hAqC+CM2AnyXP*Vb)p=G2a<0@7n z%>0*eZ=9G!LmNgbLH$3!f8Oddu9mB^8By{ay`bb))T@nbwBuD83PHOlg&XVir}=b( zU-E}N3PF<<-$y)P!^$h!kX*G)V>ezIfXw6&tF-&8JkIacv<@AEnMP*VBl`u$bh??QO`bVNyssSyvpq$UsgFFFXV1LHYqn$*Rif+MCAu@QRPiG0yK ze9-OEPDMIj@y)jg`kGFKoE8V#&}L5EQv#|kW)*|GvcJR+Kl{(*<{=o?-m+s&V)_jX zjmYP73M9VpgU$yjZVUkzcN*NSH~`Jnu#*ccXS3c2FkG#%9*4^^8OxddIO6;OZ=0(v z`qkPpnTt^$h4mTjcsV9ubh$aCf$`C!Y9>4Xx1t@Kb=LebRhas>__24Mxm%U-kRiW$ z7IP21*_G8W(g(t-Yx$Z{;vqHalf?Oo6eyO7GMJlLZ-H;2`aJ=w;MirlXu7##8Jv1I zn5T+f8w&3mYBmo0SuypA0C-ShE;V7HYmcu$$Yb!1?zW461rrt7J@m*tY z6N~1~S27(j7zhatzE3}kQRk<}R%a9Gi7iJ90h4xo-UnR@{gIH(7#_`BfdhZwc;sMy zWX>2owshp~8ne)S`*XO}L4h!926%om06~N|1fZow?@Y3byL7YgRa+t~ybEEXOg&_&P%;3OA?Zub9lYuJ>U4%8$QguKcH3t&z^?$r8r_R!@Nb?Wh znU8$?cH^GVVDfFJcpGpZEDr*{LROUd<+GM=IKYRfdBo7KEI;T(^=sp|S*TD2?$dZ8 zSXej)0u-r+#rqjBE7mW;8aajPhiWO&8&EH|ljLvy4{<7-P*l_#s`-I|+Kxo_whI_# z{huc~iW2CPGXxrEyP83Jbn>FYf4M=^u{F+FX>elwv8*X9{S^r>Mur_;@vvdZ|IMT* zks-#ov2M>|Xz`8h=8*LMTc?H}*A8SV?-rSv(LG6{(TXdru+OCeigY?>InJ!ZeUH{WQURps(JmpEdkzMs0{;5(ynOFb)2ui z#KcQ;)hREEJ%FtPsP&H3T^1|5lTdS0_@c$B++u)g8z(L|rYFu$Nut?o5=UPzek=Mm zq%Y{(Q+a^XTZ0eXsA}QR1Av|@5n0*SdqhcFxq)%_9BwUI_0fMmUwECyYGR!zw^$!d zZ7f{W)l(s8Kz8)RP|t9!VSdohwdfOxHRv!kqw0|rO5#VA^6}JenY84sRILDYiRBM6 zz&jaBl>W5mv=8Vhyi|95Nv_`2`tmv3HvZLOPl%lH+t@_lMJav9g{U4lZvyW#dve!` zRk6qW4&UAn59&Mlqqf5D_hg1_9?oQ;$|6jNo)aC^bTmtN#zk$PR=b^k2q`m#}&vpC^H7XHnwuaNg|w8DYmRA zH+CbAdmrjwqic;Awi z(ImujZ)C3j`>?gfrmAX`Z&X1)Ac_+=seEs6)`I61yuv&k_}M4LrwT$HqtU}8Ei1Tb1z9nxzQ2o!ZIWzb8e4EJ4{dC6s;SMH2(+3Z>~ zb-i$cvf_jo8DFLzUHK)weD`_ON^+BH(3w<+-JlyL_#Ib&NA_F~9Ab>EBDZl4d z+`n*RJXpaVvwW2=J=8E0jYAF_`30fLv~?Cy5Y;`U*sGsc2a}zh;y)0zt8}*(cNl5P zjjdow2<$=F&OJCRTk{B$1I$z^eY;A0u$P&5e0jv&W|xB7m5Hecu3E~Rj8K~2(HlO8 zq@(g(7JpC=p{-il+O&9~dTz*7zS0<0lI){(S(a-&DNreDDwRO}ncJ*W)Qx_H*?)?g zNFxJzBT9@l$!|b{bqQ z{2=SVmlV!sV@ih|4OuL`)Bw?{`|*u5sGcL<(Y8%JQX1Unmgjt=5+q=Gttuc{*#S;Oy?J#jGqI0Pn1i!n0?dvg;&3RLF;Vq{i)8$ zxYo0ki|^b><~B;m(89CvUy0&So-4F>Uf%A8T;iobxl>%xeM1`kYTxQH(lCsmqAcE3 zc>s{FBKup2tFyEr9*Avb5?J#G=3F7>HcF~boL#DZtQH3Lh{yK}UW^*`!o`Wg$t<*Z zkxy19@HHAxCQ$3bFF4w&%dv*4Z_d?$2?oCkn^C{_v~*Y#?91Wv$rEo9gG zjR(6nz z74<(^fd3l%1prhp`3KdZM>~A~8>WAd9 zr6H2Mfw`?=UkTv0lx=-TBIa^m#|5lo2LtUv-HMaD^K(?%>4Cq$gUh!}$v-H|q_SXD zArgM(qqNH75Eef06g|^%|6&hL9CzT}T z2unwJ|3lQZkzbToAVlfHfIO;(ke?CtA23_9T%6y}{u*`(Pg(U&AU7DP@SvA*h#X#Z zi~sYgP@v=sX~=o5)Oa0NCHx!bk%+L-yg6AVg0OChS$y%HOnWRakqj3$a7B|)8B*|k z4|(O8Wko&-FU`F7CgU{{%suwmCXboItMe<_`SX2Q3q%w$I14;)cgN~)QY&uuP2Pm` zm4tWRRjK}U_pjWqW1}I`#tDmcT%H_E@in~2$!UM{0Z1OG@$s3T~ z)c#eJSIihoO85LgGo^$cJu{4*I$fkb`1X##<6BOvCq!}h5~vKoc!4;#lV>jhcDI%$`7;!j(O`BIKZvfp=Qiz2e-*=9H8T%*iE` zr^Ud#D^)AzWrhm>N>lk^4HkG>>*Ddl}I^+bxuM?L!R_1Y^h%4P?4Ef!Nfuy z`v{#edB%HbY|0)uguxQ$AXfB{c2YNDmO4LLMb zX=_J~eBK)*l%k~DO0;H4^S@ic*>@_b70U>e%Y<~h;u3f>=E+uLqS4D;CC9WPS@`>z zc+fV3_xZK}-#2IM9CXOqm{&m@S4pjO@U}$-^}Gapre*(&8q)uB zbHEg_L1-q2JbeJ&;;DzYI_dQ8tDB~&z!@hk&$sFb)`$p%7N)*Cy_J9p_8Hw+iIZDx zxY~AMZE)_>mx}#tefwWXz79~M+WxGP;pysrR?Q$k{3L+_&)msTBy3j{>k1F%=s^~A zOzxifwkoO!1#0qwEyl;NPHRK~4{onK=eUlyeB9tD6-s;N9`KotoqsCAsSOZXRFXL( zC_F2vQ6|&nwg*ehwvc1HWY;L%RVeZ{n+^3aXCS z*dySwiP9{jpPGD`e3mB%gDM7-pWrLGFz^O@TNmTtb0jFVycNx)v+skiFY$;jNfG0O zrJ15cOtag~SdzQY5t`h>A4vq+%K>3TW*;I#ybrf|U1r%BUXT<54S z7f|pC6rB{C^!^K5VdNZBHr`A~Btgl^F#u8`1uAI%4mpJk{8bGe6Yso#O11jUJy|K1JYm3$)kk@gR*`TrB%2{pG~ zKu`x@v*|jNh;g*Be%a=fO2uygis%lLLtV1ZBPs_EgbyhZ65&&!_k~WE9eb0q&C)gl zmP&LWe~{=sewoj2eapJT{5aOnrQY06!?6x8#%Gd%VOFGg0Ozs#^%7F~V`U~9>IFx( zU7LN7E!b@?%y zRCtq`Z^fn0I8uoKe!Ae+xvS`D#S|Yz(myE9R+R7SFUMToL^VNTuzfkKll&VU7tg)AC9^z`}0Q5@qS|^=;Mlv za7)e4=Ln|x0Mc2~@Rx#FVSq96<6UWkROslm=!MOYB(%v5&I~bJvtkOn3NvD^W)d&X zb1p#*Ss#}inHDut8L||P+`3RS`&15xVvWAHH~_f>nU7#RV%&Ka**91p>NS-S1A={R;6}h1?#bV}19Y-o`93yX42aeCar6rLN7-V}Akk zDsG0)M6)z--x}6=nfmULtE7}-Twhk_zRh^HtVXG!3F+ge+TKvfPSNH-vm=Y3rN{eO zPyI|0R@i^Eehrk=t>7umR_KSCUuiDJGj+*u*Qic{$A1N}Sy^F_D*-ZlM5i{x_)sOh z9nTDw1RkeT+2EyZ0qY44Td{d1QJX@5xmM9_6t3gTeH|6>2#&}!BW|E zc#*#ftvABEKcU9OU(Ia7@rBWBv4LZ~D`a|leE8&xwdk)JA8gW#a$vs5ujZcH`8oTJ z9s6};e&hEX4Tt@mNk|dVNS?!CxYHBk(T$;|yt&*@43JcCgTuO~rSNSSvAEo&QwdJl z98Vj>d$Pbp-gt3(cxjm#T8|OMy_|LO74SgGQO5#gs86i4a4BOT1xej z?%*2A{w4C@^I+BGROr?<4&47rKGIh)K`&5p%O}vP=YIz~*#QJ=-{O0T`_EZ8@9CX{Q&~v!r z5i=k^;-tWg^x|BD-nS=3JR5<9Df`|`8u6rlMu)6AG0!_sni|@+)H!(x-5eO<5FCCx z;jdH=ptb0v)ErEc;d9u>P(zKn+s1tGfDj~*Ke^ZHy1UkBVCVzVWJa{xxlCiomu`f- zsaSZ3?(=xR-$TknyS9r=Pfe~Wa`U>kTJtR=7EBkl7gDR0(2tb6<}q1)ac2@Q&eN!z zTl?`|coyT@{UnGo)G*=UV5D7vqc#8#%qoWxJd8jyp9F}sKX6#^#lTBBs#w$p&{pX` zmH4fNFUptv%TazO@X+Gq<{DYf7eKjw<}&khvRC+`QCJJ4oka1;b@o&R7(Gxv0;CZj zVEtnz)3rjluSw5>78^zm|0v4@0p7mV`VN?G`CmJsDo^;W^bymTcQ(Xab>lOG+~;GE zRu^t^AvBezitLfiq9j&j62y=#Qea%vF9CM*U|gh&l1&Mq<~9EI&?DkxS5a+u5UA&c z+W=zh+53&q*jVD!pYgA2pb8ADr2}}b9sSmbwL%i`R{%{Ok0etIbS~ zcM9LGu;XQfSzX0_WfFPc)Ha&BSA7oebNeJqvEzyN=)#Crr{iC;&VzoApBn&zL82mk zEXNAJ{QHwrBEKDM^M|!zlkSc&_Hw!2qfIr!Ik4E!1>hVI+Z);E%ijrL_hx-k?t{19 z$6ON5x{Y3Z!CA)XgDI#tNzugOF%;lb6x|Zd5JNB4)Sw7~C$pGA-w>w0Nn-d=NV7;V zL3)9b1g<<)9L&nKDtfV7O&P zAHoU~e&~RoXaNd$`t%LaQgRa%1GzWTfTJ0oS}Wmb()%*oE$XqB-OY6;hTt#TBM9-b zH`L7>*lLo;mE$%?`v(yt<7yz=S&<{FIAeJpOJ>?Pz~`NbNeamXvTLN9mLygieus!n8<*FFNm zJ5xW>IexSi7V?Jkp{Ze-oEb}D+1q-1j<#2&730j2RqQsV4DgrnL_AWOH|R|G4>q#QS zj=exW9hlPR0X$M*6H2W8loecYy!>zyc8MFBp5w2=V_fid%*~*_Ukt&Vtw+}>fG`RJ zxX)jhyyg4FQ_Keuy!63bh9F%$Lpu9>X{Uo+ok-y-^`;8b!JD)|`7^2k>JyE0>_spo zJ~+WyB&NQ7?*a6vsydXW$-~93P#Td^-Q9~j^P@I@>B-^da&DRP@o#}#QUoW(K^Ei5 zTh$jIM^fWr2O80AZOSh4{vPxu7oyF7DG#-u4F>{D9Ouh{0&dPitFRI2TB+2=-j#n- z@KR<=OL6m=Z=qjJKUwOjabT-?^fA>HSx_6~_4mMV$b$@d2hrWITaUNiyCJbAKK-ER z8Y_nU^d!cBkov68tZzAq`9N1j;`6qsDZ0o4wbNEg?RbBDx{Of%7Bb;%z9xvMb5J-k z2IqQjK(!lMSkPItyTAGLb$a3Mal1Ay0MovRNMUQ_cX@f7DY&Ddf9FqLn!qom0FQQlfh8qA}kL4(ydJGUMNF?{mGL0Vk!N%W}#m~A)E%eo1Idz&aZIQbK%}1^KZ}p0?!6TTmu%Q z{nvu{f72h&`F$hgUjpgmx6#8FEq`PdKKMz!G$5qRncH=phNcoyNz5vCpuV}EU00r5 z{11TMLf*co$PFBJTJ1!(-2{2Q0R{NccC?4jym-rJ9#%I992$c;kVth_^&(?$JI5INaVo6`@=#m?^t^6cnUqQyDB6^# zk2rPiX;L7LFOhN?Z>A#EU(4<$J!-*Q42&a~!o)BL#r+9u;RAPFYg3J!Vv9c$(6Ql{Gk5=F(Cn0Uj=xH$S`#oF z;K3N$HN8mbgKL17fj6yTSc0Gh+6vx*Bvlm)?4#| z_!)bWA?5%-G~usUA8dXL9H^xZzK9Scrn!IfxN-s0)f?E4-18TreEOOpfV!>7WQ|?K zQ~A51o_?Qw`u0siPD>0&wOwn4&|q+vG`-$jTl4FUnjp?%CDf0fmW+me#DXB1-i3I} zAWq1!eOYRV0{xkR`Fmsl{3h5wKoqf4s_y7#$&L@*OCkkF`F_sRO}G!U(2EB@E~5%a zf$}6yjX_>F1YTWsldF9&80b6&Y8*M7i~J2Fy|X*a0S}j*oJs5B<V=T(th|??AmagekZx1RLjE= z+|Y71DUf8ui|qO;BWIT&120|3Km+S7$Yx)(0ikZmiHflc&QF+eHCwkUzR&Jcl}trg zGP)n?ft#NbXEqAl9z1QQ1O{EP`2y|1LJ+!~ePq`5NR~W-#;u?k2yjyx07~}r$kv+g zeZS+7oM%VD)fb}kRgrYEySLFu7M11YNJ1sDf)VlupTe<2Gt3LDkOaTS#y3IV1ixF3d{zE$1mCzyFbcEp1v@*etO5Bg;erP zU_(Gq<)*J75uo_=6Nx&US&<0cg;Xvt7~b+8AYFX4;Ra3>J#VIlkgSpEyzFA}p|Xs# zXjEG}^uwNpe*LT%uJuHw^Ufq24U0myG)%TGq2iM8}U84!4m%Q=7efrKU5!k~9wxr79bRUdNFokvQ#U;>7?))aNAFDF(Ygto;*P4mBI4+_yiFj;j;@M;`As(RD z=IO61T@C!*?J&p--&Jp*w^K@euCaS1g$78VndmKP>@@$!ZTRHp0y)OlC&|D4bY0b- zh9uL#5Ay*ZdW6w*TPoVpFg3$I(Q8zY%$hea0)XB_wiB62)2pqa#yjcg^t2knE?zX! z4KK|RHkK%sSgD)Y>@UbgN;DHkCxT^_HOK(2i%018g+=%4N`rGcTXq{`scLe{blBwe z58256zRA*?34Sls5n)?1jI!bgAd*h_yMua-S!8zD2~IsTQZ%{4vCNxh(EK*e@~NG~%3;%vVv@I&yqs zR8C2|WSx*VGa>CKJ)rl7-69iwiU4$L1(mj|KSUz|NEMD3pqaN(1Q_O5CoI|38WJGV zLhEI9b5fqy3i9m?1}69ZV!lFGOh8pGAmxoAyIT5xN6U(gcADq{BEPl(Gt(6BHc>RTJz8TrcI1XS6c_(TSZl3B5l!OdV|?FL&mf=&~H*}#>+Qm-%x9wY9= zvp889Lm;b89=tyssnE@?Vu%QEZa5!Y4f*3hHyUp)VX{s}$x z{{I4ehv-}9gO~v$x;y+)Lh1B~R-F6W^1Fd||IkNLoT$<4`GlEB>_ABueo35Ru!(?_s{n|t?#VAGd4{8Kst zx0O^c6uo=CJ*NhOj>`vgE;X2526*(yyi#rX*D)lJJOeWB;ppdWeD!tANf$ijo&SWv zC;RI1z@u#52=RNGw73}us&!`i>*%;m;eO+_ULa;cJlfb)l3cn#H_aa#&L)vL<*|m7Oo6?IWSTd z2c~t~rtPw3dbmL#y%o^(@w&y=NV9y!{kr070A+s61$UcV7r<;XU*ObrOSv_!O#q7t z(qc*SeHUtk?dPvQ$7jqY9bfwBZd9X#NpYL*kgGO#mi9Eom-EEFs6j9x6GEb-DhSRj zr5b-^2VV0$$=MvjIHD@-8` z;-B~CO;Ov0FUe3*%WuhWUg8W)oK_-#@!-;XU=e;3x7mV3dT`@l_4hdQy;~y&>{wHl zHoqgznTKPrY(=-FY}?ZN_;JEVdI%BklocTUA^_gL;bH0qp6iibfluy4WZv(pr8Gsr7iVo^*S zA_{ob^bt#&s~Tt&a*t^Ho4}448&_s$4zMEX1yw33-B!o1q8ti|IaqqmDs+?U&!!qX~Ju7r<% z`8h(5;z;r=D}H!7bm<8bn=mwopio#4i- zcLpPCnwo&FB7Y9T6s)PoKkQ8~6jngzuUT$%rypM9%NVZss=Bt_XV!{ekgM#X*{!4H zK?Odvt4uge--@<0)t995ZroPCZlu(u#r#MvwVriT9TSG{(yY!p}_J8o6Z6Dprv zrKkJIPBSh`6dZMt=Pd1Del6Ej>S&yQ>MXOog{q)dV_I-qq#*y6DQ&Dz1INLA3dh>R zfZEYenozgbdgptHQBT>lcPsLw92^kU*mcPsyNXAptfVu1N&d&`przB06UHdl=ffKk zytt|8vrj^1i>KzqldPi8&U_f0o97^8%NSUES4r;4%oh^t@ukyAA!OXyEstSh?7PsSdg+L#{^qcNnzzKww$PLTZl;i=^O8iQ$ zEG?86tT|;{jDu2r^>>C3{Jt-8$9rX!3XeZB1!BBI(0*m4T z15>xEc+^6{(MyJ{Hr^t}Eb6<`!52kz4i<&Cp0Vc_mQzo~8W<{VW5C6d=-d->@_?D4 z&%|=x5e@d)5kJ;#f#;u$em7=%LDx5qH#ZwGsVGN_(2^&XXPZc=`erP@UwA8v}3M5GJ|37BO z2$<$qB{)>v_Xii=r;N)ZKgb!a-;}-1HLR_wPx8I|Ta>7G;T5p>Gp-#Wl+u)gfrF*mi%~cZ|`7~`RU5>OL*~34xzd>uA$|WJJ2CehA#V*c#s9k9=s~bO8F5@f#bi<-S zq@rz+VoaPH?^-zZS<7k3pKtJh21jLx(ge5qdSl~{8QQ*90%y7JY@m)e@AcU5=H_w4 z3XCuVNu0l@I8+zXdWjM@S93JVm*0z0GofYD=nwvkV7$dpVn~75@9l_tnC(gQ;GbAG&M&I5za zt=KJ5sEzNYXcX$|ElUL9znk&jLB4n=9NKD40QxVs1W5e+|4`!iP^Kb^i;Y*RI>2H_ ze5U^WA-AMJsObl%;Q0^Bdif~sI{nu0=?7n^4kf?C8&nU9f8{!4K?f|>1d#HD>8B|6 z739Bl-;oaMJ&(o zV+)ONLmnPX>!gR(t}y7Gy5eeQ#KfcaV6lds?eQ^e(F;F+oh;hE%!&Z!>U&A(%_|v1 za5(W7ZL9s=bNEG1O-AR!6a9in7j4AEcDgO=Lgi3BN9jPQ&|}9Z)b=rSVvG-=3ZIdn zCMKzHG6as%!7B?F?({}BYPtaCXX{P$8Lu1aY_aG*E3{sKQCy;Q5cl;W5rX$buBY4& zUv-zM(+ud^_=G#0XH0R%3rzmmqm4rW_J%h#&~)($S0{6KxDH#eUQ}O)a{RnTY2opz z-0v-i1s*&4m^1}p2fTsjgMhypg5B~MVk$SuYZ}ohAk<(GL>*|i|15`Zca)y5Nu1vY z6}0;{4(^3iUUJlgcMcA!kB6HHK>Qd-pM2Q`4nKC1%LoSv0}XD#;td5PaW?77gbPN> zbv@8ls;;N9LK1mK3tLzRsocA!Yi5#j4w>^Yf>Pra)a>Z`H`!FP{U;pauZsTD5P~6d zTy~x?wh1jQ3jvCkZK`K{LaUag9SxQHE*DU$QTikxvL37(*XTX6@_J+QdhB9Xr7}JA zxwHgfmcnVE6Db(*TmVB>Y+jrh;-J%R<#a8jsWoQ5H+XJEM#vzRrNyJ$PTnsYX^Gm2 z3VALMnr${}^(}v$ck%E}ZF6=qZ#wu!3r$jyp(B<9#MD5xr-9?gGj*5OryM^`0y8ez z6|Ln1b+1IBvX@NCfrLn#xNAI9BtJz`FU{RfGxI73s4f!0!yXZS+>8r};SPN@Z?lwS zZi!oK2LwJ5*^3)IDTq@TT6`iJ+mj?qxlfOeIHjJxaQo9)=D`$*G8#t~#j<7ZB&b=Y z!;-Ea$?gcZYG$m~Pvv@0gXM!o#%?Lor}6<+1IC35s)#&$Y){?@>TiQeHLVd znH^o}bJxHfK``kR^1WYmNB1T9>RpK1-t|RDor^S1qt1(#1fHaoGA1iUbuQ~~9~3EC z`36;QwE>S9l%jV&haBvyO<2k?meyiRO!gBnaUJp%!R8tU#}u}kMw%j;zAQDS z{tEk9eQKF1y|)HucX0Oouk5?YthEm3smSh|!EV)|l?QQDB*_o>MpodQlg=}M6=W3A zKCBBKj!)JBfd_H%F5BLdd!-(Fm3?FNlaaIC(xrsrUXO)P{KjVQc(V1}Pfp>*5F_#d z$Ep(k{w$GH@!R$rwkmbdd`8Zht50mPKg61{`3|h;nD70mU@THge8X0L9+J>Nx~4JQ z5{Qusz$!yf^>A$&IJ%_u4ElokvK0?5VwygF3`gR~MxU#t-x>wyGthL2b!8;|+cw4b z!pxwgWbQ3%FChROt9CNXygo{R{eUD-(n^JE=t3}T56{UnIy$+@3ld^J<4scQ*21Zg z4rdnll=$rk?HFPq{a=MIP8}?{O-4CuwB&lJjZM!ZdS9`#pTa{#fnBNGfWu|3CIx|^o$f%N#kf)))!5Y(*$wHZ;}~b>3{Ce-C?>>!Zghi z&Ypmde)Bl(5j&~jfqLxf&;2u-?Wgz(oxPb@pLBAUYjxcEA#m4Tj?qA34RIFre1ZCc z-)sajpW}RQE)zhvQEn0zmdXZFJT|ze@*mEp=Aulxe$6wsF9Bs%Qmv2`rV?wz?eDpI z0HB@D_&& zH182i{)USWf)&}#PHJL=MNf1OAGlx-OqW5xD&3$sXcYcLkzK4@)WQ z5_~=C`Fh2djQV?6hGS4P%**9>O5OVj;15jQKVC(joL6(1o#i`79~F=f;_iBe(1bsq F_J0W6N0k5o diff --git a/doc/img/rwtest2.png b/doc/img/rwtest2.png new file mode 100644 index 0000000000000000000000000000000000000000..7fde6f3370b56d85c6d4f817f990f7bd9fe0a1a5 GIT binary patch literal 7547 zcmb_>2T)U8yDo@`N>dRLX-bPq2LWk81StwcDIy?2q>9u;j0yp46j6!@NLN9s0)hx3 zBq%ksP^7a%#3UdnJ5pnSkQ4m=ne)$?bLZaq=k9rDubEZewf36zKF{;69e>f*LU8Yq zyxGhc3fOLKrSxsm7P4Cn&kA_OirPG(c0l0r(|<++1S|l`T0deL_|kNKYjX? zQtS+#H+D{>W8c!5OnB#L^kbDgQp)^WKLFxws@3t;|du z?&K`w_65s#gmv&=eQ?F!Dt%LCU;MSBRmw|8PCwbDcQTm?N$z(%bXnIuK1W3*<Z{h7+N0IY*YIb*n^2vJQ*{~ZdAxn>%7>QsN3t2Bm72Odv;3}{msxt2VA1{ zJIKoFP@TL+gbqnJ6@@AgouL;LM;Q4n?6VTFg zUkCj7pC4~WF|QGrUaYoHV~DV1gX&~4M5V%aGJcYj?6XzJv$SQ|$c~9nyaWU+#`-SV zWUeh+Jm~8z8gm~*%qQ+yy1ruE38Qui>d`2kOZ=&?@GW25lUg-1B}sazu6fU!P^H#z z$qDwWZdtUx$R%=cp=SY^VDMcNGDYMq_chpD!bjLQ#TOj&Ma5Hs689`$&%U1h$1&OS z3+sw<{ymWA>?e7K$k~y$bd?$iU4HG(UWkPR^!≪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モジュールは移植性に関して次の点を前提としています。

    • 処理系はANSI C準拠であること。
      -FatFsモジュールはANSI C準拠で記述されているので、ANSI C準拠のコンパイラなら特に処理系依存な点はありません。ただし、FATというシステム間でポータブルな構造体を操作するため、プロセッサのエンディアンの違いは意識する必要があります。これは ff.h(tff.h) で定義されているので、最初にこれを適切に設定します(忘れている場合はエラーを出す)。
    • -
    • char/short/long のサイズは、それぞれ 8/16/32ビット で、intは 16または32ビット であること。
      +FatFsモジュールはANSI C準拠で記述されているので、ANSI C準拠のコンパイラなら特に処理系依存な点はありません。ただし、FATというシステム間でポータブルな構造体を操作するため、プロセッサのエンディアンの違いは意識する必要があります。これは ff.h(tff.h) で定義されているので、最初にこれを適切に設定します。
    • +
    • char/short/longのサイズは、それぞれ8/16/32ビットで、intは16または32ビットであること。
      使用される整数の型は integer.h 内で typedef されています。整数の型とサイズに関しては、まっとうな処理系なら問題ないはずですが、既存の定義と衝突した場合は矛盾がないように注意しなければなりません。
    -

    メモリ使用量 (R0.05a)

    +

    メモリ使用量 (R0.06)

    各種環境でのモジュールのメモリ使用量の例を示します。数値の単位はバイトで、Dは論理ドライブ数、Fは同時オープン・ファイル数を示します。最適化オプションはコード・サイズとしています。

    - - + + - - - - + + + + - - - - + + + +
    AVRH8/300HPICMSP430TLCS-870/CV850ESSH2
    コンパイラgccCH38C30(gcc)CL430CC870CCA850SHC
    AVRH8/300HPICMSP430TLCS870CV850ESSH2
    コンパイラWinAVR(gcc)CH38C30(gcc)CL430CC870CCA850SHC
    _MCU_ENDIAN1222112
    FatFs Code
    (Full, R/W)
    91469218915566627430
    FatFs Code
    (Minimum, R/W)
    58245756586140964710
    FatFs Code
    (Full, R/O)
    42684116418729863382
    FatFs Code
    (Minimum, R/O)
    30763134314322002610
    FatFs Code
    (Full, R/W)
    92809348938767287538
    FatFs Code
    (Minimum, R/W)
    58145798591340944742
    FatFs Code
    (Full, R/O)
    44024236437130543474
    FatFs Code
    (Minimum, R/O)
    30663158321321722630
    FatFs Work (Static)D*2+2D*4+2D*2+2D*4+2D*4+2
    FatFs Work (Dynamic)D*554+F*544D*554+F*550D*554+F*544D*554+F*550D*554+F*550
    Tiny-FatFs Code
    (Full, R/W)
    7566762673716894931459266580
    Tiny-FatFs Code
    (Minimum, R/W)
    4730481446834306628536704236
    Tiny-FatFs Code
    (Full, R/O)
    3564353235223226438926783022
    Tiny-FatFs Code
    (Minimum, R/O)
    2554267425952372337618562300
    Tiny-FatFs Code
    (Full, R/W)
    7628766875607108950159786640
    Tiny-FatFs Code
    (Minimum, R/W)
    4684482046984390632236784236
    Tiny-FatFs Code
    (Full, R/O)
    3634360036183382455427223072
    Tiny-FatFs Code
    (Minimum, R/O)
    2524270026012398339018622300
    Tiny-FatFs Wrok (Static)4644466
    Tiny-FatFs Work (Dynamic)544+F*28544+F*32544+F*28544+F*28544+F*28544+F*32544+F*32
    @@ -47,7 +47,7 @@ FatFs

    FatFs vs. Tiny-FatFs

    -

    ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsは標準構成ではFAT32に対応していないので、使用できるディスクは2GB(FAT64で4GB)までという制約があります。_FAT32オプションでFAT32対応を追加できますが、その分コード・サイズが膨らみます。フル機能のFatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な場合に有効です。

    +

    ポータブル・オーディオやデータ・ロガーなど、よくある用途ではTiny-FatFsで十分です。しかし、Tiny-FatFsは標準構成ではFAT32に対応していないので、使用できるディスクは2GBまでという制約があります。_FAT32オプションでFAT32対応を追加できますが、その分コード・サイズが膨らみます。FatFsは、複数ファイルを高速アクセスする場合や、複数ドライブの対応が必要な用途に適しています。

    @@ -112,9 +112,9 @@ FatFs
  • セクタ・バッファ管理の改善
    現在はセクタ・バッファを固定して使用しているため、無駄なディスクアクセスが多く効率が悪い。メモリの潤沢なシステムでは、複数のセクタ・バッファを使用してディスク・キャッシュを構成すれば性能を向上させることができます。
  • 長いファイル名への対応
    -FATの拡張仕様ではMS-DOSの8.3形式ファイル名に加え、255文字までの長いファイル名(LFN)を扱えるようになっていますが、現リビジョンでは未対応で8.3形式しか使用できません。これに対応するには、ファイル名だけでも500バイト以上のバッファが必要になったり、UCS-2とShift_JISの相互変換(巨大な変換テーブルを使う)が必要となるなど、メモリの消費が爆発的に増えてしまいます。なお、LFNの機能はMicrosoft社の特許になっているため、これを製品に使うにはライセンス契約が必要です。
  • +FATの拡張仕様ではMS-DOSの8.3形式ファイル名に加え、255文字までの長いファイル名(LFN)を扱えるようになっていますが、現リビジョンでは未対応で8.3形式しか使用できません。これに対応するには、ファイル名1個で500バイト以上のバッファが必要になったり、Unicodeとローカル・コードの相互変換(256Kバイトの変換テーブルを使う)が必要になるなど、メモリの消費が爆発的に増えてしまいます。なお、LFNの機能はMicrosoft社の特許になっているため、これを製品に使うにはライセンス契約が必要です。
  • RTOSへの対応
    -FatFsモジュールを使用するタスクを一つに限るなら特に意識する必要はありませんが、同じ論理ドライブに複数のタスクから同時アクセスするには、何らかの排他制御が必要になってきます。FatFsモジュールのRTOSへの対応作業は、TOPPERSプロジェクトで行われています。
  • +FatFsモジュールを使用するタスクを一つに限るなら特に意識する必要はありませんが、同じ論理ドライブに対して複数のタスクから再入するには、何らかの排他制御が必要になってきます。FatFsモジュールのRTOSへの対応作業は、TOPPERSプロジェクトで行われています。

    そして、これらの機能拡張を行うとそれだけ多くのリソースが要求されるようになり、このプロジェクトの対象とする8/16ビット・マイコンのシステムに載せられなくなってしまうという問題もあります(これが一番の問題かも知れません)。

    diff --git a/doc/ja/chmod.html b/doc/ja/chmod.html index 02b12a1..6b70386 100644 --- a/doc/ja/chmod.html +++ b/doc/ja/chmod.html @@ -30,11 +30,11 @@ FRESULT f_chmod (
    Attribute
    設定する属性。指定可能な属性は次の通りで、これらの組み合わせで指定します。指定されなかった属性は解除されます。
    メモリ容量FATタイプ
    - - - - - + + + + +
    意味
    AM_RDOリード・オンリー
    AM_ARCアーカイブ
    AM_SYSシステム
    AM_HIDヒドゥン
    意味
    AM_RDOリード・オンリー
    AM_ARCアーカイブ
    AM_SYSシステム
    AM_HIDヒドゥン
    AttributeMask
    diff --git a/doc/ja/dioctl.html b/doc/ja/dioctl.html index 51262c7..b43b406 100644 --- a/doc/ja/dioctl.html +++ b/doc/ja/dioctl.html @@ -50,10 +50,11 @@ DRESULT disk_ioctl (

    解説

    -

    物理ドライブの種類によりサポートされるコマンドは異なりますが、FatFsモジュールでは、ドライブの種類に依存した制御は行いません。次のドライブ共通コマンドを使用します。

    +

    物理ドライブの種類によりサポートされるコマンドは異なりますが、FatFsモジュールでは、次の汎用コマンドのみ使用し、ドライブの種類に依存した制御は行いません。

    +

    この関数はリード・オンリー構成では必要とされません。

    - - + +
    コマンド解説
    CTRL_SYNCドライブがデータの書き込みを完了するのを待ちます。ライト・バック・キャッシュを持っている場合は、書き込まれていないデータを即時書き戻します。リード・オンリー構成では使用されません。
    コマンド解説
    CTRL_SYNCドライブがデータの書き込みを完了するのを待ちます。ライト・バック・キャッシュがある場合は、書き込まれていないデータを即時書き戻します。
    GET_SECTOR_COUNTBufferの指すDWORD変数にドライブ上の総セクタ数を返します。f_mkfs内でのみ使用。
    GET_BLOCK_SIZEBufferの指すDWORD変数にメモリ・アレーの消去ブロックサイズをセクタ単位で返します。不明な場合またはHDDでは1を返します。f_mkfs内でのみ使用。
    diff --git a/doc/ja/dread.html b/doc/ja/dread.html index 2b46292..7b12215 100644 --- a/doc/ja/dread.html +++ b/doc/ja/dread.html @@ -44,7 +44,7 @@ DRESULT disk_read (
    RES_OK (0)
    正常終了。
    RES_ERROR
    -
    読み込み中にエラーが発生した。
    +
    読み込み中にエラーが発生し、その回復にも失敗した。
    RES_PARERR
    パラメータが不正。
    RES_NOTRDY
    diff --git a/doc/ja/dwrite.html b/doc/ja/dwrite.html index bdb10ca..44941c8 100644 --- a/doc/ja/dwrite.html +++ b/doc/ja/dwrite.html @@ -44,7 +44,7 @@ DRESULT disk_write (
    RES_OK (0)
    正常終了。
    RES_ERROR
    -
    書き込み中にエラーが発生した。
    +
    書き込み中にエラーが発生し、その回復にも失敗した。
    RES_WRPRT
    ディスクが書き込み禁止状態。
    RES_PARERR
    diff --git a/doc/ja/filename.html b/doc/ja/filename.html index dc6f606..825fdb8 100644 --- a/doc/ja/filename.html +++ b/doc/ja/filename.html @@ -11,7 +11,7 @@

    ファイル・ディレクトリの指定方法

    -

    FatFsモジュールでのファイル、ディレクトリ、ドライブの指定方法はMS-DOSとほぼ同じです。ただし、MS-DOSのようなカレント・ディレクトリの概念は無いので、常にルート・ディレクトリから辿る絶対パスでの指定となります。パス名の指定方法と例は次の通りです。

    +

    FatFsモジュールでのファイル、ディレクトリ、ドライブの指定方法はMS-DOSとほぼ同じです。ただし、一般的なOSのようなカレント・ディレクトリの概念は無いので、常にルート・ディレクトリから辿る絶対パスでの指定となります。パス名の指定方法と例は次の通りです。

     
      "[論理ドライブ番号:][/]ディレクトリ名/ファイル名"
    diff --git a/doc/ja/forward.html b/doc/ja/forward.html
    new file mode 100644
    index 0000000..f0e23cf
    --- /dev/null
    +++ b/doc/ja/forward.html
    @@ -0,0 +1,134 @@
    +
    +
    +
    +
    +
    +
    +
    +FatFs - f_forward
    +
    +
    +
    +
    +
    +

    f_forward

    +

    ファイルからデータを読み出し、送信ストリームに直接転送します。

    +
    +FRESULT f_forward (
    +  FIL* FileObject,                 /* ファイル・オブジェクト構造体 */
    +  UINT (*Func)(const BYTE*,UINT),  /* データ転送関数 */
    +  UINT ByteToFwd,                  /* 転送するバイト数 */
    +  UINT* ByteFwd                    /* 転送されたバイト数 */
    +);
    +
    +
    + +
    +

    引数

    +
    +
    FileObject
    +
    ファイル・オブジェクト構造体へのポインタを指定します。
    +
    Func
    +
    データを渡すユーザ定義関数へのポインタを指定します。この関数の仕様はサンプルを参照してください。
    +
    ByteToRead
    +
    転送するバイト数(0〜UINTの最大値)を指定します。
    +
    ByteRead
    +
    実際に転送されたバイト数を格納する変数を指すポインタを指定します。
    +
    +
    + + +
    +

    戻り値

    +
    +
    FR_OK (0)
    +
    正常終了。
    +
    FR_DENIED
    +
    非読み込みモードで開いたファイルから読み込もうとした。
    +
    FR_RW_ERROR
    +
    ディスク・エラーまたは内部エラーによる失敗。
    +
    FR_NOT_READY
    +
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    +
    FR_INVALID_OBJECT
    +
    無効なファイル・オブジェクト。
    +
    +
    + + +
    +

    解説

    +

    Tiny-FatFs専用関数です。ファイルのデータをバッファに読み出さずに送信ストリームに直接転送します。アプリケーション側でデータ・バッファを必要としないので、メモリの限られた環境で有効です。転送開始位置は、現在のファイルR/Wポインタからになります。ファイルR/Wポインタは転送されたバイト数だけ進みます。指定されたバイト数の転送中にファイルの終端に達した場合や送信ストリームがビジーになった場合、*ByteFwdByteToFwdよりも小さくなります。

    +

    この関数は、_USE_FORWARD == 0および、FatFsではサポートされません。

    +
    + + +
    +

    使用例(オーディオ再生)

    +
    +/*-----------------------------------------------------------------------*/
    +/* f_forward関数から呼ばれるデータ送信関数の例                           */
    +/*-----------------------------------------------------------------------*/
    +
    +UINT out_stream (   /* 戻り値: 転送されたバイト数またはストリームの状態 */
    +    const BYTE *p,  /* 転送するデータを指すポインタ */
    +    UINT btf        /* >0: 転送を行う(バイト数). 0: ストリームの状態を調べる */
    +)
    +{
    +    UINT cnt = 0;
    +
    +
    +    if (btf == 0) {     /* センス要求 */
    +        /* ストリームの状態を返す (0: ビジー, 1: レディ) */
    +        /* 一旦、レディを返したら、続く転送要求で少なくとも1バイトは */
    +        /* 転送されないと f_forward関数は FR_RW_ERROR となる。 */
    +        if (FIFO_READY) cnt = 1;
    +    }
    +    else {              /* 転送要求 */
    +        do {    /* 全てのバイトを転送するか、ストリームがビジーになるまで繰り返す */
    +            FIFO_PORT = *p++;
    +            cnt++;
    +        } while (cnt < btf && FIFO_READY);
    +    }
    +
    +    return cnt;
    +}
    +
    +
    +/*-----------------------------------------------------------------------*/
    +/* f_forward関数の使用例                                                 */
    +/*-----------------------------------------------------------------------*/
    +
    +FRESULT play_file (
    +    char *fn        /* 再生するオーディオ・ファイル名を指すポインタ */
    +)
    +{
    +    FRESULT rc;
    +    FIL fil;
    +    UINT dmy;
    +
    +    /* ファイルを読み出しモードで開く */
    +    rc = f_open(&fil, fn, FA_READ);
    +
    +    /* 全てのデータが転送されるかエラーが発生するまで続ける */
    +    while (rc == FR_OK && fil.fptr < fil.fsize) {
    +
    +        /* ほかの処理... */
    +
    +        /* 定期的または要求に応じてデータをストリームに送出する */
    +        rc = f_forward(&fil, out_stream, 1000, &dmy);
    +    }
    +
    +    return rc;	/* FR_OK: 正常終了, ほか:異常終了 */
    +}
    +
    +
    + + +
    +

    参照

    +

    f_open, fgets, f_write, f_close, FIL

    +
    + +

    戻る

    + + diff --git a/doc/ja/getfree.html b/doc/ja/getfree.html index 0f43c00..4717bf2 100644 --- a/doc/ja/getfree.html +++ b/doc/ja/getfree.html @@ -56,7 +56,7 @@ FRESULT f_getfree (

    解説

    -

    論理ドライブ上の空きクラスタ数を取得します。返されたファイル・システム・オブジェクトのsects_clustメンバがクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。FAT32ボリュームにおいて、_USE_FSINFOが指定されているときは不正確な値を返す可能性があり、指定されていないときは処理に時間がかかります。

    +

    論理ドライブ上の空きクラスタ数を取得します。返されたファイル・システム・オブジェクトのcsizeメンバがクラスタあたりのセクタ数を示しているので、これを元に実際の空きサイズが計算できます。FAT32ボリュームにおいて、_USE_FSINFOが指定されているときは不正確な値を返す可能性があり、指定されていないときは処理に時間がかかります。

    リードオンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

    @@ -69,14 +69,14 @@ FRESULT f_getfree ( // Get free clusters - res = f_getfree("", &clust, &fs); + res = f_getfree("", &clust, &fs); if (res) die(res); // Get free space printf("%lu KB total disk space.\n" "%lu KB available on the disk.\n", - (DWORD)(fs->max_clust - 2) * fs->sects_clust / 2, - clust * fs->sects_clust / 2); + (DWORD)(fs->max_clust - 2) * fs->csize / 2, + clust * fs->csize / 2);
    diff --git a/doc/ja/gets.html b/doc/ja/gets.html new file mode 100644 index 0000000..023ed97 --- /dev/null +++ b/doc/ja/gets.html @@ -0,0 +1,58 @@ + + + + + + + +FatFs - fgets + + + + +
    +

    fgets

    +

    ファイルから文字列を読み出します。

    +
    +char* fgets (
    +  char* Str,        /* バッファ */
    +  int Size,         /* バッファのサイズ */
    +  FIL* FileObject   /* ファイル・オブジェクト */
    +);
    +
    +
    + +
    +

    引数

    +
    +
    Str
    +
    文字列を読み出すバッファを指すポインタを指定します。
    +
    Size
    +
    バッファのサイズを指定します。
    +
    FileObject
    +
    ファイル・オブジェクト構造体へのポインタを指定します。
    +
    +
    + + +
    +

    戻り値

    +

    関数が成功するとStrが返されます。

    +
    + + +
    +

    解説

    +

    この関数はf_read()のラッパー関数です。読み出し動作は、最初の'\n'を読み込むか、ファイル終端に達するか、Size - 1文字を読み出すまで続きます。読み込まれた文字列の終端には'\0'が付加されます。既にファイル終端で1文字も読み込まれなかったとき、または何らかのエラーが発生したときはNULLを返します。ファイル終端に達しているかどうかはfeof()マクロで調べられます。

    +

    _USE_STRFUNCが1または2のときこの関数がサポートされます。2のときは、ファイルに含まれる'\r'が取り除かれてバッファに読み込まれます。

    +
    + + + + +

    戻る

    + + diff --git a/doc/ja/lseek.html b/doc/ja/lseek.html index 6570041..f98312d 100644 --- a/doc/ja/lseek.html +++ b/doc/ja/lseek.html @@ -63,16 +63,16 @@ FRESULT f_lseek (

    使用例

         // ファイル・オフセット5000へ移動
    -    res = f_lseek(&file, 5000);
    +    res = f_lseek(&file, 5000);
     
         // 3000バイト進める
    -    res = f_lseek(&file, file.fptr + 3000);
    +    res = f_lseek(&file, file.fptr + 3000);
     
         // 2000バイト戻す(オーバーフローに注意)
    -    res = f_lseek(&file, file.fptr - 2000);
    +    res = f_lseek(&file, file.fptr - 2000);
     
         // ファイル追記の準備(ファイル終端へ移動)
    -    res = f_lseek(&file, file.fsize);
    +    res = f_lseek(&file, file.fsize);
     
    diff --git a/doc/ja/mkdir.html b/doc/ja/mkdir.html index 26d59e9..773cfb1 100644 --- a/doc/ja/mkdir.html +++ b/doc/ja/mkdir.html @@ -61,8 +61,6 @@ FRESULT f_mkdir (

    解説

    空のディレクトリを作成します。リード・オンリー構成および_FS_MINIMIZE >= 1ではこの関数はサポートされません。

    -

    -

    diff --git a/doc/ja/mkfs.html b/doc/ja/mkfs.html index bcb76ca..7ffef74 100644 --- a/doc/ja/mkfs.html +++ b/doc/ja/mkfs.html @@ -28,9 +28,9 @@ FRESULT f_mkfs (
    Drive
    フォーマットする論理ドライブ(0-9)。
    PartitioningRule
    -
    0を指定すると、区画テーブルを作成したあとその区画にファイル・システムを作成します(FDISKフォーマット)。1を指定すると、先頭セクタから直接ファイル・システムを構築します(super floppy (SFD) フォーマット)。
    +
    0を指定すると、ドライブの全領域を占める基本DOS区画を作成したあとその区画にファイル・システムを作成します(FDISKフォーマット)。1を指定すると、区画テーブルを作成せずドライブの先頭セクタから直接ファイル・システムを作成します(super floppy (SFD) フォーマット)。
    AllocSize
    -
    クラスタ・サイズをバイト単位で指定します。512〜32768の範囲でかつ2の累乗でなければなりません。
    +
    クラスタ・サイズをバイト単位で指定します。512〜32768の範囲でかつ2の累乗でなければなりません。FAT64(64KB/クラスタ)は選択できません。
    @@ -62,9 +62,9 @@ FRESULT f_mkfs (

    説明

    -

    f_mkfs関数はFATファイル・システムをドライブ上に作成します。リムーバブル・メディアのパーテーショニング・ルールとしては、FDISK形式とSFD形式がありますが、FDISK形式が一般的です。この関数は複数区画には対応していないので、その物理ドライブの既存の区画は全て削除され、全体が一つの区画になります。

    +

    f_mkfs関数はFATファイル・システムをドライブ上に作成します。リムーバブル・メディアのパーテーショニング・ルールとしてはFDISK形式とSFD形式があり、メモリ・カードではFDISK形式が一般的です。この関数は複数区画には対応していないので、その物理ドライブの既存の区画は全て削除され、全体が一つの区画になります。

    FATタイプ(FAT12/FAT16/FAT32)は、ディスク上のクラスタ数によってのみ決定される[FAT仕様書より]決まりになっていて、それ以外の要因はありません。したがって、どのFATタイプになるかは、ディスク・サイズとクラスタ・サイズに依存します。クラスタ・サイズは大きいほど性能が上がるので、特に小容量のドライブでなければ32768バイトを選択しておけばよいです。

    -

    この関数は、FatFsで構成オプション_USE_MKFSを選択したときにサポートされます。また、Tiny-FatFsではサポートされません。

    +

    この関数は、FatFsで構成オプション_USE_MKFSを選択したときにサポートされます。また、Tiny-FatFsではサポートされません。

    diff --git a/doc/ja/mount.html b/doc/ja/mount.html index 02e9b7e..87bfb15 100644 --- a/doc/ja/mount.html +++ b/doc/ja/mount.html @@ -45,7 +45,7 @@ FRESULT f_mount (

    解説

    FatFsモジュールではそれぞれの論理ドライブにファイル・システム・オブジェクトというワーク・エリアが必要です。この関数は論理ドライブにそのワーク・エリアを登録したり抹消したりします。何らかのファイル関数を使用する前にこの関数でその論理ドライブのワーク・エリアを与えておかなければなりません。FileSystemObjectにヌル・ポインタを指定するとその論理ドライブのワーク・エリアの登録は抹消され、登録されていたワーク・エリアは破棄できます。

    -

    この関数内では物理ドライブへのアクセスは発生せず、ワーク・エリアを初期化して内部配列にそのアドレスを登録するだけです。実際のマウント動作は、他のファイル関数(パス名を指定するもの)の中で必要に応じて行われます。

    +

    この関数内では物理ドライブへのアクセスは発生せず、ワーク・エリアを初期化して内部配列にそのアドレスを登録するだけです。実際のマウント動作は、f_mount()またはメディア交換後、最初のファイル・アクセスのときに行われます。

    diff --git a/doc/ja/open.html b/doc/ja/open.html index 1f29bd4..383967e 100644 --- a/doc/ja/open.html +++ b/doc/ja/open.html @@ -32,7 +32,7 @@ FRESULT f_open (
    ModeFlags
    ファイルのアクセス方法やオープン方法を決めるフラグです。このパラメータには次の組み合わせを指定します。
    - + @@ -78,8 +78,8 @@ FRESULT f_open (

    解説

    -

    作成されたファイル・オブジェクトは、以降そのファイルに対するアクセスに使用します。ファイルを閉じるときは、f_close()を使用します。書き込みが行われたファイルが閉じられなかった場合、そのファイルは破損します。

    -

    ファイル操作関数を使用する前にまず、f_mount()を使ってそれぞれの論理ドライブにワーク・エリア(ファイル・システム・オブジェクト)を与えなければなりません。この初期化の後、その論理ドライブに対して全てのファイル関数が使えるようになります。

    +

    作成されたファイル・オブジェクトは、以降そのファイルに対するアクセスに使用します。ファイルを閉じるときは、f_close()を使用します。何らかの変更が行われたファイルが正しく閉じられなかった場合、そのファイルが破損する場合があります。

    +

    ファイル・アクセスを開始する前に、f_mount()を使ってそれぞれの論理ドライブにワーク・エリア(ファイル・システム・オブジェクト)を与える必要があります。この初期化の後、その論理ドライブに対して全てのファイル関数が使えるようになります。

    リードオンリー構成では、FA_WRITE, FA_CREATE_ALWAYS, FA_CREATE_NEW, FA_OPEN_ALWAYSの各フラグはサポートされません。

    @@ -96,27 +96,27 @@ void main () UINT br, bw; // File R/W count // ドライブ0のワーク・エリアを与える - f_mount(0, &fs); + f_mount(0, &fs); // ソース・ファイルを開く - res = f_open(&fsrc, "srcfile.dat", FA_OPEN_EXISTING | FA_READ); + res = f_open(&fsrc, "srcfile.dat", FA_OPEN_EXISTING | FA_READ); if (res) die(res); // デスティネーション・ファイルを作成する - res = f_open(&fdst, "dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE); + res = f_open(&fdst, "dstfile.dat", FA_CREATE_ALWAYS | FA_WRITE); if (res) die(res); // ソースからデスティネーションにコピーする for (;;) { - res = f_read(&fsrc, buffer, sizeof(buffer), &br); + res = f_read(&fsrc, buffer, sizeof(buffer), &br); if (res || br == 0) break; // error or eof - res = f_write(&fdst, buffer, br, &bw); + res = f_write(&fdst, buffer, br, &bw); if (res || bw < br) break; // error or disk full } // 全てのファイルを閉じる - f_close(&fsrc); - f_close(&fdst); + f_close(&fsrc); + f_close(&fdst); // ワーク・エリアを開放する f_mount(0, NULL); diff --git a/doc/ja/opendir.html b/doc/ja/opendir.html index b0dedeb..0cfccfb 100644 --- a/doc/ja/opendir.html +++ b/doc/ja/opendir.html @@ -37,8 +37,6 @@ FRESULT f_opendir (
    FR_OK (0)
    正常終了。
    -
    FR_NO_FILE
    -
    ディレクトリが見つからない。
    FR_NO_PATH
    パスが見つからない。
    FR_INVALID_NAME
    diff --git a/doc/ja/printf.html b/doc/ja/printf.html new file mode 100644 index 0000000..f2d2504 --- /dev/null +++ b/doc/ja/printf.html @@ -0,0 +1,71 @@ + + + + + + + +FatFs - fprintf + + + + +
    +

    fprintf

    +

    ファイルに書式化文字列を書き込みます。

    +
    +int fprintf (
    +  FIL* FileObject,     /* ファイル・オブジェクト */
    +  const char* Foramt,  /* 書式制御文字列 */
    +  ...
    +);
    +
    +
    + +
    +

    引数

    +
    +
    FileObject
    +
    ファイル・オブジェクト構造体へのポインタを指定します。
    +
    Format
    +
    '\0'で終わる書式制御文字列を指すポインタを指定します。'\0'は書き込まれません。
    +
    ...
    +
    オプションの引数。
    + +
    +
    + + +
    +

    戻り値

    +

    文字列が正常に書き込まれると書き込んだ文字数が返されます。ディスクが満杯またはその他エラーにより正常に書き込まれなかったときはEOF(-1)が返されます。

    +
    + + +
    +

    解説

    +

    この関数はfputc()およびfputs()のラッパー関数です。書式制御機能はサブセットとなっていて、使用可能はタイプはc s d u X、精度指定はl、フラグは0となっています。リード・ライト構成で_USE_STRFUNCが1または2のときこの関数がサポートされます。

    +
    + + +
    +

    使用例

    +
    +    fprintf(&fil, "%6d", -200);         // "  -200"
    +    fprintf(&fil, "%02u", 5);           // "05"
    +    fprintf(&fil, "%ld", 12345678L);    // "12345678"
    +    fprintf(&fil, "%08lX", 1194684UL);  // "00123ABC"
    +    fprintf(&fil, "%s", "String");      // "String"
    +    fprintf(&fil, "%c", 'a');           // "a"
    +
    +
    + + +
    +

    参照

    +

    f_open, fputc, fputs, fgets, f_close, FIL

    +
    + +

    戻る

    + + diff --git a/doc/ja/putc.html b/doc/ja/putc.html new file mode 100644 index 0000000..26dd660 --- /dev/null +++ b/doc/ja/putc.html @@ -0,0 +1,54 @@ + + + + + + + +FatFs - fputc + + + + +
    +

    fputc

    +

    ファイルに文字を書き込みます。

    +
    +int fputc (
    +  int Chr,          /* 書き込む文字 */
    +  FIL* FileObject   /* ファイル・オブジェクト */
    +);
    +
    +
    + +
    +

    引数

    +
    +
    Chr
    +
    書き込む文字を指定します。
    +
    FileObject
    +
    ファイル・オブジェクト構造体へのポインタを指定します。
    +
    +
    + + +
    +

    戻り値

    +

    文字が正常に書き込まれると書き込んだ文字が返されます。ディスクが満杯またはその他エラーにより書き込まれなかったときはEOFが返されます。

    +
    + + +
    +

    解説

    +

    この関数はf_write()のラッパー関数です。リード・ライト構成で、_USE_STRFUNCが1または2のときこの関数がサポートされます。2を指定すると、'\n'"\r\n"に変換されて書き込まれます。

    +
    + + +
    +

    参照

    +

    f_open, fputs, fprintf, fgets, f_close, FIL

    +
    + +

    戻る

    + + diff --git a/doc/ja/puts.html b/doc/ja/puts.html new file mode 100644 index 0000000..7be5548 --- /dev/null +++ b/doc/ja/puts.html @@ -0,0 +1,54 @@ + + + + + + + +FatFs - fputs + + + + +
    +

    fputs

    +

    ファイルに文字列を書き込みます。

    +
    +int fputs (
    +  const char* Str,  /* 文字列 */
    +  FIL* FileObject   /* ファイル・オブジェクト */
    +);
    +
    +
    + +
    +

    引数

    +
    +
    Str
    +
    書き込む'\0'で終わる文字列を指すポインタを指定します。'\0'は書き込まれません。
    +
    FileObject
    +
    ファイル・オブジェクト構造体へのポインタを指定します。
    +
    +
    + + +
    +

    戻り値

    +

    文字列が正常に書き込まれると書き込んだ文字数が返されます。ディスクが満杯またはその他エラーにより正常に書き込まれなかったときはEOFが返されます。

    +
    + + +
    +

    解説

    +

    この関数はfputc()のラッパー関数です。リード・ライト構成で、_USE_STRFUNCが1または2のときこの関数がサポートされます。2を指定すると、文字列中の'\n'"\r\n"に変換されて書き込まれます。

    +
    + + +
    +

    参照

    +

    f_open, fputc, fprintf, fgets, f_close, FIL

    +
    + +

    戻る

    + + diff --git a/doc/ja/read.html b/doc/ja/read.html index ba55840..813052a 100644 --- a/doc/ja/read.html +++ b/doc/ja/read.html @@ -34,7 +34,7 @@ FRESULT f_read (
    読み出すバイト数(0〜UINTの最大値)を指定します。
    ByteRead
    実際に読み出されたバイト数を格納する変数を指すポインタを指定します。
    - +
    @@ -63,7 +63,7 @@ FRESULT f_read (

    戻る

    diff --git a/doc/ja/readdir.html b/doc/ja/readdir.html index 3cc0821..2dea683 100644 --- a/doc/ja/readdir.html +++ b/doc/ja/readdir.html @@ -62,15 +62,15 @@ void scan_files (char* path) DIR dirs; int i; - if (f_opendir(&dirs, path) == FR_OK) { + if (f_opendir(&dirs, path) == FR_OK) { i = strlen(path); - while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0]) { - if (finfo._attrib & AM_DIR) { - sprintf(&path[i], "/%s", &finfo.fname[0]); + while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0]) { + if (finfo._attrib & AM_DIR) { + sprintf(&path[i], "/%s", &finfo.fname[0]); scan_files(path); path[i] = 0; } else { - printf("%s/%s\n", path, &finfo.fname[0]); + printf("%s/%s\n", path, &finfo.fname[0]); } } } diff --git a/doc/ja/sfatfs.html b/doc/ja/sfatfs.html index 0aa63e3..e149629 100644 --- a/doc/ja/sfatfs.html +++ b/doc/ja/sfatfs.html @@ -27,7 +27,7 @@ typedef struct _FATFS { DWORD last_clust; /* Last allocated cluster */ DWORD free_clust; /* Number of free clusters */ BYTE fs_type; /* FAT type (0:Not mounted) */ - BYTE sects_clust; /* Sectors per cluster */ + BYTE csize; /* Sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ BYTE drive; /* Physical drive number */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ @@ -50,7 +50,7 @@ typedef struct _FATFS { CLUST last_clust; /* Last allocated cluster */ CLUST free_clust; /* Number of free clusters */ BYTE fs_type; /* FAT type (0:Not mounted) */ - BYTE sects_clust; /* Sectors per cluster */ + BYTE csize; /* Sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ BYTE win[512]; /* Disk access window for Directory/FAT/File */ diff --git a/doc/ja/sfile.html b/doc/ja/sfile.html index 7ae1ce8..1877c19 100644 --- a/doc/ja/sfile.html +++ b/doc/ja/sfile.html @@ -18,7 +18,7 @@ typedef struct _FIL { WORD id; /* Owner file system mount ID (inverted) */ BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ + BYTE csect; /* Sector address in the cluster */ FATFS* fs; /* Pointer to the owner file system object */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ @@ -36,7 +36,7 @@ typedef struct _FIL { typedef struct _FIL { WORD id; /* Owner file system mount ID (inverted) */ BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ + BYTE csect; /* Sector address in the cluster */ FATFS* fs; /* Pointer to owner file system */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ diff --git a/doc/ja/stat.html b/doc/ja/stat.html index d301e03..f1a5e74 100644 --- a/doc/ja/stat.html +++ b/doc/ja/stat.html @@ -12,7 +12,6 @@

    f_stat

    -

     FRESULT f_stat (
       const char* FileName,  /* ファイルまたはディレクトリ名へのポインタ */
    @@ -43,7 +42,7 @@ FRESULT f_stat (
     
    パスが見つからない。
    FR_INVALID_NAME
    パス名が不正。
    -
    FR_INVALID_NAME
    +
    FR_INVALID_DRIVE
    ドライブ番号が不正。
    FR_NOT_READY
    メディアがセットされていないなど、ディスク・ドライブが動作不能状態。
    diff --git a/doc/ja/write.html b/doc/ja/write.html index 4609c97..c4fb76b 100644 --- a/doc/ja/write.html +++ b/doc/ja/write.html @@ -44,7 +44,7 @@ FRESULT f_write (
    FR_OK (0)
    正常終了。
    FR_DENIED
    -
    非書き込みモードで開いたファイルに書き込もうとした。
    +
    非書き込みモードで開かれたファイルに書き込もうとした。
    FR_RW_ERROR
    ディスク・エラーまたは内部エラーによる失敗。
    FR_NOT_READY
    @@ -57,13 +57,14 @@ FRESULT f_write (

    解説

    -

    書き込み開始位置は、ファイルR/Wポインタの現在位置からになります。ファイルR/Wポインタは実際に書き込まれたバイト数だけ進みます。書き込み中にディスクが一杯になったときは、*ByteWrittenByteToWriteよりも小さくなります。リード・オンリー構成ではこの関数はサポートされません。

    +

    書き込み開始位置は、ファイルR/Wポインタの位置からになります。ファイルR/Wポインタは実際に書き込まれたバイト数だけ進みます。関数が正常終了した後、要求したバイト数が書き込まれたかどうか*ByteWrittenをチェックすべきです。*ByteWritten < ByteToWriteのときは、ディスク・フルを意味します。

    +

    リード・オンリー構成ではこの関数はサポートされません。

    戻る

    diff --git a/doc/updates.txt b/doc/updates.txt index 49b943d..f0e22f1 100644 --- a/doc/updates.txt +++ b/doc/updates.txt @@ -1,3 +1,8 @@ +R0.06, Apr 01, 2008 + Added f_forward. (Tiny-FatFs) + Added string functions: fgets, fputc, fputs and fprintf. + Improved performance of f_lseek on moving to the same or following cluster. + R0.05a, Feb 03, 2008 Added f_truncate. Added f_utime. diff --git a/patches.txt b/patches.txt new file mode 100644 index 0000000..aa383ab --- /dev/null +++ b/patches.txt @@ -0,0 +1,63 @@ +Patches for FatFs and Tiny-FatFs R0.06 + +April 16, 2008 - FatFs and Tiny-FatFs +------------------------------------------------------------------------------ +The va_arg(arp,char) used in fprintf() will cause an incorrect behavior on +the big-endian processor due to type promotion rules. Thus the corresponding +code should be changed to va_arg(arp,int). + + + +October 11, 2008 - FatFs and Tiny-FatFs +------------------------------------------------------------------------------ +Warnings due to wrong cast may occure in the get_fileinfo function. To +eliminate it, remove const attribute of the argument, "const BYTE *dir". + + + +October 22, 2008 - FatFs and Tiny-FatFs +------------------------------------------------------------------------------ +Improving write performance. On sector misaligned long writes, FatFs issues +sector write requests out of the sector order. It will decrease the write +performance of flash memory storages. This is not the case on short writes +without direct transfer. To solve this problem, apply following patches. + +--- ff.c Tue Apr 1 21:49:26 2008 ++++ ff_new.c Tue Oct 21 23:27:44 2008 +@@ -1018,6 +1018,11 @@ + fp->curr_clust = clust; /* Update current cluster */ + fp->csect = 0; /* Reset sector address in the cluster */ + } ++ if (fp->flag & FA__DIRTY) { /* Write back file I/O buffer prior to following direct transfer */ ++ if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) ++ goto fw_error; ++ fp->flag &= (BYTE)~FA__DIRTY; ++ } + sect = clust2sect(fp->fs, fp->curr_clust) + fp->csect; /* Get current sector */ + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ +@@ -1030,11 +1035,6 @@ + continue; + } + if (sect != fp->curr_sect) { /* Is window offset changed? */ +- if (fp->flag & FA__DIRTY) { /* Write back file I/O buffer if needed */ +- if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) +- goto fw_error; +- fp->flag &= (BYTE)~FA__DIRTY; +- } + if (fp->fptr < fp->fsize && /* Fill file I/O buffer with file data */ + disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK) + goto fw_error; + + +--- tff.c Tue Apr 1 21:49:28 2008 ++++ tff_new.c Wed Oct 22 02:13:05 2008 +@@ -1037,6 +1037,8 @@ + if (wcnt > btw) wcnt = btw; + memcpy(&fp->fs->win[fp->fptr % 512U], wbuff, wcnt); + fp->fs->winflag = 1; ++ if (((UINT)fp->fptr + wcnt) % 512U == 0 /* Flush sector window when last byte is written */ ++ && !move_window(0)) goto fw_error; + } + + if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ diff --git a/src/00readme.txt b/src/00readme.txt index 1934e6a..8510b3e 100644 --- a/src/00readme.txt +++ b/src/00readme.txt @@ -1,4 +1,4 @@ -FatFs/Tiny-FatFs Module Source Files R0.05a (C)ChaN, 2008 +FatFs/Tiny-FatFs Module Source Files R0.06 (C)ChaN, 2008 FILES @@ -27,30 +27,37 @@ CONFIGURATION OPTIONS _MCU_ENDIAN This is the most impotant option that depends on the processor architecture. - When the target device corresponds to either or both of following terms, the - _MCU_ENDIAN must be set to 2 to force FatFs to access FAT structure in - byte-by-byte. + The value 2 is compatible with all MCUs. It forces FatFs to access FAT + structures in byte-by-byte. When the target device corresponds to either or + both of following cases, it must always be set 2. - Muti-byte integers (short, long) are stored in Big-Endian. - Address miss-aligned memory access results in an incorrect behavior. - If not the case, this can also be set to 1 for good code efficiency. The - initial value is 0. (must be set to 1 or 2 properly) + If not the case, setting 1 is recommended rather than 2 for good code + efficiency. The initial value is 0. (Must set 1 or 2 properly) _FS_READONLY - When application program does not require any write function, _FS_READONLY - can be set to 1 to eliminate writing code to reduce the module size. This + When application program does not require write functions, _FS_READONLY can + be set to 1 to eliminate writing code to reduce the module size. This setting should be reflected to configurations of low level disk I/O module if available. The initial value is 0. (Read and Write) _FS_MINIMIZE - When application program requires only file read/write function, _FS_MINIMIZE - can be changed to eliminate some functions to reduce the module size. The - initial value is 0. (full function) + When application program requires only file read/write function and nothing + else, _FS_MINIMIZE can be changed to eliminate some functions to reduce the + module size. The initial value is 0. (Full function) + + + _USE_STRFUNC + + When _USE_STRFUNC is set to 1, the string functions, fputc, fputs, fprintf + and fgets are enabled. The initial value is 0. (String functions are not + available) _DRIVES @@ -62,7 +69,7 @@ CONFIGURATION OPTIONS When _FAT32 is set to 1, the FAT32 support is added with an additional code size. This option is for only Tiny-FatFs. FatFs always supports all - FAT sub-types. The initial value is 0. (no FAT32 support) + FAT sub-types. The initial value is 0. (No FAT32 support) _USE_FSINFO @@ -93,26 +100,31 @@ CONFIGURATION OPTIONS Following table shows which function is removed by configuration options. - _FS_MINIMIZE _FS_READONLY _USE_MKFS - (1) (2) (3) (1) (0) - f_mount - f_open - f_close - f_read - f_write x - f_sync x - f_lseek x - f_opendir x x - f_readdir x x - f_stat x x x - f_getfree x x x x - f_truncate x x x x - f_unlink x x x x - f_mkdir x x x x - f_chmod x x x x - f_utime x x x x - f_rename x x x x - f_mkfs x x x x x + _FS_MINIMIZE _FS_READONLY _USE_STRFUNC _USE_MKFS _USE_FORWARD + (1) (2) (3) (1) (0) (0) (0) + f_mount + f_open + f_close + f_read + f_write x + f_sync x + f_lseek x + f_opendir x x + f_readdir x x + f_stat x x x + f_getfree x x x x + f_truncate x x x x + f_unlink x x x x + f_mkdir x x x x + f_chmod x x x x + f_utime x x x x + f_rename x x x x + f_mkfs x x + f_forward x + fputc x x + fputs x x + fprintf x x + fgets x @@ -120,8 +132,8 @@ AGREEMENTS The FatFs/Tiny-FatFs module is a free software and there is no warranty. The FatFs/Tiny-FatFs module is opened for education, reserch and development. - You can use and/or modify it for personal, non-profit or commercial use - without any restriction under your responsibility. + There is no restriction on use. You can use it for personal, non-profit or + commercial use under your responsibility. @@ -171,3 +183,7 @@ REVISION HISTORY 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. diff --git a/src/diskio.h b/src/diskio.h index d02178d..ae7aa27 100644 --- a/src/diskio.h +++ b/src/diskio.h @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -/ Low level disk interface modlue include file R0.05x (C)ChaN, 2007 +/ Low level disk interface modlue include file R0.06 (C)ChaN, 2007 /-----------------------------------------------------------------------*/ #ifndef _DISKIO @@ -48,7 +48,7 @@ void disk_timerproc (void); /* Command code for disk_ioctrl() */ /* Generic command */ -#define CTRL_SYNC 0 /* Mandatory for write functions */ +#define CTRL_SYNC 0 /* Mandatory for read/write configuration */ #define GET_SECTOR_COUNT 1 /* Mandatory for only f_mkfs() */ #define GET_SECTOR_SIZE 2 #define GET_BLOCK_SIZE 3 /* Mandatory for only f_mkfs() */ diff --git a/src/ff.c b/src/ff.c index 2ca7adc..e030ab0 100644 --- a/src/ff.c +++ b/src/ff.c @@ -1,6 +1,6 @@ -/*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.05a (C)ChaN, 2008 -/---------------------------------------------------------------------------/ +/*----------------------------------------------------------------------------/ +/ FatFs - FAT file system module R0.06 (C)ChaN, 2008 +/-----------------------------------------------------------------------------/ / The FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, / research and development under license policy of following trems. @@ -9,45 +9,49 @@ / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or -/ profit use without any restriction under your responsibility. +/ commercial use without restriction under your responsibility. / * Redistributions of source code must retain the above copyright notice. / -/---------------------------------------------------------------------------/ -/ Feb 26, 2006 R0.00 Prototype. +/-----------------------------------------------------------------------------/ +/ Feb 26,'06 R0.00 Prototype. / -/ Apr 29, 2006 R0.01 First stable version. +/ Apr 29,'06 R0.01 First stable version. / -/ Jun 01, 2006 R0.02 Added FAT12 support. -/ Removed unbuffered mode. -/ Fixed a problem on small (<32M) patition. -/ Jun 10, 2006 R0.02a Added a configuration option (_FS_MINIMUM). +/ Jun 01,'06 R0.02 Added FAT12 support. +/ Removed unbuffered mode. +/ Fixed a problem on small (<32M) patition. +/ Jun 10,'06 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. +/ Sep 22,'06 R0.03 Added f_rename(). +/ Changed option _FS_MINIMUM to _FS_MINIMIZE. +/ Dec 11,'06 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. -/ Changed some interfaces for multiple drive system. -/ Changed f_mountdrv() to f_mount(). -/ Added f_mkfs(). -/ Apr 01, 2007 R0.04a Supported multiple partitions on a plysical 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, 2007 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. +/ 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 plysical 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, 2007 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, 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. +/ 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. /---------------------------------------------------------------------------*/ #include @@ -211,7 +215,7 @@ BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ p = &fs->win[bc & (SS(fs) - 1)]; *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; bc++; - fs->winflag = 1; + fs->winflag = 1; if (!move_window(fs, fatsect + (bc / SS(fs)))) return FALSE; p = &fs->win[bc & (SS(fs) - 1)]; *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); @@ -309,8 +313,8 @@ DWORD create_chain ( /* 0: No free cluster, 1: Error, >=2: New cluster number */ if (ncl == scl) return 0; /* No free custer */ } - if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ - if (clust && !put_cluster(fs, clust, ncl)) return 1; /* Link it to previous one if needed */ + if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ + if (clust != 0 && !put_cluster(fs, clust, ncl)) return 1; /* Link it to previous one if needed */ fs->last_clust = ncl; /* Update fsinfo */ if (fs->free_clust != 0xFFFFFFFF) { @@ -339,7 +343,7 @@ DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ { clust -= 2; if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */ - return clust * fs->sects_clust + fs->database; + return clust * fs->csize + fs->database; } @@ -361,10 +365,10 @@ BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ idx = dj->index + 1; if ((idx & ((SS(dj->fs) - 1) / 32)) == 0) { /* Table sector changed? */ dj->sect++; /* Next sector */ - if (!dj->clust) { /* In static table */ + if (dj->clust == 0) { /* In static table */ if (idx >= dj->fs->n_rootdir) return FALSE; /* Reached to end of table */ } else { /* In dynamic table */ - if (((idx / (SS(dj->fs) / 32)) & (dj->fs->sects_clust - 1)) == 0) { /* Cluster changed? */ + if (((idx / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ clust = get_cluster(dj->fs, dj->clust); /* Get next cluster */ if (clust < 2 || clust >= dj->fs->max_clust) /* Reached to end of table */ return FALSE; @@ -566,10 +570,10 @@ FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW /* Re-initialize directory object */ clust = dj->sclust; - if (clust) { /* Dyanmic directory table */ + if (clust != 0) { /* Dyanmic directory table */ dj->clust = clust; dj->sect = clust2sect(fs, clust); - } else { /* Static directory table */ + } else { /* Static directory table */ dj->sect = fs->dirbase; } dj->index = 0; @@ -585,13 +589,13 @@ FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW /* Reached to end of the directory table */ /* Abort when it is a static table or could not stretch dynamic table */ - if (!clust || !(clust = create_chain(fs, dj->clust))) return FR_DENIED; + if (clust == 0 || !(clust = create_chain(fs, dj->clust))) return FR_DENIED; if (clust == 1 || !move_window(fs, 0)) return FR_RW_ERROR; /* Cleanup the expanded table */ fs->winsect = sector = clust2sect(fs, clust); memset(fs->win, 0, SS(fs)); - for (n = fs->sects_clust; n; n--) { + for (n = fs->csize; n; n--) { if (disk_write(fs->drive, fs->win, sector, 1) != RES_OK) return FR_RW_ERROR; sector++; @@ -711,13 +715,13 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */ fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */ - fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */ totalsect = LD_WORD(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */ if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); fs->max_clust = maxclust = (totalsect /* max_clust = Last cluster# + 1 */ - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (SS(fs)/32) - ) / fs->sects_clust + 2; + ) / fs->csize + 2; fmt = FS_FAT12; /* Determine the FAT sub type */ if (maxclust >= 0xFF7) fmt = FS_FAT16; @@ -822,7 +826,7 @@ FRESULT f_open ( char fn[8+3+1]; - fp->fs = NULL; + fp->fs = NULL; /* Clear file object */ #if !_FS_READONLY mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW); res = auto_mount(&path, &dj.fs, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW))); @@ -881,7 +885,6 @@ FRESULT f_open ( if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ return FR_DENIED; } - fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; #endif @@ -889,8 +892,8 @@ FRESULT f_open ( fp->org_clust = /* File start cluster */ ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]); fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */ - fp->fptr = 0; /* Initialze file pointer */ - fp->sect_clust = 1; /* Initialize sector counter */ + fp->fptr = 0; fp->csect = 255; /* File pointer */ + fp->curr_sect = 0; fp->fs = dj.fs; fp->id = dj.fs->id; /* Owner file system object of the file */ return FR_OK; @@ -922,46 +925,46 @@ FRESULT f_read ( if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */ remain = fp->fsize - fp->fptr; - if (btr > remain) btr = (UINT)remain; /* Truncate read count by number of bytes left */ + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until all data transferred */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr & (SS(fp->fs) - 1)) == 0) { /* On the sector boundary */ - if (--fp->sect_clust) { /* Decrement left sector counter */ - sect = fp->curr_sect + 1; /* Get current sector */ - } else { /* On the cluster boundary, get next cluster */ - clust = (fp->fptr == 0) ? + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */ + clust = (fp->fptr == 0) ? /* On the top of the file? */ fp->org_clust : get_cluster(fp->fs, fp->curr_clust); - if (clust < 2 || clust >= fp->fs->max_clust) - goto fr_error; - fp->curr_clust = clust; /* Current cluster */ - sect = clust2sect(fp->fs, clust); /* Get current sector */ - fp->sect_clust = fp->fs->sects_clust; /* Re-initialize the left sector counter */ + if (clust < 2 || clust >= fp->fs->max_clust) goto fr_error; + fp->curr_clust = clust; /* Update current cluster */ + fp->csect = 0; /* Reset sector address in the cluster */ } -#if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Flush file I/O buffer if needed */ - if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) - goto fr_error; - fp->flag &= (BYTE)~FA__DIRTY; - } -#endif - fp->curr_sect = sect; /* Update current sector */ - cc = btr / SS(fp->fs); /* When left bytes >= SS, */ + sect = clust2sect(fp->fs, fp->curr_clust) + fp->csect; /* Get current sector */ + cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ if (cc) { /* Read maximum contiguous sectors directly */ - if (cc > fp->sect_clust) cc = fp->sect_clust; + if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - fp->csect; if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK) goto fr_error; - fp->sect_clust -= (BYTE)(cc - 1); - fp->curr_sect += cc - 1; - rcnt = cc * SS(fp->fs); + fp->csect += (BYTE)cc; /* Next sector address in the cluster */ + rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ continue; } - if (disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK) /* Load the sector into file I/O buffer */ - goto fr_error; + if (sect != fp->curr_sect) { /* Is window offset changed? */ +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write back file I/O buffer if needed */ + if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fr_error; + fp->flag &= (BYTE)~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK) /* Fill file I/O buffer with file data */ + goto fr_error; + fp->curr_sect = sect; + } + fp->csect++; /* Next sector address in the cluster */ } - rcnt = SS(fp->fs) - (fp->fptr & (SS(fp->fs) - 1)); /* Copy fractional bytes from file I/O buffer */ + rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector from file I/O buffer */ if (rcnt > btr) rcnt = btr; - memcpy(rbuff, &fp->buffer[fp->fptr & (SS(fp->fs) - 1)], rcnt); + memcpy(rbuff, &fp->buffer[fp->fptr % SS(fp->fs)], rcnt); } return FR_OK; @@ -1001,46 +1004,47 @@ FRESULT f_write ( for ( ; btw; /* Repeat until all data transferred */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr & (SS(fp->fs) - 1)) == 0) { /* On the sector boundary */ - if (--fp->sect_clust) { /* Decrement left sector counter */ - sect = fp->curr_sect + 1; /* Get current sector */ - } else { /* On the cluster boundary, get next cluster */ - if (fp->fptr == 0) { /* Is top of the file */ - clust = fp->org_clust; - if (clust == 0) /* No cluster is created yet */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clust = fp->org_clust; /* Follow from the origin */ + if (clust == 0) /* When there is no cluster chain, */ fp->org_clust = clust = create_chain(fp->fs, 0); /* Create a new cluster chain */ - } else { /* Middle or end of file */ + } else { /* Middle or end of the file */ clust = create_chain(fp->fs, fp->curr_clust); /* Trace or streach cluster chain */ } - if (clust == 0) break; /* Disk full */ + if (clust == 0) break; /* Could not allocate a new cluster (disk full) */ if (clust == 1 || clust >= fp->fs->max_clust) goto fw_error; - fp->curr_clust = clust; /* Current cluster */ - sect = clust2sect(fp->fs, clust); /* Get current sector */ - fp->sect_clust = fp->fs->sects_clust; /* Re-initialize the left sector counter */ + fp->curr_clust = clust; /* Update current cluster */ + fp->csect = 0; /* Reset sector address in the cluster */ } - if (fp->flag & FA__DIRTY) { /* Flush file I/O buffer if needed */ - if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) - goto fw_error; - fp->flag &= (BYTE)~FA__DIRTY; - } - fp->curr_sect = sect; /* Update current sector */ - cc = btw / SS(fp->fs); /* When left bytes >= SS, */ + sect = clust2sect(fp->fs, fp->curr_clust) + fp->csect; /* Get current sector */ + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ if (cc) { /* Write maximum contiguous sectors directly */ - if (cc > fp->sect_clust) cc = fp->sect_clust; + if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - fp->csect; if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK) goto fw_error; - fp->sect_clust -= (BYTE)(cc - 1); - fp->curr_sect += cc - 1; - wcnt = cc * SS(fp->fs); + fp->csect += (BYTE)cc; /* Next sector address in the cluster */ + wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ continue; } - if (fp->fptr < fp->fsize && /* Fill sector buffer with file data if needed */ - disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK) - goto fw_error; + if (sect != fp->curr_sect) { /* Is window offset changed? */ + if (fp->flag & FA__DIRTY) { /* Write back file I/O buffer if needed */ + if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fw_error; + fp->flag &= (BYTE)~FA__DIRTY; + } + if (fp->fptr < fp->fsize && /* Fill file I/O buffer with file data */ + disk_read(fp->fs->drive, fp->buffer, sect, 1) != RES_OK) + goto fw_error; + fp->curr_sect = sect; + } + fp->csect++; /* Next sector address in the cluster */ } - wcnt = SS(fp->fs) - (fp->fptr & (SS(fp->fs) - 1)); /* Copy fractional bytes to file I/O buffer */ + wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */ if (wcnt > btw) wcnt = btw; - memcpy(&fp->buffer[fp->fptr & (SS(fp->fs) - 1)], wbuff, wcnt); + memcpy(&fp->buffer[fp->fptr % SS(fp->fs)], wbuff, wcnt); fp->flag |= FA__DIRTY; } @@ -1134,65 +1138,78 @@ FRESULT f_lseek ( ) { FRESULT res; - DWORD clust, csize; - BYTE csect; + DWORD clust, csize, nsect, ifptr; res = validate(fp->fs, fp->id); /* Check validity of the object */ if (res != FR_OK) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; + if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */ - if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) - goto fk_error; - fp->flag &= (BYTE)~FA__DIRTY; - } - if (ofs > fp->fsize && !(fp->flag & FA_WRITE)) -#else - if (ofs > fp->fsize) + && !(fp->flag & FA_WRITE) #endif - ofs = fp->fsize; - fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */ + ) ofs = fp->fsize; - /* Move file R/W pointer if needed */ - if (ofs) { - clust = fp->org_clust; /* Get start cluster */ + ifptr = fp->fptr; + fp->fptr = 0; fp->csect = 255; + nsect = 0; + if (ofs > 0) { + csize = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / csize >= (ifptr - 1) / csize) {/* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(csize - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clust = fp->curr_clust; + } else { /* When seek to back cluster, */ + clust = fp->org_clust; /* start from the first cluster */ #if !_FS_READONLY - if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */ - clust = create_chain(fp->fs, 0); - if (clust == 1) goto fk_error; - fp->org_clust = clust; + if (clust == 0) { /* If no cluster chain, create a new chain */ + clust = create_chain(fp->fs, 0); + if (clust == 1) goto fk_error; + fp->org_clust = clust; + } +#endif + fp->curr_clust = clust; } -#endif - if (clust) { /* If the file has a cluster chain, it can be followed */ - csize = (DWORD)fp->fs->sects_clust * SS(fp->fs); /* Cluster size in unit of byte */ - for (;;) { /* Loop to skip leading clusters */ - fp->curr_clust = clust; /* Update current cluster */ - if (ofs <= csize) break; + if (clust != 0) { + while (ofs > csize) { /* Cluster following loop */ #if !_FS_READONLY - if (fp->flag & FA_WRITE) /* Check if in write mode or not */ + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ clust = create_chain(fp->fs, clust); /* Force streached if in write mode */ - else + if (clust == 0) { /* When disk gets full, clip file size */ + ofs = csize; break; + } + } else #endif - clust = get_cluster(fp->fs, clust); /* Only follow cluster chain if not in write mode */ - if (clust == 0) { /* Stop if could not follow the cluster chain */ - ofs = csize; break; - } - if (clust == 1 || clust >= fp->fs->max_clust) goto fk_error; - fp->fptr += csize; /* Update R/W pointer */ + clust = get_cluster(fp->fs, clust); /* Follow cluster chain if not in write mode */ + if (clust < 2 || clust >= fp->fs->max_clust) goto fk_error; + fp->curr_clust = clust; + fp->fptr += csize; ofs -= csize; } - csect = (BYTE)((ofs - 1) / SS(fp->fs)); /* Sector offset in the cluster */ - fp->curr_sect = clust2sect(fp->fs, clust) + csect; /* Current sector */ - if ((ofs & (SS(fp->fs) - 1)) && /* Load current sector if needed */ - disk_read(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) - goto fk_error; - fp->sect_clust = fp->fs->sects_clust - csect; /* Left sector counter in the cluster */ - fp->fptr += ofs; /* Update file R/W pointer */ + fp->fptr += ofs; + fp->csect = (BYTE)(ofs / SS(fp->fs)); /* Sector offset in the cluster */ + if (ofs & (SS(fp->fs) - 1)) { + nsect = clust2sect(fp->fs, clust) + fp->csect; /* Current sector */ + fp->csect++; + } } } + if (nsect && nsect != fp->curr_sect) { #if !_FS_READONLY - if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */ + if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */ + if (disk_write(fp->fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK) + goto fk_error; + fp->flag &= (BYTE)~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drive, fp->buffer, nsect, 1) != RES_OK) + goto fk_error; + fp->curr_sect = nsect; + } + +#if !_FS_READONLY + if (fp->fptr > fp->fsize) { /* Set changed flag if the file was extended */ fp->fsize = fp->fptr; fp->flag |= FA__WRITTEN; } @@ -1499,7 +1516,7 @@ FRESULT f_mkdir ( fw = dj.fs->win; memset(fw, 0, SS(dj.fs)); /* Clear the new directory table */ - for (n = 1; n < dj.fs->sects_clust; n++) { + for (n = 1; n < dj.fs->csize; n++) { if (disk_write(dj.fs->drive, fw, ++dsect, 1) != RES_OK) return FR_RW_ERROR; } @@ -1643,19 +1660,24 @@ FRESULT f_rename ( return sync(dj.fs); } +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ -#if _USE_MKFS + +#if _USE_MKFS && !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Create File System on the Drive */ /*-----------------------------------------------------------------------*/ - #define N_ROOTDIR 512 /* Multiple of 32 and <= 2048 */ #define N_FATS 1 /* 1 or 2 */ #define MAX_SECTOR 64000000UL /* Maximum partition size */ #define MIN_SECTOR 2000UL /* Minimum partition size */ + FRESULT f_mkfs ( BYTE drv, /* Logical drive number */ BYTE partition, /* Partitioning rule 0:FDISK, 1:SFD */ @@ -1781,12 +1803,15 @@ FRESULT f_mkfs ( 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_part); /* Hidden sectors */ + n = get_fattime(); /* Use current time as a VSN */ if (fmt != FS_FAT32) { + ST_DWORD(&tbl[BS_VolID], n); /* Volume serial number */ ST_WORD(&tbl[BPB_FATSz16], n_fat); /* Number of secters per FAT */ tbl[BS_DrvNum] = 0x80; /* Drive number */ tbl[BS_BootSig] = 0x29; /* Extended boot signature */ memcpy(&tbl[BS_VolLab], "NO NAME FAT ", 19); /* Volume lavel, FAT signature */ } else { + ST_DWORD(&tbl[BS_VolID32], n); /* Volume serial number */ ST_DWORD(&tbl[BPB_FATSz32], n_fat); /* Number of secters per FAT */ ST_DWORD(&tbl[BPB_RootClus], 2); /* Root directory cluster (2) */ ST_WORD(&tbl[BPB_FSInfo], 1); /* FSInfo record (bs+1) */ @@ -1842,9 +1867,170 @@ FRESULT f_mkfs ( return (disk_ioctl(drv, CTRL_SYNC, NULL) == RES_OK) ? FR_OK : FR_RW_ERROR; } -#endif /* _USE_MKFS */ -#endif /* !_FS_READONLY */ -#endif /* _FS_MINIMIZE == 0 */ -#endif /* _FS_MINIMIZE <= 1 */ -#endif /* _FS_MINIMIZE <= 2 */ +#endif /* _USE_MKFS && !_FS_READONLY */ + + + +#if _USE_STRFUNC >= 1 +/*-----------------------------------------------------------------------*/ +/* Get a string from the file */ +/*-----------------------------------------------------------------------*/ +char* fgets ( + char* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer */ + FIL* fil /* Pointer to the file object */ +) +{ + int i = 0; + char *p = buff; + UINT rc; + + + while (i < len - 1) { /* Read bytes until buffer gets filled */ + f_read(fil, p, 1, &rc); + if (rc != 1) break; /* Break when no data to read */ +#if _USE_STRFUNC >= 2 + if (*p == '\r') continue; /* Strip '\r' */ +#endif + i++; + if (*p++ == '\n') break; /* Break when reached end of line */ + } + *p = 0; + return i ? buff : 0; /* When no data read (eof or error), return with error. */ +} + + + +#if !_FS_READONLY +#include +/*-----------------------------------------------------------------------*/ +/* Put a character to the file */ +/*-----------------------------------------------------------------------*/ +int fputc ( + int chr, /* A character to be output */ + FIL* fil /* Ponter to the file object */ +) +{ + UINT bw; + char c; + + +#if _USE_STRFUNC >= 2 + if (chr == '\n') fputc ('\r', fil); /* LF -> CRLF conversion */ +#endif + if (!fil) { /* Special value may be used to switch the destination to any other device */ + /* put_console(chr); */ + return chr; + } + c = (char)chr; + f_write(fil, &c, 1, &bw); /* Write a byte to the file */ + return bw ? chr : EOF; /* Return the resulut */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a string to the file */ +/*-----------------------------------------------------------------------*/ +int fputs ( + const char* str, /* Pointer to the string to be output */ + FIL* fil /* Pointer to the file object */ +) +{ + int n; + + + for (n = 0; *str; str++, n++) { + if (fputc(*str, fil) == EOF) return EOF; + } + return n; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a formatted string to the file */ +/*-----------------------------------------------------------------------*/ +int fprintf ( + FIL* fil, /* Pointer to the file object */ + const char* str, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + UCHAR c, f, r; + ULONG val; + char s[16]; + int i, w, res, 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 cahracter */ + cc = fputc(c, fil); + if (cc != EOF) cc = 1; + continue; + } + w = f = 0; + c = *str++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *str++; + } + while (c >= '0' && c <= '9') { /* Precision */ + w = w * 10 + (c - '0'); + c = *str++; + } + if (c == 'l') { /* Prefix: Size is long int */ + f |= 2; c = *str++; + } + if (c == 's') { /* Type is string */ + cc = fputs(va_arg(arp, char*), fil); + continue; + } + if (c == 'c') { /* Type is character */ + cc = fputc(va_arg(arp, char), fil); + if (cc != EOF) cc = 1; + continue; + } + r = 0; + if (c == 'd') r = 10; /* Type is signed decimal */ + if (c == 'u') r = 10; /* Type is unsigned decimal */ + if (c == 'X') r = 16; /* Type is unsigned hexdecimal */ + if (r == 0) break; /* Unknown type */ + if (f & 2) { /* Get the value */ + val = (ULONG)va_arg(arp, long); + } else { + val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int); + } + /* Put numeral string */ + if (c == 'd') { + if (val >= 0x80000000) { + val = 0 - val; + f |= 4; + } + } + i = sizeof(s) - 1; s[i] = 0; + do { + c = (UCHAR)(val % r + '0'); + if (c > '9') c += 7; + s[--i] = c; + val /= r; + } while (i && val); + if (i && (f & 4)) s[--i] = '-'; + w = sizeof(s) - 1 - w; + while (i && i > w) s[--i] = (f & 1) ? '0' : ' '; + cc = fputs(&s[i], fil); + } + + va_end(arp); + return (cc == EOF) ? cc : res; +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_STRFUNC >= 1*/ diff --git a/src/ff.h b/src/ff.h index 8cd63d1..cbb86ab 100644 --- a/src/ff.h +++ b/src/ff.h @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------/ -/ FatFs - FAT file system module include file R0.05a (C)ChaN, 2008 +/ FatFs - FAT file system module include file R0.06 (C)ChaN, 2008 /---------------------------------------------------------------------------/ / FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, @@ -9,7 +9,7 @@ / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or -/ profit use without any restriction under your responsibility. +/ commercial use without any restriction under your responsibility. / * Redistributions of source code must retain the above copyright notice. / /---------------------------------------------------------------------------*/ @@ -36,13 +36,16 @@ / 2: f_opendir and f_readdir are removed in addition to level 1. / 3: f_lseek is removed in addition to level 2. */ -#define _DRIVES 2 -/* Number of logical drives to be used. This affects the size of internal table. */ +#define _USE_STRFUNC 0 +/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ #define _USE_MKFS 0 /* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is / enabled. */ +#define _DRIVES 2 +/* Number of logical drives to be used. This affects the size of internal table. */ + #define _MULTI_PARTITION 0 /* When _MULTI_PARTITION is set to 0, each logical drive is bound to same / physical drive number and can mount only 1st primaly partition. When it is @@ -65,11 +68,11 @@ /* Definitions corresponds to multiple sector size (not tested) */ -#define S_MAX_SIZ 512 /* Do not change */ -#if S_MAX_SIZ > 512 +#define S_MAX_SIZ 512U /* Do not change */ +#if S_MAX_SIZ > 512U #define SS(fs) ((fs)->s_size) #else -#define SS(fs) 512 +#define SS(fs) 512U #endif @@ -93,8 +96,8 @@ typedef struct _FATFS { #endif #endif BYTE fs_type; /* FAT sub type */ - BYTE sects_clust; /* Sectors per cluster */ -#if S_MAX_SIZ > 512 + BYTE csize; /* Number of sectors per cluster */ +#if S_MAX_SIZ > 512U WORD s_size; /* Sector size */ #endif BYTE n_fats; /* Number of FAT copies */ @@ -120,7 +123,7 @@ typedef struct _DIR { typedef struct _FIL { WORD id; /* Owner file system mount ID */ BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ + BYTE csect; /* Sector address in the cluster */ FATFS* fs; /* Pointer to the owner file system object */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ @@ -209,7 +212,14 @@ FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */ FRESULT f_utime (const char*, const FILINFO*); /* Change file/dir timestamp */ FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */ FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */ - +#if _USE_STRFUNC +#define feof(fp) ((fp)->fptr == (fp)->fsize) +#define EOF -1 +int fputc (int, FIL*); /* Put a character to the file */ +int fputs (const char*, FIL*); /* Put a string to the file */ +int fprintf (FIL*, const char*, ...); /* Put a formatted string to the file */ +char* fgets (char*, int, FIL*); /* Get a string from the file */ +#endif /* User defined function to give a current time to fatfs module */ diff --git a/src/integer.h b/src/integer.h index 54f74ca..2d14ec8 100644 --- a/src/integer.h +++ b/src/integer.h @@ -5,7 +5,7 @@ #ifndef _INTEGER /* These types must be 16-bit, 32-bit or larger integer */ -typedef signed int INT; +typedef int INT; typedef unsigned int UINT; /* These types must be 8-bit integer */ @@ -14,12 +14,12 @@ typedef unsigned char UCHAR; typedef unsigned char BYTE; /* These types must be 16-bit integer */ -typedef signed short SHORT; +typedef short SHORT; typedef unsigned short USHORT; typedef unsigned short WORD; /* These types must be 32-bit integer */ -typedef signed long LONG; +typedef long LONG; typedef unsigned long ULONG; typedef unsigned long DWORD; diff --git a/src/tff.c b/src/tff.c index c76dba8..dec3e71 100644 --- a/src/tff.c +++ b/src/tff.c @@ -1,6 +1,6 @@ -/*--------------------------------------------------------------------------/ -/ FatFs - Tiny FAT file system module R0.05a (C)ChaN, 2008 -/---------------------------------------------------------------------------/ +/*----------------------------------------------------------------------------/ +/ FatFs - Tiny FAT file system module R0.06 (C)ChaN, 2008 +/-----------------------------------------------------------------------------/ / The FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, / research and development under license policy of following trems. @@ -9,42 +9,46 @@ / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or -/ profit use without any restriction under your responsibility. +/ commercial use without any restriction under your responsibility. / * Redistributions of source code must retain the above copyright notice. / -/---------------------------------------------------------------------------/ -/ Feb 26, 2006 R0.00 Prototype. +/-----------------------------------------------------------------------------/ +/ Feb 26,'06 R0.00 Prototype. / -/ Apr 29, 2006 R0.01 First stable version. +/ Apr 29,'06 R0.01 First stable version. / -/ Jun 01, 2006 R0.02 Added FAT12 support. -/ Removed unbuffered mode. -/ Fixed a problem on small (<32M) patition. -/ Jun 10, 2006 R0.02a Added a configuration option (_FS_MINIMUM). +/ Jun 01,'06 R0.02 Added FAT12 support. +/ Removed unbuffered mode. +/ Fixed a problem on small (<32M) patition. +/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM). / -/ Sep 22, 2006 R0.03 Added f_rename(). -/ Changed option _FS_MINIMUM to _FS_MINIMIZE. -/ Dec 09, 2006 R0.03a Improved cluster scan algolithm to write files fast. +/ Sep 22,'06 R0.03 Added f_rename(). +/ Changed option _FS_MINIMUM to _FS_MINIMIZE. +/ Dec 09,'06 R0.03a Improved cluster scan algolithm to write files fast. / -/ Feb 04, 2007 R0.04 Added FAT32 supprt. -/ Changed some interfaces incidental to FatFs. -/ Changed f_mountdrv() to f_mount(). -/ Apr 01, 2007 R0.04a Added a capability of extending file size to f_lseek(). -/ Added minimization level 3. -/ Fixed a problem in FAT32 support. -/ May 05, 2007 R0.04b Added a configuration option _USE_NTFLAG. -/ Added FSInfo support. -/ Fixed some problems corresponds to FAT32 support. -/ Fixed DBCS name can result FR_INVALID_NAME. -/ Fixed short seek (<= csize) collapses the file object. +/ Feb 04,'07 R0.04 Added FAT32 supprt. +/ Changed some interfaces incidental to FatFs. +/ Changed f_mountdrv() to f_mount(). +/ Apr 01,'07 R0.04a Added a capability of extending file size to f_lseek(). +/ Added minimization level 3. +/ Fixed a problem in FAT32 support. +/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG. +/ Added FSInfo support. +/ Fixed some problems corresponds to FAT32 support. +/ Fixed DBCS name can result FR_INVALID_NAME. +/ Fixed short seek (<= csize) collapses the file object. / -/ Aug 25, 2007 R0.05 Changed arguments of f_read() and f_write(). -/ 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. -/---------------------------------------------------------------------------*/ +/ Aug 25,'07 R0.05 Changed arguments of f_read() and f_write(). +/ 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 f_forward(), fputc(), fputs(), fprintf() and fgets(). +/ Improved performance of f_lseek() on moving to the same +/ or following cluster. +/----------------------------------------------------------------------------*/ #include #include "tff.h" /* Tiny-FatFs declarations */ @@ -122,7 +126,7 @@ FRESULT sync (void) /* FR_OK: successful, FR_RW_ERROR: failed */ /* Update FSInfo sector if needed */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { fs->winsect = 0; - memset(fs->win, 0, 512); + memset(fs->win, 0, 512U); ST_WORD(&fs->win[BS_55AA], 0xAA55); ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252); ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272); @@ -161,19 +165,19 @@ CLUST get_cluster ( /* 0,>=2: successful, 1: failed */ switch (fs->fs_type) { case FS_FAT12 : bc = (WORD)clust * 3 / 2; - if (!move_window(fatsect + bc / 512)) break; - wc = fs->win[bc % 512]; bc++; - if (!move_window(fatsect + bc / 512)) break; - wc |= (WORD)fs->win[bc % 512] << 8; + if (!move_window(fatsect + bc / 512U)) break; + wc = fs->win[bc % 512U]; bc++; + if (!move_window(fatsect + bc / 512U)) break; + wc |= (WORD)fs->win[bc % 512U] << 8; return (clust & 1) ? (wc >> 4) : (wc & 0xFFF); case FS_FAT16 : if (!move_window(fatsect + clust / 256)) break; - return LD_WORD(&fs->win[((WORD)clust * 2) % 512]); + return LD_WORD(&fs->win[((WORD)clust * 2) % 512U]); #if _FAT32 case FS_FAT32 : if (!move_window(fatsect + clust / 128)) break; - return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF; + return LD_DWORD(&fs->win[((WORD)clust * 4) % 512U]) & 0x0FFFFFFF; #endif } } @@ -205,24 +209,24 @@ BOOL put_cluster ( /* TRUE: successful, FALSE: failed */ switch (fs->fs_type) { case FS_FAT12 : bc = (WORD)clust * 3 / 2; - if (!move_window(fatsect + bc / 512)) return FALSE; - p = &fs->win[bc % 512]; + if (!move_window(fatsect + bc / 512U)) return FALSE; + p = &fs->win[bc % 512U]; *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; bc++; - fs->winflag = 1; - if (!move_window(fatsect + bc / 512)) return FALSE; - p = &fs->win[bc % 512]; + fs->winflag = 1; + if (!move_window(fatsect + bc / 512U)) return FALSE; + p = &fs->win[bc % 512U]; *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); break; case FS_FAT16 : if (!move_window(fatsect + clust / 256)) return FALSE; - ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val); + ST_WORD(&fs->win[((WORD)clust * 2) % 512U], (WORD)val); break; #if _FAT32 case FS_FAT32 : if (!move_window(fatsect + clust / 128)) return FALSE; - ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val); + ST_DWORD(&fs->win[((WORD)clust * 4) % 512U], val); break; #endif default : @@ -308,8 +312,8 @@ CLUST create_chain ( /* 0: No free cluster, 1: Error, >=2: New cluster number */ if (ncl == scl) return 0; /* No free custer */ } - if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ - if (clust && !put_cluster(clust, ncl)) return 1; /* Link it to previous one if needed */ + if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */ + if (clust != 0 && !put_cluster(clust, ncl)) return 1; /* Link it to previous one if needed */ fs->last_clust = ncl; /* Update fsinfo */ if (fs->free_clust != (CLUST)0xFFFFFFFF) { @@ -340,7 +344,7 @@ DWORD clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */ clust -= 2; if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */ - return (DWORD)clust * fs->sects_clust + fs->database; + return (DWORD)clust * fs->csize + fs->database; } @@ -362,10 +366,10 @@ BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */ idx = dj->index + 1; if ((idx & 15) == 0) { /* Table sector changed? */ dj->sect++; /* Next sector */ - if (!dj->clust) { /* In static table */ + if (dj->clust == 0) { /* In static table */ if (idx >= dj->fs->n_rootdir) return FALSE; /* Reached to end of table */ } else { /* In dynamic table */ - if (((idx / 16) & (dj->fs->sects_clust - 1)) == 0) { /* Cluster changed? */ + if (((idx / 16) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ clust = get_cluster(dj->clust); /* Get next cluster */ if (clust < 2 || clust >= dj->fs->max_clust) /* Reached to end of table */ return FALSE; @@ -456,7 +460,7 @@ char make_dirfile ( /* 1: error - detected an invalid format, '\0'or'/': next c } break; } - if (_USE_SJIS && + if (_USE_SJIS && ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ (c >= 0xE0 && c <= 0xFC))) { if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ @@ -573,10 +577,10 @@ FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW /* Re-initialize directory object */ clust = dj->sclust; - if (clust) { /* Dyanmic directory table */ + if (clust != 0) { /* Dyanmic directory table */ dj->clust = clust; dj->sect = clust2sect(clust); - } else { /* Static directory table */ + } else { /* Static directory table */ dj->sect = fs->dirbase; } dj->index = 0; @@ -592,12 +596,12 @@ FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW /* Reached to end of the directory table */ /* Abort when static table or could not stretch dynamic table */ - if (!clust || !(clust = create_chain(dj->clust))) return FR_DENIED; + if (clust == 0 || !(clust = create_chain(dj->clust))) return FR_DENIED; if (clust == 1 || !move_window(0)) return FR_RW_ERROR; fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */ - memset(fs->win, 0, 512); - for (n = fs->sects_clust; n; n--) { + memset(fs->win, 0, 512U); + for (n = fs->csize; n; n--) { if (disk_write(0, fs->win, sector, 1) != RES_OK) return FR_RW_ERROR; sector++; @@ -695,7 +699,7 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ fmt = check_fs(bootsect); /* Check the partition */ } } - if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512) /* No valid FAT patition is found */ + if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512U) /* No valid FAT patition is found */ return FR_NO_FILESYSTEM; /* Initialize the file system object */ @@ -705,13 +709,13 @@ FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */ fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */ - fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */ totalsect = LD_WORD(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */ if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); fs->max_clust = maxclust = (totalsect /* max_clust = Last cluster# + 1 */ - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / 16 - ) / fs->sects_clust + 2; + ) / fs->csize + 2; fmt = FS_FAT12; /* Determine the FAT sub type */ if (maxclust >= 0xFF7) fmt = FS_FAT16; @@ -819,7 +823,7 @@ FRESULT f_open ( char fn[8+3+1]; - fp->fs = NULL; + fp->fs = NULL; /* Clear file object */ #if !_FS_READONLY mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW); res = auto_mount(&path, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW))); @@ -883,20 +887,18 @@ FRESULT f_open ( if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ return FR_DENIED; } - - fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ + fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dir; #endif - fp->flag = mode; /* File access mode */ - fp->org_clust = /* File start cluster */ + fp->flag = mode; /* File access mode */ + fp->org_clust = /* File start cluster */ #if _FAT32 ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | #endif LD_WORD(&dir[DIR_FstClusLO]); fp->fsize = LD_DWORD(&dir[DIR_FileSize]); /* File size */ - fp->fptr = 0; /* File ptr */ - fp->sect_clust = 1; /* Sector counter */ - fp->fs = dj.fs; fp->id = dj.fs->id; /* Owner file system object of the file */ + fp->fptr = 0; fp->csect = 255; /* File pointer */ + fp->fs = dj.fs; fp->id = dj.fs->id; /* Owner file system object of the file */ return FR_OK; } @@ -928,38 +930,36 @@ FRESULT f_read ( if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */ remain = fp->fsize - fp->fptr; - if (btr > remain) btr = (UINT)remain; /* Truncate read count by number of bytes left */ + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until all data transferred */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % 512) == 0) { /* On the sector boundary */ - if (--fp->sect_clust) { /* Decrement left sector counter */ - sect = fp->curr_sect + 1; /* Get current sector */ - } else { /* On the cluster boundary, get next cluster */ - clust = (fp->fptr == 0) ? + if ((fp->fptr % 512U) == 0) { /* On the sector boundary? */ + if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */ + clust = (fp->fptr == 0) ? /* On the top of the file? */ fp->org_clust : get_cluster(fp->curr_clust); - if (clust < 2 || clust >= fp->fs->max_clust) - goto fr_error; - fp->curr_clust = clust; /* Current cluster */ - sect = clust2sect(clust); /* Get current sector */ - fp->sect_clust = fp->fs->sects_clust; /* Re-initialize the left sector counter */ + if (clust < 2 || clust >= fp->fs->max_clust) goto fr_error; + fp->curr_clust = clust; /* Update current cluster */ + fp->csect = 0; /* Reset sector address in the cluster */ } - fp->curr_sect = sect; /* Update current sector */ - cc = btr / 512; /* When left bytes >= 512, */ + sect = clust2sect(fp->curr_clust) + fp->csect; /* Get current sector */ + cc = btr / 512U; /* When remaining bytes >= sector size, */ if (cc) { /* Read maximum contiguous sectors directly */ - if (cc > fp->sect_clust) cc = fp->sect_clust; + if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - fp->csect; if (disk_read(0, rbuff, sect, (BYTE)cc) != RES_OK) goto fr_error; - fp->sect_clust -= (BYTE)(cc - 1); - fp->curr_sect += cc - 1; - rcnt = cc * 512; + fp->csect += (BYTE)cc; /* Next sector address in the cluster */ + rcnt = 512U * cc; /* Number of bytes transferred */ continue; } + fp->csect++; /* Next sector address in the cluster */ } - if (!move_window(fp->curr_sect)) goto fr_error; /* Move sector window */ - rcnt = 512 - (fp->fptr % 512); /* Copy fractional bytes from sector window */ + sect = clust2sect(fp->curr_clust) + fp->csect - 1; /* Get current sector */ + if (!move_window(sect)) goto fr_error; /* Move sector window */ + rcnt = 512U - (fp->fptr % 512U); /* Get partial sector from sector window */ if (rcnt > btr) rcnt = btr; - memcpy(rbuff, &fp->fs->win[fp->fptr % 512], rcnt); + memcpy(rbuff, &fp->fs->win[fp->fptr % 512U], rcnt); } return FR_OK; @@ -1000,50 +1000,48 @@ FRESULT f_write ( for ( ; btw; /* Repeat until all data transferred */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % 512) == 0) { /* On the sector boundary */ - if (--fp->sect_clust) { /* Decrement left sector counter */ - sect = fp->curr_sect + 1; /* Get current sector */ - } else { /* On the cluster boundary, get next cluster */ - if (fp->fptr == 0) { /* Is top of the file */ - clust = fp->org_clust; - if (clust == 0) /* No cluster is created yet */ + if ((fp->fptr % 512U) == 0) { /* On the sector boundary? */ + if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clust = fp->org_clust; /* Follow from the origin */ + if (clust == 0) /* When there is no cluster chain, */ fp->org_clust = clust = create_chain(0); /* Create a new cluster chain */ - } else { /* Middle or end of file */ + } else { /* Middle or end of the file */ clust = create_chain(fp->curr_clust); /* Trace or streach cluster chain */ } - if (clust == 0) break; /* Disk full */ + if (clust == 0) break; /* Could not allocate a new cluster (disk full) */ if (clust == 1 || clust >= fp->fs->max_clust) goto fw_error; - fp->curr_clust = clust; /* Current cluster */ - sect = clust2sect(clust); /* Get current sector */ - fp->sect_clust = fp->fs->sects_clust; /* Re-initialize the left sector counter */ + fp->curr_clust = clust; /* Update current cluster */ + fp->csect = 0; /* Reset sector address in the cluster */ } - fp->curr_sect = sect; /* Update current sector */ - cc = btw / 512; /* When left bytes >= 512, */ + sect = clust2sect(fp->curr_clust) + fp->csect; /* Get current sector */ + cc = btw / 512U; /* When remaining bytes >= sector size, */ if (cc) { /* Write maximum contiguous sectors directly */ - if (cc > fp->sect_clust) cc = fp->sect_clust; + if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - fp->csect; if (disk_write(0, wbuff, sect, (BYTE)cc) != RES_OK) goto fw_error; - fp->sect_clust -= (BYTE)(cc - 1); - fp->curr_sect += cc - 1; - wcnt = cc * 512; + fp->csect += (BYTE)cc; /* Next sector address in the cluster */ + wcnt = 512U * cc; /* Number of bytes transferred */ continue; } - if (fp->fptr >= fp->fsize) { /* Flush R/W window if needed */ + if (fp->fptr >= fp->fsize) { /* Flush R/W window without reading if needed */ if (!move_window(0)) goto fw_error; - fp->fs->winsect = fp->curr_sect; + fp->fs->winsect = sect; } + fp->csect++; /* Next sector address in the cluster */ } - if (!move_window(fp->curr_sect)) /* Move sector window */ - goto fw_error; - wcnt = 512 - (fp->fptr % 512); /* Copy fractional bytes bytes to sector window */ + sect = clust2sect(fp->curr_clust) + fp->csect - 1; /* Get current sector */ + if (!move_window(sect)) goto fw_error; /* Move sector window */ + wcnt = 512U - (fp->fptr % 512U); /* Put partial sector into sector window */ if (wcnt > btw) wcnt = btw; - memcpy(&fp->fs->win[fp->fptr % 512], wbuff, wcnt); + memcpy(&fp->fs->win[fp->fptr % 512U], wbuff, wcnt); fp->fs->winflag = 1; } if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ fp->flag |= FA__WRITTEN; /* Set file changed flag */ - return FR_OK; + return res; fw_error: /* Abort this file due to an unrecoverable error */ fp->flag |= FA__ERROR; @@ -1127,57 +1125,62 @@ FRESULT f_lseek ( { FRESULT res; CLUST clust; - DWORD csize; - BYTE csect; + DWORD csize, ifptr; res = validate(fp->fs, fp->id); /* Check validity of the object */ if (res != FR_OK) return res; if (fp->flag & FA__ERROR) return FR_RW_ERROR; + if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ #if !_FS_READONLY - if (ofs > fp->fsize && !(fp->flag & FA_WRITE)) -#else - if (ofs > fp->fsize) + && !(fp->flag & FA_WRITE) #endif - ofs = fp->fsize; - fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */ + ) ofs = fp->fsize; - /* Move file R/W pointer if needed */ - if (ofs) { - clust = fp->org_clust; /* Get start cluster */ + ifptr = fp->fptr; + fp->fptr = 0; fp->csect = 255; + if (ofs > 0) { + csize = (DWORD)fp->fs->csize * 512U; /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / csize >= (ifptr - 1) / csize) {/* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(csize - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clust = fp->curr_clust; + } else { /* When seek to back cluster, */ + clust = fp->org_clust; /* start from the first cluster */ #if !_FS_READONLY - if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */ - clust = create_chain(0); - if (clust == 1) goto fk_error; - fp->org_clust = clust; + if (clust == 0) { /* If no cluster chain, create a new chain */ + clust = create_chain(0); + if (clust == 1) goto fk_error; + fp->org_clust = clust; + } +#endif + fp->curr_clust = clust; } -#endif - if (clust) { /* If the file has a cluster chain, it can be followed */ - csize = (DWORD)fp->fs->sects_clust * 512; /* Cluster size in unit of byte */ - for (;;) { /* Loop to skip leading clusters */ - fp->curr_clust = clust; /* Update current cluster */ - if (ofs <= csize) break; + if (clust != 0) { + while (ofs > csize) { /* Cluster following loop */ #if !_FS_READONLY - if (fp->flag & FA_WRITE) /* Check if in write mode or not */ - clust = create_chain(clust); /* Force streached if in write mode */ - else + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + clust = create_chain(clust); /* Force streached if in write mode */ + if (clust == 0) { /* When disk gets full, clip file size */ + ofs = csize; break; + } + } else #endif - clust = get_cluster(clust); /* Only follow cluster chain if not in write mode */ - if (clust == 0) { /* Stop if could not follow the cluster chain */ - ofs = csize; break; - } - if (clust == 1 || clust >= fp->fs->max_clust) goto fk_error; - fp->fptr += csize; /* Update R/W pointer */ + clust = get_cluster(clust); /* Follow cluster chain if not in write mode */ + if (clust < 2 || clust >= fp->fs->max_clust) goto fk_error; + fp->curr_clust = clust; + fp->fptr += csize; ofs -= csize; } - csect = (BYTE)((ofs - 1) / 512); /* Sector offset in the cluster */ - fp->curr_sect = clust2sect(clust) + csect; /* Current sector */ - fp->sect_clust = fp->fs->sects_clust - csect; /* Left sector counter in the cluster */ - fp->fptr += ofs; /* Update file R/W pointer */ + fp->fptr += ofs; + fp->csect = (BYTE)(ofs / 512U); /* Sector offset in the cluster */ + if (ofs % 512U) fp->csect++; } } + #if !_FS_READONLY - if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */ + if (fp->fptr > fp->fsize) { /* Set changed flag if the file was extended */ fp->fsize = fp->fptr; fp->flag |= FA__WRITTEN; } @@ -1497,8 +1500,8 @@ FRESULT f_mkdir ( if (!move_window(dsect)) return FR_RW_ERROR; fw = dj.fs->win; - memset(fw, 0, 512); /* Clear the directory table */ - for (n = 1; n < dj.fs->sects_clust; n++) { + memset(fw, 0, 512U); /* Clear the directory table */ + for (n = 1; n < dj.fs->csize; n++) { if (disk_write(0, fw, ++dsect, 1) != RES_OK) return FR_RW_ERROR; } @@ -1652,3 +1655,222 @@ FRESULT f_rename ( #endif /* _FS_MINIMIZE <= 1 */ #endif /* _FS_MINIMIZE <= 2 */ + +#if _USE_FORWARD +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_forward ( + FIL *fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btr, /* Number of bytes to forward */ + UINT *br /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + DWORD remain; + UINT rcnt; + CLUST clust; + + + *br = 0; + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res != FR_OK) return res; + if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */ + if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */ + remain = fp->fsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr && (*func)(NULL, 0); /* Repeat until all data transferred */ + fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if ((fp->fptr % 512U) == 0) { /* On the sector boundary? */ + if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */ + clust = (fp->fptr == 0) ? /* On the top of the file? */ + fp->org_clust : get_cluster(fp->curr_clust); + if (clust < 2 || clust >= fp->fs->max_clust) goto ff_error; + fp->curr_clust = clust; /* Update current cluster */ + fp->csect = 0; /* Reset sector address in the cluster */ + } + fp->csect++; /* Next sector address in the cluster */ + } + if (!move_window(clust2sect(fp->curr_clust) + fp->csect - 1)) /* Move sector window */ + goto ff_error; + rcnt = 512U - (WORD)(fp->fptr % 512U); /* Forward data from sector window */ + if (rcnt > btr) rcnt = btr; + rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % 512U], rcnt); + if (rcnt == 0) goto ff_error; + } + + return FR_OK; + +ff_error: /* Abort this function due to an unrecoverable error */ + fp->flag |= FA__ERROR; + return FR_RW_ERROR; +} +#endif /* _USE_FORWARD */ + + + +#if _USE_STRFUNC >= 1 +/*-----------------------------------------------------------------------*/ +/* Get a string from the file */ +/*-----------------------------------------------------------------------*/ +char* fgets ( + char* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer */ + FIL* fil /* Pointer to the file object */ +) +{ + int i = 0; + char *p = buff; + UINT rc; + + + while (i < len - 1) { /* Read bytes until buffer gets filled */ + f_read(fil, p, 1, &rc); + if (rc != 1) break; /* Break when no data to read */ +#if _USE_STRFUNC >= 2 + if (*p == '\r') continue; /* Strip '\r' */ +#endif + i++; + if (*p++ == '\n') break; /* Break when reached end of line */ + } + *p = 0; + return i ? buff : 0; /* When no data read (eof or error), return with error. */ +} + + + +#if !_FS_READONLY +#include +/*-----------------------------------------------------------------------*/ +/* Put a character to the file */ +/*-----------------------------------------------------------------------*/ +int fputc ( + int chr, /* A character to be output */ + FIL* fil /* Ponter to the file object */ +) +{ + UINT bw; + char c; + + +#if _USE_STRFUNC >= 2 + if (chr == '\n') fputc ('\r', fil); /* LF -> CRLF conversion */ +#endif + if (!fil) { /* Special value may be used to switch the destination to any other device */ + /* put_console(chr); */ + return chr; + } + c = (char)chr; + f_write(fil, &c, 1, &bw); /* Write a byte to the file */ + return bw ? chr : EOF; /* Return the resulut */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a string to the file */ +/*-----------------------------------------------------------------------*/ +int fputs ( + const char* str, /* Pointer to the string to be output */ + FIL* fil /* Pointer to the file object */ +) +{ + int n; + + + for (n = 0; *str; str++, n++) { + if (fputc(*str, fil) == EOF) return EOF; + } + return n; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a formatted string to the file */ +/*-----------------------------------------------------------------------*/ +int fprintf ( + FIL* fil, /* Pointer to the file object */ + const char* str, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + UCHAR c, f, r; + ULONG val; + char s[16]; + int i, w, res, 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 cahracter */ + cc = fputc(c, fil); + if (cc != EOF) cc = 1; + continue; + } + w = f = 0; + c = *str++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *str++; + } + while (c >= '0' && c <= '9') { /* Precision */ + w = w * 10 + (c - '0'); + c = *str++; + } + if (c == 'l') { /* Prefix: Size is long int */ + f |= 2; c = *str++; + } + if (c == 's') { /* Type is string */ + cc = fputs(va_arg(arp, char*), fil); + continue; + } + if (c == 'c') { /* Type is character */ + cc = fputc(va_arg(arp, char), fil); + if (cc != EOF) cc = 1; + continue; + } + r = 0; + if (c == 'd') r = 10; /* Type is signed decimal */ + if (c == 'u') r = 10; /* Type is unsigned decimal */ + if (c == 'X') r = 16; /* Type is unsigned hexdecimal */ + if (r == 0) break; /* Unknown type */ + if (f & 2) { /* Get the value */ + val = (ULONG)va_arg(arp, long); + } else { + val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int); + } + /* Put numeral string */ + if (c == 'd') { + if (val >= 0x80000000) { + val = 0 - val; + f |= 4; + } + } + i = sizeof(s) - 1; s[i] = 0; + do { + c = (UCHAR)(val % r + '0'); + if (c > '9') c += 7; + s[--i] = c; + val /= r; + } while (i && val); + if (i && (f & 4)) s[--i] = '-'; + w = sizeof(s) - 1 - w; + while (i && i > w) s[--i] = (f & 1) ? '0' : ' '; + cc = fputs(&s[i], fil); + } + + va_end(arp); + return (cc == EOF) ? cc : res; +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_STRFUNC >= 1*/ diff --git a/src/tff.h b/src/tff.h index cdccab4..264afe9 100644 --- a/src/tff.h +++ b/src/tff.h @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------/ -/ Tiny-FatFs - FAT file system module include file R0.05a (C)ChaN, 2008 +/ Tiny-FatFs - FAT file system module include file R0.06 (C)ChaN, 2008 /---------------------------------------------------------------------------/ / FatFs module is an experimenal project to implement FAT file system to / cheap microcontrollers. This is a free software and is opened for education, @@ -9,7 +9,7 @@ / / * The FatFs module is a free software and there is no warranty. / * You can use, modify and/or redistribute it for personal, non-profit or -/ profit use without any restriction under your responsibility. +/ commercial use without any restriction under your responsibility. / * Redistributions of source code must retain the above copyright notice. / /---------------------------------------------------------------------------*/ @@ -36,6 +36,12 @@ / 2: f_opendir and f_readdir are removed in addition to level 1. / 3: f_lseek is removed in addition to level 2. */ +#define _USE_STRFUNC 0 +/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ + +#define _USE_FORWARD 0 +/* To enable f_forward function, set _USE_FORWARD to 1. */ + #define _FAT32 0 /* To enable FAT32 support in addition of FAT12/16, set _FAT32 to 1. */ @@ -84,7 +90,7 @@ typedef struct _FATFS { #endif #endif BYTE fs_type; /* FAT sub type */ - BYTE sects_clust; /* Sectors per cluster */ + BYTE csize; /* Number of sectors per cluster */ BYTE n_fats; /* Number of FAT copies */ BYTE winflag; /* win[] dirty flag (1:must be written back) */ BYTE win[512]; /* Disk access window for Directory/FAT/File */ @@ -106,7 +112,7 @@ typedef struct _DIR { typedef struct _FIL { WORD id; /* Owner file system mount ID */ BYTE flag; /* File status flags */ - BYTE sect_clust; /* Left sectors in cluster */ + BYTE csect; /* Sector address in the cluster */ FATFS* fs; /* Pointer to owner file system */ DWORD fptr; /* File R/W pointer */ DWORD fsize; /* File size */ @@ -145,13 +151,14 @@ typedef enum { FR_WRITE_PROTECTED, /* 9 */ FR_NOT_ENABLED, /* 10 */ FR_NO_FILESYSTEM, /* 11 */ - FR_INVALID_OBJECT /* 12 */ + FR_INVALID_OBJECT, /* 12 */ + FR_MKFS_ABORTED /* 13 (not used) */ } FRESULT; /*-----------------------------------------------------*/ -/* FatFs module application interface */ +/* Tiny-FatFs module application interface */ FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */ @@ -170,6 +177,15 @@ FRESULT f_mkdir (const char*); /* Create a new directory */ FRESULT f_chmod (const char*, BYTE, BYTE); /* Change file/dir attriburte */ FRESULT f_utime (const char*, const FILINFO*); /* Change file/dir timestamp */ FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */ +FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */ +#if _USE_STRFUNC +#define feof(fp) ((fp)->fptr == (fp)->fsize) +#define EOF -1 +int fputc (int, FIL*); /* Put a character to the file */ +int fputs (const char*, FIL*); /* Put a string to the file */ +int fprintf (FIL*, const char*, ...); /* Put a formatted string to the file */ +char* fgets (char*, int, FIL*); /* Get a string from the file */ +#endif /* User defined function to give a current time to fatfs module */
    意味
    意味
    FA_READ読み出しモードで開きます。読み書きする場合はFA_WRITEと共に指定します。
    FA_WRITE書き込みモードで開きます。読み書きする場合はFA_READと共に指定します。
    FA_OPEN_EXISTING既存のファイルを開きます。ファイルが無いときはエラーになります。(デフォルト)