From d5234633ba671ee926890ba3e0f234280034e73d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:06:21 -0700 Subject: [PATCH 001/100] FatFs: Update to R0.12a. --- .../ext/fatfs/doc/00index_e.html | 56 +- .../ext/fatfs/doc/00index_j.html | 40 +- .../ext/fatfs/doc/en/appnote.html | 189 +- .../ext/fatfs/doc/en/chmod.html | 2 +- .../ext/fatfs/doc/en/close.html | 2 +- .../ext/fatfs/doc/en/closedir.html | 2 +- .../ext/fatfs/doc/en/config.html | 92 +- .../ext/fatfs/doc/en/dinit.html | 2 +- .../ext/fatfs/doc/en/dioctl.html | 7 +- .../ext/fatfs/doc/en/dread.html | 10 +- .../ext/fatfs/doc/en/dstat.html | 6 +- .../ext/fatfs/doc/en/dwrite.html | 6 +- .../ext/fatfs/doc/en/eof.html | 2 +- .../ext/fatfs/doc/en/error.html | 4 +- .../ext/fatfs/doc/en/expand.html | 116 + .../ext/fatfs/doc/en/fdisk.html | 25 +- .../ext/fatfs/doc/en/filename.html | 31 +- .../ext/fatfs/doc/en/findfirst.html | 25 +- .../ext/fatfs/doc/en/forward.html | 4 +- .../ext/fatfs/doc/en/getcwd.html | 1 + .../ext/fatfs/doc/en/getlabel.html | 4 +- .../ext/fatfs/doc/en/lseek.html | 22 +- .../ext/fatfs/doc/en/mkfs.html | 54 +- .../ext/fatfs/doc/en/mount.html | 8 +- .../ext/fatfs/doc/en/open.html | 10 +- .../ext/fatfs/doc/en/rc.html | 29 +- .../ext/fatfs/doc/en/read.html | 4 +- .../ext/fatfs/doc/en/readdir.html | 62 +- .../ext/fatfs/doc/en/sdir.html | 13 +- .../ext/fatfs/doc/en/setlabel.html | 11 +- .../ext/fatfs/doc/en/sfatfs.html | 12 +- .../ext/fatfs/doc/en/sfile.html | 12 +- .../ext/fatfs/doc/en/sfileinfo.html | 31 +- .../ext/fatfs/doc/en/size.html | 6 +- .../ext/fatfs/doc/en/stat.html | 18 +- .../ext/fatfs/doc/en/tell.html | 4 +- .../ext/fatfs/doc/en/truncate.html | 1 + .../ext/fatfs/doc/en/unlink.html | 2 +- .../ext/fatfs/doc/en/utime.html | 2 +- .../ext/fatfs/doc/en/write.html | 4 +- .../ext/fatfs/doc/img/f7.png | Bin 11388 -> 0 bytes .../ext/fatfs/doc/img/funcs.png | Bin 19491 -> 0 bytes .../ext/fatfs/doc/img/modules.png | Bin 7932 -> 0 bytes .../ext/fatfs/doc/img/rwtest.png | Bin 19068 -> 0 bytes .../ext/fatfs/doc/ja/appnote.html | 180 +- .../ext/fatfs/doc/ja/config.html | 50 +- .../ext/fatfs/doc/ja/dioctl.html | 3 + .../ext/fatfs/doc/ja/dread.html | 6 +- .../ext/fatfs/doc/ja/dwrite.html | 8 +- .../ext/fatfs/doc/ja/expand.html | 116 + .../ext/fatfs/doc/ja/fdisk.html | 33 +- .../ext/fatfs/doc/ja/filename.html | 15 +- .../ext/fatfs/doc/ja/findfirst.html | 19 +- .../ext/fatfs/doc/ja/findnext.html | 2 +- .../ext/fatfs/doc/ja/forward.html | 4 +- .../ext/fatfs/doc/ja/getcwd.html | 1 + .../ext/fatfs/doc/ja/getfree.html | 2 +- .../ext/fatfs/doc/ja/getlabel.html | 4 +- .../ext/fatfs/doc/ja/lseek.html | 10 +- .../ext/fatfs/doc/ja/mkfs.html | 58 +- .../ext/fatfs/doc/ja/mount.html | 2 +- .../ext/fatfs/doc/ja/open.html | 7 +- .../ext/fatfs/doc/ja/rc.html | 11 +- .../ext/fatfs/doc/ja/readdir.html | 61 +- .../ext/fatfs/doc/ja/sdir.html | 11 +- .../ext/fatfs/doc/ja/setlabel.html | 7 +- .../ext/fatfs/doc/ja/sfatfs.html | 12 +- .../ext/fatfs/doc/ja/sfile.html | 9 +- .../ext/fatfs/doc/ja/sfileinfo.html | 27 +- .../ext/fatfs/doc/ja/size.html | 4 +- .../ext/fatfs/doc/ja/stat.html | 18 +- .../ext/fatfs/doc/ja/tell.html | 2 +- .../ext/fatfs/doc/{img => res}/app1.c | 1 + .../ext/fatfs/doc/{img => res}/app2.c | 0 .../ext/fatfs/doc/{img => res}/app3.c | 3 +- .../ext/fatfs/doc/{img => res}/app4.c | 0 .../ext/fatfs/doc/{img => res}/f1.png | Bin .../ext/fatfs/doc/{img => res}/f2.png | Bin .../ext/fatfs/doc/{img => res}/f3.png | Bin .../ext/fatfs/doc/{img => res}/f4.png | Bin .../ext/fatfs/doc/{img => res}/f5.png | Bin .../ext/fatfs/doc/{img => res}/f6.png | Bin .../ext/fatfs/doc/res/f7.png | Bin 0 -> 30461 bytes .../ext/fatfs/doc/res/funcs.png | Bin 0 -> 22722 bytes .../ext/fatfs/doc/{img => res}/layers.png | Bin .../ext/fatfs/doc/{img => res}/layers1.png | Bin .../ext/fatfs/doc/{img => res}/layers2.png | Bin .../ext/fatfs/doc/{img => res}/layers3.png | Bin .../ext/fatfs/doc/{img => res}/mkfatimg.zip | Bin .../ext/fatfs/doc/res/mkfs.xls | Bin 0 -> 3238912 bytes .../ext/fatfs/doc/res/modules.png | Bin 0 -> 17469 bytes .../ext/fatfs/doc/res/rwtest1.png | Bin 0 -> 27860 bytes .../ext/fatfs/doc/{img => res}/rwtest2.png | Bin .../ext/fatfs/doc/{img => res}/rwtest3.png | Bin .../ext/fatfs/src/00history.txt | 26 +- .../ext/fatfs/src/00readme.txt | 2 +- .../chibios-portapack/ext/fatfs/src/diskio.c | 61 +- .../chibios-portapack/ext/fatfs/src/diskio.h | 6 +- firmware/chibios-portapack/ext/fatfs/src/ff.c | 4769 +++++++++++------ firmware/chibios-portapack/ext/fatfs/src/ff.h | 228 +- .../ext/fatfs/src/ffconf_template.h | 143 +- .../chibios-portapack/ext/fatfs/src/integer.h | 15 +- .../ext/fatfs/src/option/cc932.c | 109 +- .../ext/fatfs/src/option/cc936.c | 109 +- .../ext/fatfs/src/option/cc949.c | 110 +- .../ext/fatfs/src/option/cc950.c | 110 +- .../ext/fatfs/src/option/ccsbcs.c | 108 +- .../ext/fatfs/src/option/syscall.c | 10 +- 108 files changed, 4625 insertions(+), 2798 deletions(-) create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/en/expand.html delete mode 100644 firmware/chibios-portapack/ext/fatfs/doc/img/f7.png delete mode 100644 firmware/chibios-portapack/ext/fatfs/doc/img/funcs.png delete mode 100644 firmware/chibios-portapack/ext/fatfs/doc/img/modules.png delete mode 100644 firmware/chibios-portapack/ext/fatfs/doc/img/rwtest.png create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/ja/expand.html rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/app1.c (90%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/app2.c (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/app3.c (94%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/app4.c (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/f1.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/f2.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/f3.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/f4.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/f5.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/f6.png (100%) create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/res/f7.png create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/res/funcs.png rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/layers.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/layers1.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/layers2.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/layers3.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/mkfatimg.zip (100%) create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/res/mkfs.xls create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/res/modules.png create mode 100644 firmware/chibios-portapack/ext/fatfs/doc/res/rwtest1.png rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/rwtest2.png (100%) rename firmware/chibios-portapack/ext/fatfs/doc/{img => res}/rwtest3.png (100%) diff --git a/firmware/chibios-portapack/ext/fatfs/doc/00index_e.html b/firmware/chibios-portapack/ext/fatfs/doc/00index_e.html index 2eef02ee..9427acbe 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/00index_e.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/00index_e.html @@ -18,22 +18,23 @@
-layer -

FatFs is a generic FAT file system module for small embedded systems. The FatFs module is written in compliance with ANSI C (C89) and completely separated from the disk I/O layer. Therefore it is independent of the platform. It can be incorporated into small microcontrollers with limited resource, such as 8051, PIC, AVR, ARM, Z80, 78K and etc. Also Petit FatFs module for tiny microcontrollers is available here.

+layer +

FatFs is a generic FAT/exFAT file system module for small embedded systems. The FatFs module is written in compliance with ANSI C (C89) and completely separated from the disk I/O layer. Therefore it is independent of the platform. It can be incorporated into small microcontrollers with limited resource, such as 8051, PIC, AVR, ARM, Z80, 78K and etc. Also Petit FatFs module for tiny microcontrollers is available here.

Features

@@ -42,7 +43,7 @@

Application Interface

-layer +layer

-

Return

+

Latest Information

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/00index_j.html b/firmware/chibios-portapack/ext/fatfs/doc/00index_j.html index fc8444e1..3b881f53 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/00index_j.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/00index_j.html @@ -18,20 +18,21 @@
-layer -

FatFsは小規模な組み込みシステム向けの汎用FATファイルシステム モジュールです。ANSI C(C89)準拠でハードウェア アーキテクチャには依存しないので、必要なワーク エリアが確保できれば、8051, PIC, AVR, SH, Z80, 68k, H8, ARMなど安価なマイコンでも使用可能です。このほか、FatFsを極小マイコン向けにシュリンクしたぷちFatFsもあります。

+layer +

FatFsは小規模な組み込みシステム向けの汎用FAT/exFATファイルシステム モジュールです。ANSI C(C89)準拠でハードウェア アーキテクチャには依存しないので、必要なワーク エリアが確保できれば、8051, PIC, AVR, SH, Z80, 68k, H8, ARMなど安価なマイコンでも使用可能です。このほか、FatFsを極小マイコン向けにシュリンクしたぷちFatFsもあります。

FatFsモジュールの特徴

    -
  • Windows互換 FATファイル システム
  • +
  • Windows互換 FAT/exFATファイルシステム
  • プラットフォーム非依存
  • コンパクトなコードとRAM使用量
  • 多くの構成オプション:
      -
    • 複数のボリューム(物理ドライブ・区画)
    • +
    • ボリューム構成(物理ドライブ数・区画)
    • DBCSを含む複数のANSI/OEMコード ページの選択
    • 長いファイル名(LFN)への対応
    • -
    • マルチタスク関連
    • -
    • マルチ セクタ サイズ
    • +
    • exFATファイルシステムへの対応
    • +
    • RTOS環境への対応
    • +
    • セクタ サイズ(固定/可変)
    • リード オンリー構成、一部APIの削除、バッファ構成、その他…
  • @@ -41,7 +42,7 @@

    上位レイヤ インターフェース

    -layer +layer
    • ファイル アクセス
        @@ -53,6 +54,7 @@
      • f_truncate - サイズの切り詰め
      • f_sync - キャッシュされたデータのフラッシュ
      • f_forward - データをストリーム関数に転送
      • +
      • f_expand - 連続領域の割り当て
      • f_gets - 文字列の読み出し
      • f_putc - 文字の書き込み
      • f_puts - 文字列の書き込み
      • @@ -101,8 +103,8 @@

        下位レイヤ インターフェース

        -layer -

        FatFsモジュールは、単なるファイル システム レイヤなので、ストレージ デバイス制御レイヤは含まれません。使用するプラットフォームやストレージ デバイスに対応した制御関数は、インプリメンタによって提供される必要があります。FatFsモジュールは、下位レイヤに対し標準的には次のインターフェースを要求します。一部の拡張機能、たとえばOS関連機能を有効にしたときは、加えてプロセス/メモリ操作関数なども必要になります。サンプル プロジェクトに下位レイヤの実装例を示します。

        +layer +

        FatFsモジュールは、単なるファイルシステム レイヤなので、その下位のストレージ デバイス制御レイヤはそれに含まれません。それぞれのプラットフォームやストレージ デバイスに対応した制御レイヤは、インプリメンタによって提供される必要があります。FatFsモジュールは、下位レイヤに対し標準的には次のインターフェースを要求します。一部の拡張機能、たとえばOS関連機能を有効にしたときは、加えてプロセス/メモリ操作関数なども必要になります。サンプル プロジェクトに下位レイヤの実装例を示します。


        -

        戻る

        +

        FatFs Home Page

        diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/appnote.html b/firmware/chibios-portapack/ext/fatfs/doc/en/appnote.html index aa989320..2344b3a6 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/appnote.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/appnote.html @@ -15,9 +15,10 @@
      • How to Port
      • Limits
      • Memory Usage
      • -
      • Module Size Reduction
      • +
      • Reducing Module Size
      • Long File Name
      • Unicode API
      • +
      • exFAT File System
      • Re-entrancy
      • Duplicated File Access
      • Performance Effective File Access
      • @@ -36,14 +37,14 @@
      • ANSI C
        The FatFs module is a middleware written in ANSI C (C89). There is no platform dependence, so long as the compiler is in compliance with ANSI C.
      • Size of integer types
        -The FatFs module assumes that size of char/short/long are 8/16/32 bit and int is 16 or 32 bit. These correspondence are defined in integer.h. This will not be a problem on most compilers. When any conflict with existing definitions is occured, you must resolve it with care.
      • +The FatFs module assumes that size of char/short/long are 8/16/32 bit and int is 16 or 32 bit. These correspondence are defined in integer.h. This will not be a problem on most compilers. When any conflict with existing definitions is occured, you must resolve it with care.

      System organizations

      -

      The dependency diagram shown below is a typical configuration of the embedded system with FatFs module.

      -

      dependency diagram

      +

      The dependency diagram shown below is a typical but not specific configuration of the embedded system with FatFs module.

      +

      dependency diagram

      (a) If a working disk module with FatFs API is provided, no additional function is needed. (b) To attach existing disk drivers with different API, glue functions are needed to translate the APIs between FatFs and the drivers.

      -

      functional diagram

      +

      functional diagram

      Which function is required?

      You need to provide only low level disk I/O functions that required by FatFs module and nothing else. If a working disk module for the target system is already existing, you need to write only glue functions to attach it to the FatFs module. If not, you need to port any other disk module or write it from scratch. Most of defined functions are not that always required. For example, disk write function is not required at read-only configuration. Following table shows which function is required depends on the configuration options.

      @@ -63,13 +64,13 @@ The FatFs module assumes that size of char/short/long are 8/16/32 bit and int is

      Limits

        -
      • FAT sub-types: FAT12, FAT16 and FAT32.
      • +
      • File system type: FAT12, FAT16, FAT32(r0.0) and exFAT(r1.0).
      • Number of open files: Unlimited. (depends on available memory)
      • Number of volumes: Upto 10.
      • -
      • File size: Upto 4G-1 bytes. (by FAT specs.)
      • -
      • Volume size: Upto 2T bytes at 512 bytes/sector. (by FAT specs.)
      • -
      • Cluster size: Upto 64K bytes at 512 bytes/sector. (by FAT specs.)
      • -
      • Sector size: 512, 1024, 2048 and 4096 bytes. (by FAT specs.)
      • +
      • Volume size: Upto 2 TiB at 512 bytes/sector.
      • +
      • File size: Upto 4 GiB - 1 on FAT volume and virtually unlimited on exFAT volume.
      • +
      • Cluster size: Upto 128 sectors on FAT volume and upto 16 MiB on exFAT volume.
      • +
      • Sector size: 512, 1024, 2048 and 4096 bytes.
      @@ -78,73 +79,74 @@ The FatFs module assumes that size of char/short/long are 8/16/32 bit and int is

      The memory usage varies depends on the configuration options.

      - - - - - - - - - + + + + + + + + +
      ARM7
      32bit
      ARM7
      Thumb
      CM3
      Thumb-2
      AVRH8/300HPIC24RL78V850ESSH-2ARX600IA-32
      CompilerGCCGCCGCCGCCCH38C30CC78K0RCA850SHCRXCVC6
      text (Full, R/W)10.6k7.1k6.5k13.3k10.9k11.7k13.3k8.1k9.0k6.0k7.9k
      text (Min, R/W) 6.7k4.6k4.2k 8.6k 7.3k 7.7k 9.1k5.3k5.8k3.9k5.2k
      text (Full, R/O) 4.8k3.2k2.9k 6.2k 5.2k 5.5k 6.5k3.8k4.0k2.9k3.7k
      text (Min, R/O) 3.6k2.5k2.3k 4.6k 4.1k 4.3k 5.0k3.0k3.1k2.2k2.9k
      bssV*4 + 2V*4 + 2V*4 + 2V*2 + 2V*4 + 2V*2 + 2V*2 + 2V*4 + 2V*4 + 2V*4 + 2V*4 + 2
      Work area
      (_FS_TINY == 0)
      V*560
      + F*550
      V*560
      + F*550
      V*560
      + F*550
      V*560
      + F*544
      V*560
      + F*550
      V*560
      + F*544
      V*560
      + F*544
      V*560
      + F*544
      V*560
      + F*550
      V*560
      + F*550
      V*560
      + F*550
      Work area
      (_FS_TINY == 1)
      V*560
      + F*36
      V*560
      + F*36
      V*560
      + F*36
      V*560
      + F*32
      V*560
      + F*36
      V*560
      + F*32
      V*560
      + F*32
      V*560
      + F*36
      V*560
      + F*36
      V*560
      + F*36
      V*560
      + F*36
      CompilerGCCGCCGCCGCCCH38C30CC78K0RCA850SHCRXCMSC
      text (Full, R/W)10.1k6.6k6.2k12.1k10.5k11.2k12.6k8.5k8.7k6.3k8.4k
      text (Min, R/W) 6.6k4.5k4.2k 7.9k 7.0k 7.6k 8.8k5.9k5.8k4.3k5.8k
      text (Full, R/O) 4.8k3.1k2.9k 5.8k 5.1k 5.5k 6.4k4.1k4.0k3.1k4.0k
      text (Min, R/O) 3.5k2.4k2.3k 4.4k 3.9k 4.2k 5.0k3.3k3.1k2.4k3.1k
      bssV*4 + 2V*4 + 2V*4 + 2V*2 + 2V*4 + 2V*2 + 2V*2 + 2V*4 + 2V*4 + 2V*4 + 2V*4 + 2
      Work area
      (_FS_TINY == 0)
      V*564
      + F*552
      V*564
      + F*552
      V*564
      + F*552
      V*560
      + F*546
      V*560
      + F*546
      V*560
      + F*546
      V*560
      + F*546
      V*564
      + F*552
      V*564
      + F*552
      V*564
      + F*552
      V*564
      + F*552
      Work area
      (_FS_TINY == 1)
      V*564
      + F*40
      V*564
      + F*40
      V*564
      + F*40
      V*560
      + F*34
      V*560
      + F*34
      V*560
      + F*34
      V*560
      + F*34
      V*564
      + F*40
      V*564
      + F*40
      V*564
      + F*40
      V*564
      + F*40
      -

      These are the memory usage on some target systems with following condition. The memory sizes are in unit of byte, V denotes number of volumes and F denotes number of open files. All samples are optimezed in code size.

      +

      These are the memory usage on some target systems with following condition. The memory sizes are in unit of byte, V denotes option _VOLUMES and F denotes number of open files. All samples here are optimezed in code size.

      -FatFs R0.11 options:
      +FatFs R0.12 options:
       _FS_READONLY   0 (R/W) or 1 (R/O)
      -_FS_MINIMIZE   0 (Full basic function) or 3 (Minimized function)
      -_VOLUMES       V (Number of logical drives to be used)
      -_WORD_ACCESS   0 or 1 (Set for 1 if possible)
      -(Any other options are left not changed from default setting)
      +_FS_MINIMIZE   0 (Full, with all basic functions) or 3 (Min, with fully minimized)
      +_FS_TINY       0 (Default) or 1 (Tiny file object)
      +And any other options are left unchanged from original setting.
       
    -

    Module Size Reduction

    +

    Reducing Modle Size

    Follwing table shows which API function is removed by configuration options for the module size reduction. To use any API function, the row of the function must be clear.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Function_FS_MINIMIZE_FS_READONLY_USE_STRFUNC_FS_RPATH_USE_FIND_USE_LABEL_USE_MKFS_USE_FORWARD_MULTI_PARTITION
    0123010  1/20120101010101
    f_mount
    f_open
    f_close
    f_read
    f_writex
    f_syncx
    f_lseekx
    f_opendirxx
    f_closedirxx
    f_readdirxx
    f_findfirstxxx
    f_findnextxxx
    f_statxxx
    f_getfreexxxx
    f_truncatexxxx
    f_unlinkxxxx
    f_mkdirxxxx
    f_chmodxxxx
    f_utimexxxx
    f_renamexxxx
    f_chdirx
    f_chdrivex
    f_getcwdxx
    f_getlabelx
    f_setlabelxx
    f_forwardx
    f_mkfsxx
    f_fdiskxxx
    f_putcxx
    f_putsxx
    f_printfxx
    f_getsx
    Function_FS_
    MINIMIZE
    _FS_
    READONLY
    _USE_
    STRFUNC
    _FS_
    RPATH
    _USE_
    FIND
    _USE_
    CHMOD
    _USE_
    EXPAND
    _USE_
    LABEL
    _USE_
    MKFS
    _USE_
    FORWARD
    _MULTI_
    PARTITION
    0123010101201010101010101
    f_mount
    f_open
    f_close
    f_read
    f_write x
    f_sync x
    f_lseek x
    f_opendir xx
    f_closedir xx
    f_readdir xx
    f_findfirst xx x
    f_findnext xx x
    f_stat xxx
    f_getfree xxx x
    f_truncate xxx x
    f_unlink xxx x
    f_mkdir xxx x
    f_rename xxx x
    f_chdir x
    f_chdrive x
    f_getcwd xx
    f_chmod x x
    f_utime x x
    f_getlabel x
    f_setlabel x x
    f_expand x x
    f_forward x
    f_mkfs x x
    f_fdisk x x x
    f_putc xx
    f_puts xx
    f_printf xx
    f_gets x

    Long File Name

    -

    FatFs module supports LFN (long file name). The two different file names, SFN (short file name) and LFN, of a file is transparent on the API except for f_readdir function. The LFN feature is disabled by default. To enable it, set _USE_LFN to 1, 2 or 3, and add option/unicode.c to the project. The LFN feature requiers a certain working buffer in addition. The buffer size can be configured by _MAX_LFN according to the available memory. The length of an LFN will reach up to 255 characters, so that the _MAX_LFN should be set to 255 for full featured LFN operation. If the size of working buffer is insufficient for the input file name, the file function fails with FR_INVALID_NAME. When use any re-entry to the API with the LFN feature, _USE_LFN must be set to 2 or 3. In this case, the file function allocates the working buffer on the stack or heap. The working buffer occupies (_MAX_LFN + 1) * 2 bytes.

    +

    FatFs module supports long file name (LFN). The two different file names, short file name (SFN) and LFN, of a file is transparent on the API except for f_readdir function. The support for LFN is disabled by default. To enable the LFN, set _USE_LFN to 1, 2 or 3, and add option/unicode.c to the project. The LFN requiers a certain working buffer in addition. The buffer size can be configured by _MAX_LFN according to the available memory. The length of an LFN will be up to 255 characters, so that the _MAX_LFN should be set to 255 for all file names. If the size of working buffer is insufficient for the input file name, the file function fails with FR_INVALID_NAME. When use any re-entry to the API with LFN is enabled, _USE_LFN must be set to 2 or 3. In this case, the file function allocates the working buffer on the stack or heap. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and additional 608 bytes when exFAT enabled.

    - + @@ -152,20 +154,27 @@ _WORD_ACCESS 0 or 1 (Set for 1 if possible)
    LFN cfg. at CM3/gccWith LFN at CM3+gcc
    _CODE_PAGECode size
    SBCS+2.8K
    932(Japanese)+62.6k
    949(Korean)+139k
    950(Traditional Chinese)+111k
    -

    When the LFN feature is enabled, the module size will be increased depends on the configured code page. Right table shows how much code size increased when LFN feature is enabled with some code pages. Especially, in the CJK region, tens of thousands of characters are being used. Unfortunately, it requires a huge OEM-Unicode bidirectional conversion table and the module size will be drastically increased as shown in the table. As the result, the FatFs with LFN feature with those code pages will not able to be implemented to most 8-bit microcontrollers.

    -

    Note that the LFN feature on the FAT file system is a patent of Microsoft Corporation. This is not the case on FAT32 but most FAT32 drivers come with the LFN feature. FatFs can swich the LFN feature on/off by configuration option. When enable LFN feature on the commercial products, a license from Microsoft may be required depends on the final destination.

    +

    When the LFN is enabled, the module size will be increased depends on the configured code page. Right table shows how much code size increased when LFN is enabled with some code pages. Especially, in the CJK region, tens of thousands of characters are being used. Unfortunately, it requires a huge OEM-Unicode bidirectional conversion table and the module size will be drastically increased as shown in the table. As the result, the FatFs with LFN enebled with those code pages will not able to be ported on the most 8-bit MCU systems.

    +

    Note that the support for LFN on the FAT volume is a patent of Microsoft Corporation. This is not the case on FAT32 but most FAT32 drivers come with the support for LFN. FatFs can switch the LFN on/off by configuration option. When enable LFN on the commercial products, you will need to be licensed by Microsoft depends on the final destination of the products.

    Unicode API

    -

    By default, FatFs uses ANSI/OEM code set on the API even at LFN configuration. FatFs can also switch the character encoding on the API to Unicode by _LFN_UNICODE option. This means that the FatFs supports the True-LFN feature. For more information, refer to the description in the file name.

    +

    By default, FatFs uses ANSI/OEM code set on the API even at LFN configuration. FatFs can also switch the character encoding on the API to Unicode by configuration option _LFN_UNICODE. This means that FatFs supports the full featured LFN specification. The data type TCHAR specifies any string on the API is an alias of char(ANSI) or WCHAR(UTF-16). For more information, refer to the description in the file name.

    +
    +

    exFAT File System

    +

    The exFAT (Microsoft's Extended File Allocation Table) file system is a replacement of the FAT file system which has been widely used in the embedded systems and consumer devices. It is adopted by SDA (SD Association) as a recommended file system for high capacity SD cards (>32GB) and they are being shipped with this format, so that the exFAT will soon become one of the standard file systems for removable media.

    +

    The exFAT file system allows the file size larger than 4 GiB limit what FAT file system allows upto and some file system overhead, especially file allocation delay, are reduced as well. This feature improves the write throughput to the file. However a problem on the current implementation of FatFs is that write throughput at writing to the growing edge of the fragmented file gets less than the throughput on the FAT volume. Pre-allocating a contiguous block with f_expand function may be a workaround of this problem.

    +

    Note that the exFAT is a patent of Microsoft Corporation. The exFAT function of FatFs is an implementation based on US. Pat. App. Pub. No. 2009/0164440 A1. FatFs module can swich the exFAT on or off by configuration option. When enable the exFAT on the commercial products, you will need to be licensed by Microsoft depends on the final destination of the products.

    +

    Remark: Enabling exFAT discards C89 compatibility because of need for 64-bit integer type.

    +

    Re-entrancy

    -

    The file operations to the different volume is always re-entrant regardless of configurations and it can work simultaneously without any mutual exclusion.

    -

    The file operations to the same volume is not re-entrant but it can also be configured to thread-safe by _FS_REENTRANT option. It enables to control exclusive use of each file system object. In this case, also the OS dependent synchronization object control functions, ff_cre_syncobj/ff_del_syncobj/ff_req_grant/ff_rel_grant, needed to be added to the project. There are some examples in the option/syscall.c.

    -

    When a file function is called while the volume is being accessed by any other task, the file function to the volume will be suspended until that task leaves the file function. If the wait time exceeded a period defined by _TIMEOUT, the file function will abort with FR_TIMEOUT. The timeout feature might not be supported on the some RTOSs.

    +

    The file operations to the different volume is always re-entrant regardless of configurations except when LFN enabled with static working buffer. It can work simultaneously without any mutual exclusion.

    +

    The file operations to the same volume is not re-entrant but it can also be configured thread-safe by option _FS_REENTRANT. It enables to control exclusive use of each file system object. In this case, also the OS dependent synchronization object control functions, ff_cre_syncobj/ff_del_syncobj/ff_req_grant/ff_rel_grant, needed to be added to the project. There are some examples in the option/syscall.c.

    +

    When a file function is called while the volume is being accessed by any other task, the file function to the volume will be suspended until that task leaves the file function. If the wait time exceeded a period defined by _TIMEOUT, the file function will abort with FR_TIMEOUT. The timeout function might not be supported on the some RTOSs.

    There is an exception on the re-entrancy for f_mount/f_mkfs/f_fdisk function. These volume management functions are not re-entrant to the same volume and corresponding physical drive. When use these functions, any other tasks need to avoid to access the volume.

    Note that this section describes on the re-entrancy of the FatFs module itself. The _FS_REENTRANT controls only exclusive use of each file system object and it does not that prevent to re-enter the low level disk functions. For example, only disk_status function can be re-entered at single volume system and any disk function can be re-entered at multiple volume system. Thus the low level disk I/O layer must be always thread-safe when any FatFs API is re-entered by two or more tasks.

    @@ -180,15 +189,15 @@ _WORD_ACCESS 0 or 1 (Set for 1 if possible)

    Performance Effective File Access

    For good read/write throughput on the small embedded systems with limited size of memory, application programmer should consider what process is done in the FatFs module. The file data on the volume is transferred in following sequence by f_read function.

    Figure 1. Sector misaligned read (short)
    - +

    Figure 2. Sector misaligned read (long)
    - +

    Figure 3. Fully sector aligned read
    - +

    -

    The file I/O buffer is a sector buffer to read/write a partial data on the sector. The sector buffer is either file private sector buffer on each file object or shared sector buffer in the file system object. The buffer configuration option _FS_TINY determins which sector buffer is used for the file data transfer. When tiny buffer configuration (1) is selected, data memory consumption is reduced _MAX_SS bytes each file object. In this case, FatFs module uses only a sector buffer in the file system object for file data transfer and FAT/directory access. The disadvantage of the tiny buffer configuration is: the FAT data cached in the sector buffer will be lost by file data transfer and it must be reloaded at every cluster boundary. However it will be suitable for most application from view point of the decent performance and low memory comsumption.

    +

    The file I/O buffer is a sector buffer to read/write a part of data on the sector. The sector buffer is either file private sector buffer on each file object or shared sector buffer in the file system object. The buffer configuration option _FS_TINY determins which sector buffer is used for the file data transfer. When tiny buffer configuration (1) is selected, data memory consumption is reduced _MAX_SS bytes each file object. In this case, FatFs module uses only a sector buffer in the file system object for file data transfer and FAT/directory access. The disadvantage of the tiny buffer configuration is: the FAT data cached in the sector buffer will be lost by file data transfer and it must be reloaded at every cluster boundary. However it will be suitable for most application from view point of the decent performance and low memory comsumption.

    Figure 1 shows that a partial sector, sector misaligned part of the file, is transferred via the file I/O buffer. At long data transfer shown in Figure 2, middle of transfer data that covers one or more sector is transferred to the application buffer directly. Figure 3 shows that the case of entier transfer data is aligned to the sector boundary. In this case, file I/O buffer is not used. On the direct transfer, the maximum extent of sectors are read with disk_read function at a time but the multiple sector transfer is divided at cluster boundary even if it is contiguous.

    Therefore taking effort to sector aligned read/write accesss eliminates buffered data transfer and the read/write performance will be improved. Besides the effect, cached FAT data will not be flushed by file data transfer at the tiny configuration, so that it can achieve same performance as non-tiny configuration with small memory footprint.

@@ -199,12 +208,12 @@ _WORD_ACCESS 0 or 1 (Set for 1 if possible)

Using Mutiple-Sector Write

Figure 6. Comparison between Multiple/Single Sector Write
-fig.6 +fig.6
-

The write throughput of the flash memory media becomes the worst at single sector write transaction. The write throughput increases as the number of sectors per a write transaction as shown in Figure 6. This effect more appers at faster interface speed and the performance ratio often becomes grater than ten. This graph is clearly explaining how fast is multiple block write (W:16K, 32 sectors) than single block write (W:100, 1 sector), and also larger card tends to be slow at single block write. Number of write transactions also affects life time of the flash memory media. When compared at same amount of write data, the single sector write in Figure 6 above wears flash memory media 16 times more than multiple sector write in Figure 6 below. Single sector write is pretty pain for the flash memory media.

-

Therefore the application program should write the data in large block as possible. The ideal write chunk size and alighment is size of sector, and size of cluster is the best. Of course all layers between the application and the storage device must have consideration on multiple sector write, however most of open-source memory card drivers lack it. Do not split a multiple sector write request into single sector write transactions or the write throughput gets poor. Note that FatFs module and its sample disk drivers supprt multiple sector read/write feature.

+

The write throughput of the flash memory media becomes the worst at single sector write transaction. The write throughput increases as the number of sectors per a write transaction as shown in Figure 6. This effect more appers at faster interface speed and the performance ratio often becomes grater than ten. This graph is clearly explaining how fast is multiple block write (W:16K, 32 sectors) than single block write (W:100, 1 sector), and also larger card tends to be slow at single block write. Number of write transactions also affects life time of the flash memory media. When compared at same amount of write data, the single sector write in Figure 6 above wears flash memory media 16 times more than multiple sector write in Figure 6 below. Single sector write is pretty pain for the flash memory media.

+

Therefore the application program should write the data in large block as possible. The ideal write chunk size and alighment is size of sector, and size of cluster is the best. Of course all layers between the application and the storage device must have consideration on multiple sector write, however most of open-source memory card drivers lack it. Do not split a multiple sector write request into single sector write transactions or the write throughput gets poor. Note that FatFs module and its sample disk drivers supprt multiple sector read/write operation.

Forcing Memory Erase

-

When remove a file with f_remove function, the data clusters occupied by the file are marked 'free' on the FAT. But the data sectors containing the file data are not that applied any process, so that the file data left occupies a part of the flash memory array as 'live block'. If the file data is forced erased on removing the file, those data blocks will be turned in to the free block pool. This may skip internal block erase operation to the data block on next write operation. As the result the write performance might be improved. FatFs can manage this feature by setting _USE_TRIM to 1. Note that this is an expectation of internal process of the flash memory storage and not that always effective. Also f_remove function will take a time when remove a large file. Most applications will not need this feature.

+

When remove a file with f_unlink function, the data clusters occupied by the file are marked 'free' on the FAT. But the data sectors containing the file data are not that applied any process, so that the file data left occupies a part of the flash memory array as 'live block'. If the file data can be erased on removing the file, those data blocks will be turned into the free block pool. This may skip internal block erase operation to the data block on next write operation. As the result the write performance might be improved. FatFs can manage this function by setting _USE_TRIM to 1. Note that this is an expectation of internal process of the storage device and not that always effective. Most applications will not need this function. Also f_unlink function can take a time when remove a large file.

@@ -212,11 +221,11 @@ Figure 6. Comparison between Multiple/Single Sector Write

If a write operation to the FAT volume is interrupted due to any accidental failure, such as sudden blackout, incorrect media removal and unrecoverable disk error, the FAT structure on the volume can be broken. Following images shows the critical section of the FatFs module.

Figure 4. Long critical section
-fig.4 +fig.4
Figure 5. Minimized critical section
-fig.5 +fig.5

An interruption in the red section can cause a cross link; as a result, the object being changed can be lost. If an interruption in the yellow section is occured, there is one or more possibility listed below.

@@ -234,26 +243,28 @@ Figure 5. Minimized critical section

Extended Use of FatFs API

These are examples of extended use of FatFs APIs. New item will be added whenever a useful code is found.

    -
  1. Open or create a file for append
  2. -
  3. Empty a directory
  4. -
  5. Allocate contiguous area to the file
  6. -
  7. Function/Compatible checker for low level disk I/O module
  8. -
  9. FAT image creator
  10. +
  11. Open or create a file for append (for R0.12 and older)
  12. +
  13. Empty a directory
  14. +
  15. Allocate contiguous area to the file (for R0.11a and older)
  16. +
  17. Function/compatibility checker for low level disk I/O module
  18. +
  19. FAT image creator

About FatFs License

-

FatFs has being developped as a personal project of author, ChaN. It is free from the code anyone else wrote. Following code block shows a copy of the FatFs license document that included in the source files.

+

FatFs has being developped as a personal project of the author, ChaN. It is free from the code anyone else wrote at current release. Following code block shows a copy of the FatFs license document that included in the source files.

 /*----------------------------------------------------------------------------/
-/  FatFs - FAT file system module  R0.11                 (C)ChaN, 2015
+/  FatFs - Generic FAT file system module  R0.12a                             /
 /-----------------------------------------------------------------------------/
-/ FatFs module is a free software that opened under license policy of
-/ following conditions.
 /
-/ Copyright (C) 2015, ChaN, all right reserved.
+/ Copyright (C) 2016, ChaN, all right reserved.
 /
+/ FatFs module is an open source software. Redistribution and use of FatFs in
+/ source and binary forms, with or without modification, are permitted provided
+/ that the following condition is met:
+
 / 1. Redistributions of source code must retain the above copyright notice,
 /    this condition and the following disclaimer.
 /
@@ -263,7 +274,7 @@ Figure 5. Minimized critical section
/ by use of this software. /----------------------------------------------------------------------------*/
-

Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code or any forms without source code, does not need to explain about use of FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most open source software licenses including GNU GPL. When you redistribute the FatFs source code with any modification or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software licenses that not conflict with FatFs license.

+

Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, does not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most open source software licenses including GNU GPL. When you redistribute the FatFs source code with any changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software licenses that not conflict with FatFs license.

Return Home

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/chmod.html b/firmware/chibios-portapack/ext/fatfs/doc/en/chmod.html index 8604873c..6a3ffd00 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/chmod.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/chmod.html @@ -72,7 +72,7 @@ FRESULT f_chmod (

QuickInfo

-

Available when _FS_READONLY == 0 and _FS_MINIMIZE == 0.

+

Available when _FS_READONLY == 0 and _USE_CHMOD == 1.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/close.html b/firmware/chibios-portapack/ext/fatfs/doc/en/close.html index e7ac2fd1..c16dfa6f 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/close.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/close.html @@ -45,7 +45,7 @@ FRESULT f_close (

Description

The f_close function closes an open file object. If any data has been written to the file, the cached information of the file is written back to the volume. After the function succeeded, the file object is no longer valid and it can be discarded.

-

Note that if the file object is in read-only mode and _FS_LOCK option is not enabled, the file object can also be discarded without this process. However this is not recommended for future compatibility.

+

Note that if the file object is in read-only mode and _FS_LOCK is not enabled, the file object can also be discarded without this process. However this is not recommended for future compatibility.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/closedir.html b/firmware/chibios-portapack/ext/fatfs/doc/en/closedir.html index 1494d7e4..253d67a6 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/closedir.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/closedir.html @@ -44,7 +44,7 @@ FRESULT f_closedir (

Description

The f_closedir function closes an open directory object. After the function succeeded, the directory object is no longer valid and it can be discarded.

-

Note that the directory object can also be discarded without this process if _FS_LOCK option is not enabled. However this is not recommended for future compatibility.

+

Note that the directory object can also be discarded without this process when option _FS_LOCK is not enabled. However this is not recommended for future compatibility.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/config.html b/firmware/chibios-portapack/ext/fatfs/doc/en/config.html index 82e25c6c..880c3250 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/config.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/config.html @@ -17,7 +17,7 @@

Function Configurations

_FS_READONLY

-

Read/Write(0) or Read-only(1). Read-only configuration removes writing API functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, f_truncate, f_getfree and optional writing functions as well.

+

Read/Write (0) or Read-only (1). Read-only configuration removes writing API functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, f_truncate, f_getfree and optional writing functions as well.

_FS_MINIMIZE

This option defines minimization level to remove some basic API functions as follows:

@@ -39,19 +39,25 @@

_USE_FIND

-

Disable(0) or Enable(1). This option switches filtered directory read feature and related functions, f_findfirst and f_findnext.

+

Disable (0) or Enable (1) filtered directory read functions, f_findfirst and f_findnext. Also _FS_MINIMIZE needs to be 0 or 1.

_USE_MKFS

-

Disable(0) or Enable(1). This option switches f_mkfs function.

+

Disable (0) or Enable (1) f_mkfs function.

_USE_FASTSEEK

-

Disable(0) or Enable(1). This option switches fast seek feature to enable accelerated mode of f_lseek, f_read and f_write function. For more information, read here.

+

Disable (0) or Enable (1) fast seek function to enable accelerated mode of f_lseek, f_read and f_write function. For more information, read here.

+ +

_USE_EXPAND

+

Disable (0) or Enable (1) , f_enpand function. Also _FS_READONLY needs to be 0.

+ +

_USE_CHMOD

+

Disable (0) or Enable (1) metadata manipulation functions, f_chmod and f_utime. Also _FS_READONLY needs to be 0.

_USE_LABEL

-

Disable(0) or Enable(1). This option switches volume label functions, f_getlabel and f_setlabel.

+

Disable (0) or Enable (1) volume label functions, f_getlabel and f_setlabel.

_USE_FORWARD

-

Disable(0) or Enable(1). This option switches f_forward function. also _FS_TINY needs to be set to 1.

+

Disable (0) or Enable (1) f_forward function.

@@ -88,23 +94,23 @@

_USE_LFN

-

This option switches the LFN feature. When enable the LFN feature, Unicode handling functions option/unicode.c must be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. When use stack for the working buffer, take care on stack overflow. When use heap memory for the working buffer, memory management functions, ff_memalloc and ff_memfree, must be added to the project.

+

This option switches the support for long file name (LFN). When enable the LFN, Unicode support functions option/unicode.c need to be added to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and additional 608 bytes when exFAT enabled. When use stack for the working buffer, take care on stack overflow. When use heap memory for the working buffer, memory management functions, ff_memalloc and ff_memfree, need to be added to the project.

- +
ValueDescription
0Disable LFN feature. Only 8.3 format can be used.
0Disable LFN. Only 8.3 format can be used.
1Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
2Enable LFN with dynamic working buffer on the STACK.
3Enable LFN with dynamic working buffer on the HEAP.

_MAX_LFN

-

This option defines the size of LFN working buffer from 12 to 255 in unit of character. This option has no effect when LFN feature is disabled.

+

This option defines the size of LFN working buffer from 12 to 255 in unit of character. This option has no effect when LFN is disabled.

_LFN_UNICODE

-

ANSI/OEM(0) or Unicode(1). This option switches character encoding on the API. To use Unicode (UTF16) string for the path name, enable LFN feature and set this option to 1. This option also affects behavior of string I/O functions. When LFN feature is disabled, this option must be 0. For more information, read here.

+

ANSI/OEM (0) or Unicode (1). This option switches character encoding on the API. To use Unicode (UTF16) string for the path name, enable LFN and set this option to 1. This option also affects behavior of string I/O functions. When LFN is disabled, this option must be 0. For more information, read here.

_STRF_ENCODE

-

When Unicode API is selected by _LFN_UNICODE, this option defines the assumption of character encoding on the file to be read/written via string I/O functions, f_gets, f_putc, f_puts and f_printf. This option has no effect when _LFN_UNICODE == 0.

+

When Unicode API is selected by setting _LFN_UNICODE 1, this option defines the assumption of character encoding on the file to be read/written via string I/O functions, f_gets, f_putc, f_puts and f_printf. This option has no effect when _LFN_UNICODE = 0.

@@ -114,11 +120,11 @@
ValueDescription
0ANSI/OEM

_FS_RPATH

-

This option configures relative path feature. Note that directory items read via directory functions are affected by this option. For more information, read here.

+

This option configures relative path function. For more information, read here.

- - + +
ValueDescription
0Disable relative path feature and remove related functions.
1Enable relative path feature. f_chdir and f_chdrive function is available.
0Disable relative path function and remove related functions.
1Enable relative path function. f_chdir and f_chdrive function is available.
2f_getcwd function is available in addition to 1
@@ -129,22 +135,22 @@

Volume/Drive Configurations

_VOLUMES

-

This option configures number of volumes (logical drives, from 1 to 9) to be used.

+

This option configures number of volumes (logical drives, from 1 to 10) to be used.

_STR_VOLUME_ID

-

Disable(0) or Enable(1). This option switches string volume ID feature. When enabled, also pre-defined strings in _VOLUME_STRS can be used as drive identifier in the path name.

+

Disable (0) or Enable (1). This option switches the support for string volume ID. When enabled, also pre-defined strings in _VOLUME_STRS can be used as drive identifier in the path name.

_VOLUME_STRS

-

This option defines the drive ID strings for each logical drives. Number of items must be equal to _VOLUMES. Valid characters for the drive ID strings are: A-Z and 0-9.

+

This option defines the drive ID strings for each logical drives. Number of items must not be less than _VOLUMES. Valid characters for the drive ID string are: A-Z and 0-9.

_MULTI_PARTITION

-

Disable(0) or Enable(1). This option switches multi-partition feature. By default (0), each logical drive number is bound to the same physical drive number and only an FAT volume each physical drive are mounted. When enabled, each logical drive is bound to the partition on the physical drive listed in the user defined partition resolution table VolToPart[]. Also f_fdisk funciton will be enabled. For more information, read here.

+

Disable (0) or Enable (1). This option switches multi-partition function. By default (0), each logical drive number is bound to the same physical drive number and only an FAT volume in the physical drive is mounted. When enabled, each logical drive is bound to the partition on the physical drive listed in the user defined partition resolution table VolToPart[]. Also f_fdisk funciton will be available. For more information, read here.

_MIN_SS, _MAX_SS

-

This set of options defines size of sector on the low level disk I/O interface, disk_read and disk_write function. Valid numbers are 512, 1024, 2048 and 4096. _MIN_SS defines minimum size of sector and _MAX_SS defines the maximum size of sector. Always set both 512 for all type of memory cards and harddisk. But a larger value may be required for on-board flash memory and some type of optical media. When _MAX_SS > _MIN_SS, FatFs is configured to variable sector size and GET_SECTOR_SIZE command must be implemented to the disk_ioctl function.

+

This set of options defines the size of sector on low level disk I/O interface, disk_read and disk_write function. Valid values are 512, 1024, 2048 and 4096. _MIN_SS defines minimum sector size and _MAX_SS defines the maximum sector size. Always set both 512 for any type of memory card and harddisk. But a larger value may be required for on-board flash memory and some type of optical media. When _MAX_SS > _MIN_SS, FatFs is configured to variable sector size and GET_SECTOR_SIZE command must be implemented to the disk_ioctl function.

_USE_TRIM

-

Disable(0) or Enable(1). This option switches ATA-TRIM feature. To enable Trim feature, also CTRL_TRIM command should be implemented to the disk_ioctl function.

+

Disable (0) or Enable (1). This option switches ATA-TRIM function. To enable Trim function, also CTRL_TRIM command should be implemented to the disk_ioctl function.

_FS_NOFSINFO

0 to 3. If you need to know correct free space on the FAT32 volume, set bit 0 of this option, and f_getfree function at first time after volume mount will force a full FAT scan. Bit 1 controls the use of last allocated cluster number.

@@ -163,55 +169,33 @@

System Configurations

_FS_TINY

-

Normal(0) or Tiny(1). At the tiny configuration, size of the file object FIL is reduced _MAX_SS bytes. Instead of private data buffer eliminated from the file object, common sector buffer in the file system object FATFS is used for the file data transfer.

+

Normal (0) or Tiny (1). At the tiny configuration, size of the file object FIL is reduced _MAX_SS bytes. Instead of private data buffer eliminated from the file object, common sector buffer in the file system object FATFS is used for the file data transfer.

+ +

_FS_EXFAT

+

This option switches support for the exFAT file system in addition to the FAT file system, Enabled(1) or Disabled(1). To enable this feature, also LFN must be enabled and configureing _LFN_UNICODE = 1 and _MAX_LFN = 255 is recommended for full-featured exFAT function. Note that enabling exFAT discards C89 compatibility because of need for 64-bit integer type.

_FS_NORTC

-

Use RTC(0) or Do not use RTC(1). This option controls timestamp feature. If the system does not have an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable the timestamp feature. Any object modified by FatFs will have a fixed timestamp value defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. To use the timestamp feature, set _FS_NORTC to 0 and add get_fattime function to the project to get the current time form RTC. This option has no effect at read-only configuration.

+

Use RTC (0) or Do not use RTC (1). This option controls timestamp function. If the system does not have an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable the timestamp function. Any object modified by FatFs will have a fixed timestamp value defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. To use the timestamp function, set _FS_NORTC = 0 and add get_fattime function to the project to get the current time form real-time clock. This option has no effect at read-only configuration.

_NORTC_MON, _NORTC_MDAY, _NORTC_YEAR

-

This set of options defines default timestamp to be used at no RTC systems. This option has no effect at read-only configuration or _FS_NORTC == 0.

+

This set of options defines the time to be used at no RTC systems. This option has no effect at read-only configuration or _FS_NORTC = 0.

_FS_LOCK

-

This option switches file lock feature to control duplicated file open and illegal operations to open objects. Note that the file lock feature is independent of re-entrancy. This option must be 0 at read-only configuration.

+

This option switches file lock function to control duplicated file open and illegal operations to open objects. Note that the file lock function is independent of re-entrancy. This option must be 0 at read-only configuration.

- - + +
ValueDescription
0Disable file lock feature. To avoid volume corruption, application program should avoid illegal open, remove and rename to the open objects.
>0Enable file lock feature. The value defines how many files/sub-directories can be opened simultaneously under file lock control. Illigal operations to the open object will be rejected with FR_LOCKED.
0Disable file lock function. To avoid volume corruption, application program should avoid illegal open, remove and rename to the open objects.
>0Enable file lock function. The value defines how many files/sub-directories can be opened simultaneously under file lock control. Illigal operations to the open object will be rejected with FR_LOCKED.

_FS_REENTRANT

-

Disable(0) or Enable(1). This option switches the re-entrancy (thread safe) of the FatFs module itself. Note that file/directory access to the different volume is always re-entrant and it can work simultaneously regardless of this option but volume control functions, f_mount, f_mkfs and f_fdisk, are always not re-entrant. Only file/directory access to the same volume, in other words, exclusive use of each file system object, is under control of this feature. To enable this feature, also user provided synchronization handlers, ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj, must be added to the project. Samples are available in option/syscall.c.

+

Disable (0) or Enable (1). This option switches the re-entrancy (thread safe) of the FatFs module itself. Note that file/directory access to the different volume is always re-entrant and it can work simultaneously regardless of this option but volume control functions, f_mount, f_mkfs and f_fdisk, are always not re-entrant. Only file/directory access to the same volume, in other words, exclusive use of each file system object, is under control of this function. To enable this feature, also user provided synchronization handlers, ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj, need to be added to the project. Sample code is available in option/syscall.c.

_FS_TIMEOUT

-

Number of time ticks to abort the file function with FR_TIMEOUT when wait time is too long. This option has no effect when _FS_REENTRANT == 0.

+

Number of time ticks to abort the file function with FR_TIMEOUT when wait time is too long. This option has no effect when _FS_REENTRANT = 0.

_SYNC_t

-

This option defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, SemaphoreHandle_t and etc. A header file for O/S definitions needs to be included somewhere in the scope of ff.c. This option has no effect when _FS_REENTRANT == 0.

- -

_WORD_ACCESS

-

This is an only platform dependent option. It defines which access method is used to the word data on the FAT volume.

- - - - -
ValueDescription
0Byte-by-byte access. Always compatible with all platforms.
1Word access. Code size will be slightly reduced but do not choose this unless under both the following conditions.
-* Unaligned memory access is always allowed to ALL instructions.
-* Byte order on the memory is little-endian.
-

Following table shows an example of allowable settings of some type of processors.

-
-   ARM7TDMI   0   *2         ColdFire   0   *1         V850E      0   *2
-   Cortex-M3  0   *3         Z80        0/1            V850ES     0/1
-   Cortex-M0  0   *2         x86        0/1            TLCS-870   0/1
-   AVR        0/1            RX600(LE)  0/1            TLCS-900   0/1
-   AVR32      0   *1         RL78       0   *2         R32C       0   *2
-   PIC18      0/1            SH-2       0   *1         M16C       0/1
-   PIC24      0   *2         H8S        0   *1         MSP430     0   *2
-   PIC32      0   *1         H8/300H    0   *1         8051       0/1
-
-   *1:Big-endian.
-   *2:Unaligned memory access is not supported.
-   *3:Some compilers generate LDM/STM for mem_cpy function.
-
+

This option defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, SemaphoreHandle_t and etc. A header file for O/S definitions needs to be included somewhere in the scope of ff.c. This option has no effect when _FS_REENTRANT = 0.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/dinit.html b/firmware/chibios-portapack/ext/fatfs/doc/en/dinit.html index d66a0a19..4a003e70 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/dinit.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/dinit.html @@ -38,7 +38,7 @@ DSTATUS disk_initialize (

Description

This function initializes the storage device and put it ready to generic read/write. When the function succeeded, STA_NOINIT flag in the return value is cleared.

-

This function is under control of FatFs module. Application program MUST NOT call this function, or FAT structure on the volume can be broken. To re-initialize the file system, use f_mount function instead.

+

Remarks: This function needs to be under control of FatFs module. Application program MUST NOT call this function, or FAT structure on the volume can be broken. To re-initialize the file system, use f_mount function instead.

Return

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/dioctl.html b/firmware/chibios-portapack/ext/fatfs/doc/en/dioctl.html index e05b80af..7c692511 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/dioctl.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/dioctl.html @@ -13,7 +13,7 @@

disk_ioctl

-

The disk_ioctl function cntrols device specific features and miscellaneous functions other than generic read/write.

+

The disk_ioctl function controls device specific features and miscellaneous functions other than generic read/write.

 DRESULT disk_ioctl (
   BYTE pdrv,     /* [IN] Drive number */
@@ -61,7 +61,7 @@ DRESULT disk_ioctl (
 GET_SECTOR_COUNTReturns number of available sectors on the drive into the DWORD variable pointed by buff. This command is used by only f_mkfs and f_fdisk function to determine the volume/partition size to be created. Required at _USE_MKFS == 1 or _MULTI_PARTITION == 1.
 GET_SECTOR_SIZEReturns sector size of the media into the WORD variable pointed by buff. Valid return values of this command are 512, 1024, 2048 and 4096. This command is required only at variable sector size configuration, _MAX_SS > _MIN_SS. At fixed sector size configuration, _MAX_SS == _MIN_SS, this command is not used and the device must work at that sector size.
 GET_BLOCK_SIZEReturns erase block size of the flash memory media in unit of sector into the DWORD variable pointed by buff. The allowable value is from 1 to 32768 in power of 2. Return 1 if the erase block size is unknown or non flash memory media. This command is used by only f_mkfs function and it attempts to align data area to the erase block boundary. Required at _USE_MKFS == 1.
-CTRL_TRIMInforms the device the data on the block of sectors that specified by DWORD array {<start sector>, <end sector>} pointed by buff is no longer needed and it may be erased. This is an identical command to Trim of ATA device. When this feature is not supported or not a flash memory device, nothing to do for this command. The FatFs does not check the result code and the file function is not affected even if the sector block was not erased well. This command is called on removing a cluster chain and f_mkfs function. Required at _USE_TRIM == 1.
+CTRL_TRIMInforms the device the data on the block of sectors that specified by DWORD array {<start sector>, <end sector>} pointed by buff is no longer needed and it may be erased. This is an identical command to Trim of ATA device. Nothing to do for this command if this funcion is not supported or not a flash memory device. The FatFs does not check the result code and the file function is not affected even if the sector block was not erased well. This command is called on remove a cluster chain and in the f_mkfs function. Required at _USE_TRIM == 1.
 
 
 

FatFs never uses any device dependent command nor user defined command. Following table shows an example of non-standard commands usable for some applications.

@@ -82,6 +82,9 @@ DRESULT disk_ioctl ( ATA_GET_REVGet the revision string into a 16-byte buffer pointed by buff. (ATA/CFC specific command) ATA_GET_MODELGet the model string into a 40-byte buffer pointed by buff. (ATA/CFC specific command) ATA_GET_SNGet the serial number string into a 20-byte buffer pointed by buff. (ATA/CFC specific command) +ISDIO_READRead a block of iSDIO registers specified by command structure pointed by buff. (FlashAir specific command) +ISDIO_WRITEWrite a block of data to iSDIO registers specified by command structure pointed by buff. (FlashAir specific command) +ISDIO_MRITEChange bits in an iSDIO register specified by command structure pointed by buff. (FlashAir specific command)
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/dread.html b/firmware/chibios-portapack/ext/fatfs/doc/en/dread.html index ba31d034..14227de6 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/dread.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/dread.html @@ -34,7 +34,7 @@ DRESULT disk_read (
sector
Start sector number in 32-bit LBA.
count
-
Number of sectors to read. FatFs specifies the value in range of from 1 to 128.
+
Number of sectors to read.
@@ -56,12 +56,12 @@ DRESULT disk_read (

Description

-

The data read/write operation to the storage devices is done in unit of sector. FatFs supports the sector size in range of from 512 to 4096 bytes. When FatFs is configured to fixed sector size (_MIN_SS == MAX_SS, this will be the most case), the read/write function must work at that sector size. When FatFs is configured to variable sector size (_MIN_SS < MAX_SS), sector size is inquired with disk_ioctl function following disk_initialize function. -

The memory address specified by buff is not that always aligned to word boundary because the argument is defined as BYTE*. The misaligned read/write request can occure at direct transfer. If the bus architecture, especially DMA controller, does not allow misaligned memory access, it should be solved in this function. There are some workarounds described below to avoid this issue.

+

The data read/write operation to the storage devices is done in unit of sector. FatFs supports the sector size in range of from 512 to 4096 bytes. When FatFs is configured to fixed sector size (_MIN_SS == MAX_SS, this will be the most case), the read/write function must work at that sector size. When FatFs is configured to variable sector size (_MIN_SS != MAX_SS), sector size is inquired with disk_ioctl function following disk_initialize function.

+

The memory address specified by buff is not that always aligned to word boundary because the argument is defined as BYTE*. The unaligned read/write request can occure at direct transfer. If the bus architecture, especially DMA controller, does not allow unaligned memory access, it should be solved in this function. There are some workarounds described below to avoid this issue.

Generally, a multiple sector transfer request must not be split into single sector transactions to the storage device, or you will not get good read throughput.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/dstat.html b/firmware/chibios-portapack/ext/fatfs/doc/en/dstat.html index cadcd41d..07514609 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/dstat.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/dstat.html @@ -35,11 +35,11 @@ DSTATUS disk_status (

The current drive status is returned in combination of status flags described below. FatFs refers only STA_NOINIT and STA_PROTECT.

STA_NOINIT
-
Indicates that the device is not initialized. This flag is set on system reset, media removal or failure of disk_initialize function. It is cleared on disk_initialize function succeeded. Media change that occurs asynchronously must be captured and reflect it to the status flags, or auto-mount feature will not work correctly. If the system does not support media change detect feature, application program needs to force de-initialize the file system object with f_mount function after the media change.
+
Indicates that the device is not initialized and not ready to work. This flag is set on system reset, media removal or failure of disk_initialize function. It is cleared on disk_initialize function succeeded. Any media change that occurs asynchronously must be captured and reflect it to the status flags, or auto-mount function will not work correctly. If the system does not support media change detection, application program needs to force de-initialize the file system object and re-mount the volume with f_mount function after each media change.
STA_NODISK
-
Indicates that no medium in the drive. This is always cleared on fixed disk drive. Note that FatFs does not refer this flag.
+
Indicates that no medium in the drive. This is always cleared at fixed disk drive. Note that FatFs does not refer this flag.
STA_PROTECT
-
Indicates that the medium is write protected. This is always cleared on the drives without write protect feature. Not valid if no medium in the drive.
+
Indicates that the medium is write protected. This is always cleared at the drives without write protect function. Not valid if no medium in the drive.
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/dwrite.html b/firmware/chibios-portapack/ext/fatfs/doc/en/dwrite.html index b29b6f34..4ee6d09a 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/dwrite.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/dwrite.html @@ -34,7 +34,7 @@ DRESULT disk_write (
sector
Start sector number in 32-bit LBA.
count
-
Number of sectors to write. FatFs specifies the value in range of from 1 to 128.
+
Number of sectors to write.
@@ -60,8 +60,8 @@ DRESULT disk_write (

Description

The specified memory address is not that always aligned to word boundary because the type of pointer is defined as BYTE*. For more information, refer to the description of disk_read function.

Generally, a multiple sector transfer request must not be split into single sector transactions to the storage device, or you will never get good write throughput.

-

FatFs expects delayed write feature of the disk control layer. The write operation to the media need not to be completed due to write operation is in progress or data is stored into the write-back cache when return from this function. But write data on the buff is invalid after return from this function. The write completion request is done by CTRL_SYNC command of disk_ioctl function. Therefore, if a delayed write feature is implemented, the write throughput will be improved.

-

Application program MUST NOT call this function, or FAT structure on the volume can be collapsed.

+

FatFs expects delayed write function of the disk control layer. The write operation to the media does not need to be completed when return from this function by what write operation is in progress or data is only stored into the write-back cache. But write data on the buff is invalid after return from this function. The write completion request is done by CTRL_SYNC command of disk_ioctl function. Therefore, if a delayed write function is implemented, the write throughput will be improved.

+

Remarks: Application program MUST NOT call this function, or FAT structure on the volume can be collapsed.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/eof.html b/firmware/chibios-portapack/ext/fatfs/doc/en/eof.html index 40944c3c..2e875062 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/eof.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/eof.html @@ -39,7 +39,7 @@ int f_eof (

Description

-

In this revision, this function is implemented as a macro. It has not any validation and mutual exclusion.

+

In this revision, this function is implemented as a macro. It does not have any validation and mutual exclusion.

 #define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
 
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/error.html b/firmware/chibios-portapack/ext/fatfs/doc/en/error.html index b8ceef5e..3476f55c 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/error.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/error.html @@ -39,9 +39,9 @@ int f_error (

Description

-

In this revision, this function is implemented as a macro. It has not any validation and mutual exclusion.

+

In this revision, this function is implemented as a macro. It does not have any validation and mutual exclusion.

-#define f_error(fp) ((fp)->flag)
+#define f_error(fp) ((fp)->err)
 
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/expand.html b/firmware/chibios-portapack/ext/fatfs/doc/en/expand.html new file mode 100644 index 00000000..434580cf --- /dev/null +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/expand.html @@ -0,0 +1,116 @@ + + + + + + + + +FatFs - f_expand + + + + +
+

f_expand

+

The f_expand function prepares or allocates a contiguous data area to the file.

+ +
+FRESULT f_expand (
+  FIL*    fp,  /* [IN] File object */
+  FSIZE_t fsz, /* [IN] File size expanded to */
+  BYTE    opt  /* [IN] Operation mode */
+);
+
+
+ +
+

Parameters

+
+
fp
+
Pointer to the open file object.
+
fsz
+
Number of bytes in size to prepare or allocate for the file. The data type FSIZE_t is an alias of either DWORD(32-bit) or QWORD(64-bit) depends on the configuration option _FS_EXFAT.
+
opt
+
Operation mode. Prepare only (0) or Allocate now (1).
+
+
+ + + + + +
+

Description

+

The f_expand function prepares or allocates a contiguous data area to the file. When opt is 1, the function allocates a contiguous data area to the file. Unlike expansion of file by f_lseek function, the file must be truncated prior to use this function and read/write pointer of the file stays at top of the file after the function. The file content allocated with this function is undefined because no data is written to the file in this process. The function can fail with FR_DENIED due to some reasons below.

+
    +
  • No free contiguous space was found.
  • +
  • Size of the file was not zero.
  • +
  • The file has been opened in read-only mode.
  • +
  • Not allowable file size. (>= 4GiB on FAT volume)
  • +
+

When opt is 0, the function finds a contiguous data area and set it as suggested point for next allocation instead of allocating it to the file. The next cluster allocation is started at top of the contiguous area found by this function. Thus the write file is guaranteed be contiguous and no allocation delay until the size reaches that size at least unless any other operation to the volume with changes of FAT is performed.

+

The contiguous file would have an advantage at time-critical read/write operations. It reduces some overheads in the file system and the storage media caused by random access due to fragmented file data. Especially, at the exFAT volume, any FAT access for the contiguous file is completely eliminated and storage media will be accessed sequentially.

+

Also the contiguous file data can be easily accessed directly via low-level disk functions but it is not recommended in consideration for future compatibility.

+
+ +
+

QuickInfo

+

Available when _USE_EXPAND == 1 and _FS_READONLY == 0.

+
+ + +
+

Example

+
+    /* Creating a contiguous file */
+
+    /* Create a new file */
+    res = f_open(fp = malloc(sizeof (FIL)), "file.dat", FA_WRITE|FA_CREATE_ALWAYS);
+    if (res) { /* Check if the file has been opened */
+        free(fp);
+        ...
+    }
+
+    /* Alloacte a 100 MiB of contiguous area to the file */
+    res = f_expand(fp, 104857600, 1);
+    if (res) { /* Check if the file has been expanded */
+        ...
+        free(fp);
+        ...
+    }
+    /* Now you have a contiguous file accessible with fp */
+
+
+
+    /* Accessing the file data directly via low-level disk functions */
+
+    /* Get physical location of the file data */
+    drv = fp->obj.fs->drv;
+    sect = fp->obj.fs->database + fp->obj.fs->csize * (fp->obj.sclust - 2);
+
+    /* Write 2048 sectors from top of the file at a time */
+    res = disk_write(drv, buffer, sect, 2048);
+
+
+
+ + +
+

See Also

+

f_open, f_lseek, FIL

+
+ +

Return

+ + diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/fdisk.html b/firmware/chibios-portapack/ext/fatfs/doc/en/fdisk.html index 828bbe55..6581d87c 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/fdisk.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/fdisk.html @@ -16,9 +16,9 @@

The f_fdisk fucntion divides a physical drive.

 FRESULT f_fdisk (
-  BYTE  pdrv,         /* [IN] Physical drive number */
-  const DWORD part[], /* [IN] Partition size */
-  void* work          /* [IN] Work area */
+  BYTE  pdrv,        /* [IN] Physical drive number */
+  const DWORD* szt,  /* [IN] Partition map table */
+  void* work         /* [IN] Work area */
 );
 
@@ -27,9 +27,9 @@ FRESULT f_fdisk (

Parameters

pdrv
-
Specifies the physical drive to be divided.
-
part[]
-
Partition map table. It must have four items.
+
Specifies the physical drive to be divided. This is not the logical drive number but the drive identifier passed to the low level disk functions.
+
szt
+
Pointer to the first item of the partition map table.
work
Pointer to the function work area. The size must be at least _MAX_SS bytes.
@@ -48,7 +48,7 @@ FRESULT f_fdisk (

Description

-

The f_fdisk function creates a partition table into the MBR of the physical drive. The partitioning rule is in generic FDISK format, so that it can create upto four primary partitions. Logical volumes in the extended partition is not supported. The part[] with four items specifies how to divide the physical drive. The first item specifies the size of first primary partition and fourth item specifies the fourth primary partition. If the value is less than or equal to 100, it specifies percentage of the partition in the entire disk space. If it is larger than 100, it specifies the partition size in unit of sector.

+

The f_fdisk function creates partitions on the physical drive. The partitioning format is in generic FDISK format, so that it can create upto four primary partitions. Logical volumes in the extended partition is not supported. The partition map table with four items specifies how to divide the physical drive. The first item specifies the size of first primary partition and fourth item specifies the fourth primary partition. If the value is less than or equal to 100, it specifies the partition size in percentage of the entire drive space. If it is larger than 100, it specifies the partition size in unit of sector. The partitions are located on the drive in order of from first item.

@@ -74,15 +74,10 @@ FRESULT f_fdisk ( DWORD plist[] = {50, 50, 0, 0}; /* Divide drive into two partitions */ BYTE work[_MAX_SS]; - f_fdisk(0, plist, work); /* Divide physical drive 0 */ + f_fdisk(0, plist, work); /* Divide physical drive 0 */ - f_mount(&fs, "0:", 0); /* Register work area to the logical drive 0 */ - f_mkfs("0:", 0, 0); /* Create FAT volume on the logical drive 0. 2nd argument is ignored. */ - f_mount(0, "0:", 0); /* Unregister work area from the logical drive 0 */ - - f_mount(&fs, "1:", 0); /* Register a work area to the logical drive 1 */ - f_mkfs("1:", 0, 0); /* Create FAT volume on the logical drive 1. 2nd argument is ignored. */ - f_mount(0, "1:", 0); /* Unregister work area from the logical drive 1 */ + f_mkfs("0:", FMT_ANY, work, sizeof work); /* Create FAT volume on the logical drive 0 */ + f_mkfs("1:", FMT_ANY, work, sizeof work); /* Create FAT volume on the logical drive 1 */
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/filename.html b/firmware/chibios-portapack/ext/fatfs/doc/en/filename.html index 1faafdf9..23e6c49c 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/filename.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/filename.html @@ -16,10 +16,10 @@

Format of the path names

The format of path name on the FatFs module is similer to the filename specs of DOS/Windos as follows:

"[drive:][/]directory/file"
-

The FatFs module supports long file name (LFN) and 8.3 format file name (SFN). The LFN can be used when LFN feature is enabled (_USE_LFN > 0). The sub directories are separated with a \ or / in the same way as DOS/Windows API. Duplicated separators are skipped and ignored. Only a difference is that the logical drive is specified in a numeral with a colon. When drive number is omitted, the drive number is assumed as default drive (drive 0 or current drive).

+

The FatFs module supports long file name (LFN) and 8.3 format file name (SFN). The LFN can be used when (_USE_LFN != 0). The sub directories are separated with a \ or / in the same way as DOS/Windows API. Duplicated separators are skipped and ignored. Only a difference is that the logical drive is specified in a numeral with a colon. When drive number is omitted, the drive number is assumed as default drive (drive 0 or current drive).

Control characters ('\0' to '\x1F') are recognized as end of the path name. Leading/embedded spaces in the path name are valid as a part of the name at LFN configuration but the space is recognized as end of the path name at non-LFN configuration. Trailing spaces and dots are ignored at both configurations.

-

In default configuration (_FS_RPATH >= 0), it does not have a concept of current directory like OS oriented file system. All objects on the volume are always specified in full path name that follows from the root directory. Dot directory names (".", "..") are not allowed. Heading separator is ignored and it can be exist or omitted. The default drive is fixed to drive 0.

-

When relative path feature is enabled (_FS_RPATH >= 1), specified path is followed from the root directory if a heading separator is exist. If not, it is followed from the current directory of the drive set by f_chdir function. Dot names are also allowed for the path names. The default drive is the current drive set by f_chdrive function.

+

In default configuration (_FS_RPATH == 0), it does not have a concept of current directory like OS oriented file system. All objects on the volume are always specified in full path name that follows from the root directory. Dot directory names (".", "..") are not allowed. Heading separator is ignored and it can be exist or omitted. The default drive is fixed to drive 0.

+

When relative path is enabled (_FS_RPATH >= 1), specified path is followed from the root directory if a heading separator is exist. If not, it is followed from the current directory of the drive set by f_chdir function. Dot names are also allowed for the path names. The default drive is the current drive set by f_chdrive function.

@@ -31,11 +31,12 @@ - +
Path name_FS_RPATH == 0_FS_RPATH >= 1
file.txtA file in the root directory of the drive 0A file in the current directory of the current drive
2:file.txtA file in the root directory of the drive 2A file in the current directory of the drive 2
../file.txtInvalid nameA file in the parent directory
.Invalid nameThis directory
..Invalid nameParent directory of the current directory
..Invalid nameParent directory of the current directory (*)
dir1/..Invalid nameThe current directory
/..Invalid nameThe root directory (sticks the top level)
-

When option _STR_VOLUME_ID is specified, also pre-defined strings can be used as drive identifier in the path name instead of a numeral. e.g. "sd:file1.txt" or "ram:swapfile.dat".

+

When option _STR_VOLUME_ID is specified, also pre-defined strings can be used as drive identifier in the path name instead of a numeral. e.g. "sd:file1.txt", "ram:swapfile.dat" and DOS/Windows style drive letter, of course.

+

Remark: In this revision, R0.12, double dot name ".." cannot follow the parent directory on the exFAT volume. It will work as "." and stay there.

@@ -47,7 +48,7 @@

Unicode API

-

The path names are input/output in either ANSI/OEM code or Unicode depends on the configuration options. The type of arguments which specify the path names are defined as TCHAR. It is an alias of char by default. The code set used to the path name string is ANSI/OEM specifid by _CODE_PAGE. When _LFN_UNICODE is set to 1, the type of the TCHAR is switched to WCHAR to support Unicode (UTF-16 encoding). In this case, the LFN feature is fully supported and the Unicode specific characters, such as ✝☪✡☸☭, can also be used for the path name. It also affects data types and encoding of the string I/O functions. To define literal strings, _T(s) and _TEXT(s) macro are available to select either ANSI/OEM or Unicode automatically. The code shown below is an example to define the literal strings.

+

The path names are input/output in either ANSI/OEM code or Unicode depends on the configuration options. The type of arguments which specify the path names are defined as TCHAR. It is an alias of char by default. The code set used to the path name string is ANSI/OEM specifid by _CODE_PAGE. When _LFN_UNICODE is set to 1, the type of the TCHAR is switched to WCHAR to support Unicode (UTF-16 encoding). In this case, the full-featured LFN specification is supported and the Unicode specific characters, such as ✝☪✡☸☭, can also be used for the path name. It also affects data types and encoding of the string I/O functions. To define literal strings, _T(s) and _TEXT(s) macro are available to select either ANSI/OEM or Unicode automatically. The code shown below is an example to define the literal strings.

  f_open(fp, "filename.txt", FA_READ);      /* ANSI/OEM string */
  f_open(fp, L"filename.txt", FA_READ);     /* Unicode string */
@@ -57,25 +58,25 @@
 
 

Volume Management

-

The FatFs module needs dynamic work area called file system object for each volume (logical drive). It is registered to the FatFs module by f_mount function. By default, each logical drive is bound to the physical drive with the same drive number and an FAT volume on the drive is serched by auto detect feature. It loads boot sectors and checks it if it is an FAT boot sector in order of sector 0 as SFD format, 1st partition, 2nd partition, 3rd partition and 4th partition as FDISK format.

+

FatFs module needs dynamic work area, file system object, for each volume (logical drive). It is registered/unregistered to the FatFs module by f_mount function. By default, each logical drive is bound to the physical drive with the same drive number and an FAT volume on the drive is serched by the volume mount process. It reads boot sectors and checks it if it is an FAT boot sector in order of sector 0 as SFD format, 1st partition, 2nd partition, 3rd partition and 4th partition as FDISK format.

When _MULTI_PARTITION == 1 is specified by configuration option, each individual logical drive is bound to the partition on the physical drive specified by volume management table. The volume management table must be defined by user to resolve the relationship between logical drives and partitions. Following code is an example of a volume management table.

-Example: Logical drive 0-2 are tied to three pri-partitions on the physical drive 0 (fixed disk)
-         Logical drive 3 is tied to an FAT volume on the physical drive 1 (removable disk)
+Example: Logical drive 0-2 are tied to three pri-partitions on the physical drive 0 (fixed drive)
+         Logical drive 3 is tied to an FAT volume on the physical drive 1 (removable drive)
 
 PARTITION VolToPart[] = {
-    {0, 1},     /* Logical drive 0 ==> Physical drive 0, 1st partition */
-    {0, 2},     /* Logical drive 1 ==> Physical drive 0, 2nd partition */
-    {0, 3},     /* Logical drive 2 ==> Physical drive 0, 3rd partition */
-    {1, 0}      /* Logical drive 3 ==> Physical drive 1 (auto detection) */
+    {0, 1},     /* "0:" ==> Physical drive 0, 1st partition */
+    {0, 2},     /* "1:" ==> Physical drive 0, 2nd partition */
+    {0, 3},     /* "2:" ==> Physical drive 0, 3rd partition */
+    {1, 0}      /* "3:" ==> Physical drive 1, auto detection */
 };
 
-
relationship between logical drive and physical drive
+
relationship between logical drive and physical drive

There are some considerations on using multi-partition configuration.

  • The physical drive that has two or more mounted partitions must be non-removable. Media change while a system operation is prohibited.
  • Only four primary partitions can be specified. Extended partition is not supported.
  • -
  • Windows does not support multiple volumes on the removable storage. Only first parition will be mounted.
  • +
  • Windows does not support multiple volumes on the removable storage. Only first parition will be recognized.
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/findfirst.html b/firmware/chibios-portapack/ext/fatfs/doc/en/findfirst.html index 66130386..5b4b1fbc 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/findfirst.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/findfirst.html @@ -34,7 +34,7 @@ FRESULT f_findfirst (
path
Pointer to the null-terminated string that specifies the directory name to be opened.
pattern
-
Pointer to the null-terminated string that specifies the name matching pattern to be searched for. It is referred by also subsequent f_findnext function, so that the string must be valid while the successive function calls.
+
Pointer to the nul-terminated string that specifies the name matching pattern to be searched for. It is referred by also subsequent f_findnext function, so that the string must be valid while the successive function calls.
@@ -61,11 +61,11 @@ FRESULT f_findfirst (

Description

-

After the directory specified by path could be opened, it starts to search the directory for the item with a name specified by pattern. If found, the information about the object is stored into the file information structure. For more information about file information structure, refer to f_readdir function.

-

The matching pattern can contain wildcard characters (? and *). A ? matches an any character and an * matches an any string in length of zero or longer. At LFN configuration, both names of the item, SFN and LFN (if exist), are tested. In this revision, there are some differences listed below between FatFs and standard systems in matching condition.

+

After the directory specified by path could be opened, it starts to search the directory for the items with a name specified by pattern. If found, the information about the object is stored into the file information structure. For more information about file information structure, refer to f_readdir function.

+

The matching pattern can contain wildcard characters (? and *). A ? matches an any character and an * matches an any string in length of zero or longer. When support of long file name is enabled, only fname[] is tested at _USE_FIND == 1 and also altname[] is tested at _USE_FIND == 2. In this revision, there are some differences listed below between FatFs and standard systems in matching condition.

    -
  • "*.*" never matches any name without extension. (It matches all names at the standard systems)
  • -
  • Any pattern terminated with a period never matches any name. (It matches the names without extensiton at the standard systems)
  • +
  • "*.*" never matches any name without extension while it matches any names at the standard systems.
  • +
  • Any patterns terminated with a period never matches any name while it matches any names without extensiton at the standard systems.
  • DBCS extended characters are compared in case-sensitive at LFN with non-Unicode configuration.
@@ -73,7 +73,7 @@ FRESULT f_findfirst (

QuickInfo

-

This is a wrapper function of f_opendir and f_readdir function. Available when _USE_FIND == 1 and _FS_MINIMIZE <= 1.

+

This is a wrapper function of f_opendir and f_readdir function. Available when _USE_FIND >= 1 and _FS_MINIMIZE <= 1.

@@ -87,20 +87,11 @@ void find_image (void) FRESULT fr; /* Return value */ DIR dj; /* Directory search object */ FILINFO fno; /* File information */ -#if _USE_LFN - char lfn[_MAX_LFN + 1]; - fno.lfname = lfn; - fno.lfsize = _MAX_LFN + 1; -#endif - fr = f_findfirst(&dj, &fno, "", "dsc*.jpg"); /* Start to search for JPEG files with the name started by "dsc" */ + fr = f_findfirst(&dj, &fno, "", "dsc*.jpg"); /* Start to search for photo files */ while (fr == FR_OK && fno.fname[0]) { /* Repeat while an item is found */ -#if _USE_LFN - printf("%-12s %s\n", fno.fname, fno.lfname);/* Display the item name */ -#else - printf("%s\n", fno.fname); -#endif + printf("%s\n", fno.fname); /* Display the object name */ fr = f_findnext(&dj, &fno); /* Search for next item */ } f_closedir(&dj); diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/forward.html b/firmware/chibios-portapack/ext/fatfs/doc/en/forward.html index 7581140c..eddb051f 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/forward.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/forward.html @@ -59,7 +59,7 @@ FRESULT f_forward (

QuickInfo

-

Available when _USE_FORWARD == 1 and _FS_TINY == 1.

+

Available when _USE_FORWARD == 1.

@@ -112,7 +112,7 @@ FRESULT play_file ( if (rc) return rc; /* Repeat until the file pointer reaches end of the file */ - while (rc == FR_OK && !f_eof(&fil)) { + while (rc == FR_OK && !f_eof(&fil)) { /* any other processes... */ diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/getcwd.html b/firmware/chibios-portapack/ext/fatfs/doc/en/getcwd.html index cee958a6..c30aa650 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/getcwd.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/getcwd.html @@ -51,6 +51,7 @@ FRESULT f_getcwd (

Description

The f_getcwd function retrieves full path name of the current directory of the current drive. When _VOLUMES is larger than 1, a logical drive number is added to top of the path name.

+

Note: In this revision, R0.12, this function cannot retrieve the current directory path on the exFAT volume. It always returns the root directory path.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/getlabel.html b/firmware/chibios-portapack/ext/fatfs/doc/en/getlabel.html index 736792fd..cec65aa6 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/getlabel.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/getlabel.html @@ -29,7 +29,7 @@ FRESULT f_getlabel (
path
Pointer to the null-terminated string that specifies the logical drive. Null-string specifies the default drive.
label
-
Pointer to the buffer to store the volume label. The buffer size must be at least 12 items. If the volume has no label, a null-string will be returned. Set null pointer if this information is not needed.
+
Pointer to the buffer to store the volume label. The buffer size must be at least 24 items at _LFN_UNICODE == 0 or 12 items at _LFN_UNICODE == 1. If the volume has no label, a null-string will be returned. Set null pointer if this information is not needed.
vsn
Pointer to the DWORD variable to store the volume serial number. Set null pointer if this information is not needed.
@@ -60,7 +60,7 @@ FRESULT f_getlabel (

Example

-    char str[12];
+    char str[24];
 
     /* Get volume label of the default drive */
     f_getlabel("", str, 0);
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/lseek.html b/firmware/chibios-portapack/ext/fatfs/doc/en/lseek.html
index e684a380..cf4f47e5 100644
--- a/firmware/chibios-portapack/ext/fatfs/doc/en/lseek.html
+++ b/firmware/chibios-portapack/ext/fatfs/doc/en/lseek.html
@@ -17,8 +17,8 @@
 
 
 FRESULT f_lseek (
-  FIL* fp,   /* [IN] File object */
-  DWORD ofs  /* [IN] File read/write pointer */
+  FIL*    fp,  /* [IN] File object */
+  FSIZE_t ofs  /* [IN] File read/write pointer */
 );
 
@@ -29,7 +29,7 @@ FRESULT f_lseek (
fp
Pointer to the open file object.
ofs
-
Byte offset from top of the file.
+
Byte offset from top of the file. The data type FSIZE_t is an alias of either DWORD(32-bit) or QWORD(64-bit) depends on the configuration option _FS_EXFAT.
@@ -48,19 +48,19 @@ FRESULT f_lseek (

Description

-

The f_lseek function moves the file read/write pointer of an open file. The offset can be specified in only origin from top of the file. When an offset beyond the file size is specified at write mode, the file size is expanded to the specified offset. The file data in the expanded area is undefined because no data is written to the file. This is suitable to pre-allocate a cluster chain quickly, for fast write operation. After the f_lseek function succeeded, the current read/write pointer should be checked in order to make sure the read/write pointer has been moved correctry. In case of the current read/write pointer is not the expected value, either of followings has been occured.

+

The f_lseek function moves the file read/write pointer of an open file. The offset can be specified in only origin from top of the file. When an offset beyond the file size is specified at write mode, the file size is expanded to the specified offset. The file data in the expanded area is undefined because no data is written to the file in this process. This is suitable to pre-allocate a cluster chain quickly, for fast write operation. When a contiguous data area needs to be allocated to the file, use f_expand function instead. After the f_lseek function succeeded, the current read/write pointer should be checked in order to make sure the read/write pointer has been moved correctry. In case of the read/write pointer is not the expected value, either of followings has been occured.

-

The fast seek feature enables fast backward/long seek operations without FAT access by using an on-memory CLMT (cluster link map table). It is applied to f_read and f_write function as well, however, the file size cannot be expanded by f_write, f_lseek function while the file is in fast seek mode.

-

The fast seek feature is enabled when the member cltbl in the file object is not NULL. The CLMT must be created into the DWORD array prior to use the fast seek feature. To create the CLMT, set address of the DWORD array to the member cltbl in the open file object, set the size of array in unit of items to the first item and call the f_lseek function with ofs = CREATE_LINKMAP. After the function succeeded and CLMT is created, no FAT access is occured in subsequent f_read, f_write, f_lseek function to the file. The number of items used or required is returned into the first item of the array. The number of items to be used is (number of the file fragments + 1) * 2. For example, when the file is fragmented in 5, 12 items in the array will be used. If the function failed with FR_NOT_ENOUGH_CORE, the given array size is insufficient for the file.

+

The fast seek function enables fast backward/long seek operations without FAT access by using an on-memory CLMT (cluster link map table). It is applied to f_read and f_write function as well, however, the file size cannot be expanded by f_write, f_lseek function while the file is in fast seek mode.

+

The fast seek function is enabled when the member cltbl in the file object is not NULL. The CLMT must be created into the DWORD array prior to use the fast seek function. To create the CLMT, set address of the DWORD array to the member cltbl in the open file object, set the size of array in unit of items to the first item and call the f_lseek function with ofs = CREATE_LINKMAP. After the function succeeded and CLMT is created, no FAT access is occured in subsequent f_read, f_write, f_lseek function to the file. The number of items used or required is returned into the first item of the array. The number of items to be used is (number of the file fragments + 1) * 2. For example, when the file is fragmented in 5, 12 items in the array will be used. If the function failed with FR_NOT_ENOUGH_CORE, the given array size is insufficient for the file.

QuickInfo

-

Available when _FS_MINIMIZE <= 2. To use fast seek feature, _USE_FASTSEEK needs to be set 1.

+

Available when _FS_MINIMIZE <= 2. To use fast seek function, _USE_FASTSEEK needs to be set 1.

@@ -102,7 +102,7 @@ FRESULT f_lseek ( res = f_close(fp);
-/* Using fast seek feature */
+/* Using fast seek function */
 
     DWORD clmt[SZ_TBL];                    /* Cluster link map table buffer */
 
@@ -110,7 +110,7 @@ FRESULT f_lseek (
 
     res = f_lseek(fp, ofs1);               /* This is normal seek (cltbl is nulled on file open) */
 
-    fp->cltbl = clmt;                      /* Enable fast seek feature (cltbl != NULL) */
+    fp->cltbl = clmt;                      /* Enable fast seek function (cltbl != NULL) */
     clmt[0] = SZ_TBL;                      /* Set table size */
     res = f_lseek(fp, CREATE_LINKMAP);     /* Create CLMT */
     ...
@@ -122,7 +122,7 @@ FRESULT f_lseek (
 
 
 
 

Return

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/mkfs.html b/firmware/chibios-portapack/ext/fatfs/doc/en/mkfs.html index 1637a0e2..52f5c3cb 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/mkfs.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/mkfs.html @@ -13,12 +13,14 @@

f_mkfs

-

The f_mkfs fucntion creates an FAT volume on the logical drive.

+

The f_mkfs fucntion creates an FAT/exFAT volume on the logical drive.

 FRESULT f_mkfs (
   const TCHAR* path,  /* [IN] Logical drive number */
-  BYTE  sfd,          /* [IN] Partitioning rule */
-  UINT  au            /* [IN] Size of the allocation unit */
+  BYTE  opt,          /* [IN] Format options */
+  DWORD au,           /* [IN] Size of the allocation unit */
+  void* work,         /* [-]  Working buffer */
+  UINT len            /* [IN] Size of working buffer */
 );
 
@@ -27,11 +29,15 @@ FRESULT f_mkfs (

Parameters

path
-
Pointer to the null-terminated string that specifies the logical drive to be formatted. If there is no drive number, it means the default drive.
-
sfd
-
Specifies partitioning rule (FDISK(0) or SFD(1)). This argument will be ignored on some case.
+
Pointer to the null-terminated string specifies the logical drive to be formatted. If there is no drive number in it, it means the default drive. The logical drive does not need to be mounted.
+
opt
+
Specifies the format option in combination of FM_FAT, FM_FAT32, FM_EXFAT and bitwise-or of these three, FM_ANY. FM_EXFAT is ignored when exFAT is not enabled. These flags specify which FAT type to be created on the volume. If two or more types are specified, one out of them will be selected depends on the volume size. The flag FM_SFD specifies to place the volume on the drive in SFD format.
au
-
Specifies size of the allocation unit (cluter) in number of bytes or sectors. When the value is from 1 to 128, it specifies number of sectors. When the value is >= _MIN_SS, it specifies number of bytes. If any invalid value, zero or not power of 2, is given, the cluster size is automatically determined depends on the volume size.
+
Specifies size of the allocation unit (cluter) in unit of byte. The valid value is N times the sector size. N is power of 2 from 1 to 128 for FAT volume and upto 16MiB for exFAT volume. If zero is given, the default allocation unit size is selected depends on the volume size.
+
work
+
Pointer to the working buffer for the format process.
+
len
+
Size of the working buffer in unit of byte. It needs to be the sector size at least. Plenty of working buffer reduces number of write transaction to the device and the format process will be finished quickly.
@@ -43,7 +49,6 @@ FRESULT f_mkfs ( FR_NOT_READY, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, -FR_NOT_ENABLED, FR_MKFS_ABORTED, FR_INVALID_PARAMETER

@@ -51,11 +56,11 @@ FRESULT f_mkfs (

Description

-

The f_mkfs function creates an FAT volume on the specified logical drive. When FDISK format is specified, a primary partition occupies entire space of the physical drive is created and then an FAT volume is created on the partition. When SFD format is specified, the FAT volume starts from the first sector of the physical drive.

-

If the logical drive is bound to the specific partition (1-4) by multiple partition feature (_MULTI_PARTITION), the FAT volume is created into the partition. In this case, the second argument sfd is ignored. The physical drive must have been partitioned with f_fdisk function or any other partitioning tools prior to create the FAT volume with this function.

-

Note that there are two partitioning rules, FDISK and SFD. The FDISK partitioning is usually used for harddisk, MMC, SDC, CFC and U Disk. It can divide a physical drive into one or more partitions with a partition table on the MBR. However Windows does not support multiple partition on the removable disk. The SFD is non-partitioned method. The FAT volume starts from the first sector on the physical drive without partition table. It is usually used for floppy disk, Microdrive, optical disk and any type of super-floppy media.

-

The FAT sub-type, FAT12/FAT16/FAT32, is determined by number of clusters on the volume and nothing else, according to the FAT specification issued by Microsoft. Thus which FAT sub-type is selected, is depends on the volume size and the specified cluster size. The cluster size affects read/write throughput and space usage efficiency. Larger cluster size increases the read/write throughput and decreases the space usage efficiency of the volume.

-

In case of the number of clusters gets near the FAT sub-type boundaries, the function can fail with FR_MKFS_ABORTED.

+

The FAT sub-type, FAT12/FAT16/FAT32, of FAT volume except exFAT is determined by only number of clusters on the volume and nothing else, according to the FAT specification issued by Microsoft. Thus which FAT sub-type is selected, is depends on the volume size and the specified cluster size. In case of the combination of FAT type and cluter size specified by argument cannot be valid on the volume, the function will fail with FR_MKFS_ABORTED.

+

The allocation unit, also called 'cluster', is a unit of disk space allocation for files. When the size of allocation unit is 32768 bytes, a file with 100 bytes in size occupies 32768 bytes of disk space. The space efficiency of disk usage gets worse as increasing size of allocation unit, but, on the other hand, the read/write performance increases as the size of allocation unit. Therefore the allocation unit is a trade-off between space efficiency and performance. For the large storages in GB order, 32768 bytes or larger cluster (this is automatically selected by default) is recommended for most case unless extremely many files are created on a volume.

+

There are two disk formats, FDISK and SFD. The FDISK format is usually used for harddisk, MMC, SDC, CFC and U Disk. It can divide a physical drive into one or more partitions with a partition table on the MBR (maser boot record, the first sector of the physical drive). The SFD (super-floppy disk) is non-partitioned disk format. The FAT volume starts at the first sector of the physical drive without any disk partitioning. It is usually used for floppy disk, Microdrive, optical disk and most type of super-floppy media. Some systems support only either one of two formats and other is not supported.

+

When FM_SFD is not specified, a primary partition occupies whole drive space is created and then the FAT volume is created in it. When FM_SFD is specified, the FAT volume occupies from the first sector of the drive is created.

+

If the logical drive to be formatted is bound to the specific partition (1-4) by support of multiple partition, _MULTI_PARTITION, the FAT volume is created into the partition and FM_SFD flag is ignored. The physical drive needs to be partitioned with f_fdisk function or any other partitioning tools prior to create the FAT volume with this function.

@@ -69,19 +74,20 @@ FRESULT f_mkfs ( /* Format default drive and create a file */ int main (void) { - FATFS fs; /* File system object (volume work area) */ - FIL fil; /* File object */ - FRESULT res; /* API result code */ - UINT bw; /* Bytes written */ + FATFS fs; /* File system object */ + FIL fil; /* File object */ + FRESULT res; /* API result code */ + UINT bw; /* Bytes written */ + BYTE work[_MAX_SS]; /* Work area (larger is better for process time) */ - /* Register work area (do not care about error) */ - f_mount(&fs, "", 0); - - /* Create FAT volume with default cluster size */ - res = f_mkfs("", 0, 0); + /* Create FAT volume */ + res = f_mkfs("", FM_ANY, 0, work, sizeof work); if (res) ... + /* Register work area */ + f_mount(&fs, "", 0); + /* Create a file as new */ res = f_open(&fil, "hello.txt", FA_CREATE_NEW | FA_WRITE); if (res) ... @@ -95,12 +101,14 @@ int main (void) /* Unregister work area */ f_mount(0, "", 0); + + ...

See Also

-

Volume management, f_fdisk

+

Example of volume size and format parameters, Volume management, f_fdisk

Return

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/mount.html b/firmware/chibios-portapack/ext/fatfs/doc/en/mount.html index 5ab9a1f2..f7176327 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/mount.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/mount.html @@ -31,7 +31,7 @@ FRESULT f_mount (
path
Pointer to the null-terminated string that specifies the logical drive. The string without drive number means the default drive.
opt
-
Initialization option. 0: Do not mount now (to be mounted later), 1: Force mounted the volume to check if the FAT volume is ready to work.
+
Initialization option. 0: Do not mount now (to be mounted later), 1: Force mounted the volume to check if the volume is ready to work.
@@ -49,15 +49,15 @@ FRESULT f_mount (

Description

-

The f_mount function registers/unregisters a file system object used for the logical drive to the FatFs module as follows:

+

The f_mount function registers/unregisters a file system object used for the volume (logical drive) to the FatFs module as follows:

  1. Determines the logical drive which specified by path.
  2. -
  3. Clears and unregisters the regsitered work area of the drive.
  4. +
  5. Clears and unregisters the regsitered work area of the drive if exist.
  6. Clears and registers the new work area to the drive if fs is not NULL.
  7. Performs volume mount process to the drive if forced mount is specified.

The file system object is the work area needed for each logical drive. It must be given to the logical drive with this function prior to use any other file functions except for f_fdisk function to the logical drive. To unregister the work area, specify a NULL to the fs, and then the work area can be discarded.

-

If forced mounting is not specified, this function always succeeds regardless of the physical drive status due to delayed mount feature. It only clears (de-initializes) the given work area and registers its address to the internal table. No activity of the physical drive in this function. It can also be used to force de-initialized the registered work area of a logical drive. The volume mount processes, initialize the corresponding physical drive, find the FAT volume in it and initialize the work area, is performed in the subsequent file access functions when either or both of following condition is true.

+

If forced mounting is not specified, this function always succeeds regardless of the physical drive status due to delayed mount feature. It only clears (de-initializes) the given work area and registers its address to the internal table. There is no activity of the physical drive in this function. It can also be used to force de-initialized the registered work area of a logical drive. The volume mount processes, initialize the corresponding physical drive, find the FAT volume in it and initialize the work area, is performed in the subsequent file access functions when either or both of following condition is true.

@@ -53,7 +53,7 @@ FRESULT f_read (

Description

-

The file read/write pointer of the file object advances number of bytes read. After the function succeeded, *br should be checked to detect end of the file. In case of *br is less than btr, it means the read/write pointer reached end of the file during read operation.

+

The function starts to read data from the file at the position pointed by the read/write pointer. The read/write pointer advances as number of bytes read. After the function succeeded, *br should be checked to detect end of the file. In case of *br is less than btr, it means the read/write pointer reached end of the file during read operation.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/readdir.html b/firmware/chibios-portapack/ext/fatfs/doc/en/readdir.html index 2cb12107..235beee7 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/readdir.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/readdir.html @@ -13,7 +13,7 @@

f_readdir

-

The f_readdir function reads directory entries.

+

The f_readdir function reads an item of the directory.

 FRESULT f_readdir (
   DIR* dp,      /* [IN] Directory object */
@@ -26,9 +26,9 @@ FRESULT f_readdir (
 

Parameters

dp
-
Pointer to the directory object created by f_opendir function.
+
Pointer to the open directory object or null pointer.
fno
-
Pointer to the file information structure to store the information about read item.
+
Pointer to the file information structure to store the information about read item.
@@ -48,13 +48,14 @@ FRESULT f_readdir (

Description

-

The f_readdir function reads directory items, informations about file and directory, in sequence. All items in the directory can be read by calling f_readdir function repeatedly. When relative path feature is enabled (_FS_RPATH >= 1), dot entries ("." and "..") are not filtered out and they will appear in the read items. When all directory items have been read and no item to read, a null string is stored into the fno->fname[] without any error. When a null pointer is given to the fno, the read index of the directory object is rewinded.

-

When LFN feature is enabled, fno->lfname and fno->lfsize in the file information structure must be initialized with valid value prior to use it. The lfname points the LFN read buffer. The lfsize is size of the LFN read buffer in unit of TCHAR. If the LFN is not needed, set a null pointer to the lfname and the LFN is not returned. A null string will be returned into the LFN read buffer in case of following conditions.

+

The f_readdir function reads a directory item, informations about the object. All items in the directory can be read in sequence by f_readdir function calls. Dot entries ("." and "..") in the sub-directory are filtered out and they will never appear in the read items. When all directory items have been read and no item to read, a nul string is stored into the fno->fname[] without any error. When a null pointer is given to the fno, the read index of the directory object is rewinded.

+

When support of long file name (LFN) is enabled, a member altname[] is defined in the file information structure to store the short file name of the object. In case of the some conditions listed below, short file name is stored into the fname[] and altname[] has a null string.

+

There is a problem on reading a directory of exFAT volume. The exFAT does not support short file name. This means no name can be returned on the condition above. If it is the case, a "?" is returned as file name to indicate that the object is not accessible. To avoid this problem, configure FatFs _LFN_UNICODE = 1 and _MAX_LFN = 255 to support the full feature of LFN specification.

@@ -68,40 +69,28 @@ FRESULT f_readdir (

Sample Code

 FRESULT scan_files (
-    char* path        /* Start node to be scanned (also used as work area) */
+    char* path        /* Start node to be scanned (***also used as work area***) */
 )
 {
     FRESULT res;
-    FILINFO fno;
     DIR dir;
-    int i;
-    char *fn;   /* This function assumes non-Unicode configuration */
-#if _USE_LFN
-    static char lfn[_MAX_LFN + 1];   /* Buffer to store the LFN */
-    fno.lfname = lfn;
-    fno.lfsize = sizeof lfn;
-#endif
+    UINT i;
+    static FILINFO fno;
 
 
     res = f_opendir(&dir, path);                       /* Open the directory */
     if (res == FR_OK) {
-        i = strlen(path);
         for (;;) {
             res = f_readdir(&dir, &fno);                   /* Read a directory item */
             if (res != FR_OK || fno.fname[0] == 0) break;  /* Break on error or end of dir */
-            if (fno.fname[0] == '.') continue;             /* Ignore dot entry */
-#if _USE_LFN
-            fn = *fno.lfname ? fno.lfname : fno.fname;
-#else
-            fn = fno.fname;
-#endif
             if (fno.fattrib & AM_DIR) {                    /* It is a directory */
-                sprintf(&path[i], "/%s", fn);
-                res = scan_files(path);
-                path[i] = 0;
+                i = strlen(path);
+                sprintf(&path[i], "/%s", fno.fname);
+                res = scan_files(path);                    /* Enter the directory */
                 if (res != FR_OK) break;
+                path[i] = 0;
             } else {                                       /* It is a file. */
-                printf("%s/%s\n", path, fn);
+                printf("%s/%s\n", path, fno.fname);
             }
         }
         f_closedir(&dir)
@@ -109,6 +98,23 @@ FRESULT scan_files (
 
     return res;
 }
+
+
+int main (void)
+{
+    FATFS fs;
+    FRESULT res;
+    char buff[256];
+
+
+    res = f_mount(&fs, "", 1);
+    if (res == FR_OK) {
+        strcpy(buff, "/");
+        res = scan_files(buff);
+    }
+
+    return res;
+}
 
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/sdir.html b/firmware/chibios-portapack/ext/fatfs/doc/en/sdir.html index 27b205f5..a01a7166 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/sdir.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/sdir.html @@ -16,20 +16,15 @@

The DIR structure is used for the work area to read a directory by f_oepndir, f_readdir, f_findfirst and f_findnext function. Application program must not modify any member in this structure, or any data on the FAT volume can be collapsed.

 typedef struct {
-    FATFS*  fs;         /* Pointer to the owner file system object */
-    WORD    id;         /* Owner file system mount ID */
-    WORD    index;      /* Index of directory entry to start to search next */
-    DWORD   sclust;     /* Table start cluster (0:Root directory) */
+    _FDID   obj;        /* Owner file sytem object and object identifier */
+    DWORD   dptr;       /* Current read/write offset */
     DWORD   clust;      /* Current cluster */
     DWORD   sect;       /* Current sector */
     BYTE*   dir;        /* Pointer to the current SFN entry in the win[] */
     BYTE*   fn;         /* Pointer to the SFN buffer (in/out) {file[8],ext[3],status[1]} */
-#if _FS_LOCK
-    UINT    lockid;     /* Sub-directory lock ID (0:Root directory) */
-#endif
 #if _USE_LFN
-    WCHAR*  lfn;        /* Pointer to the LFN buffer (in/out) */
-    WORD    lfn_idx;    /* Index of the LFN entris (0xFFFF:No LFN) */
+    DWORD   blk_ofs;    /* Offset of the entry block (0xFFFFFFFF:Invalid) */
+    WCHAR*  lfn;        /* Pointer to the LFN working buffer (in/out) */
 #endif
 #if _USE_FIND
     const TCHAR*  pat;  /* Ponter to the matching pattern */
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/setlabel.html b/firmware/chibios-portapack/ext/fatfs/doc/en/setlabel.html
index e76a285d..f7a8b0eb 100644
--- a/firmware/chibios-portapack/ext/fatfs/doc/en/setlabel.html
+++ b/firmware/chibios-portapack/ext/fatfs/doc/en/setlabel.html
@@ -49,13 +49,14 @@ FRESULT f_setlabel (
 
 

Description

-

When the string has a drive number, the volume label will be set to the volume specified by the drive number. If not, the volume label will be set to the default drive. If length of the given volume label is zero, the volume label on the volume will be removed. The format of the volume label is similar to the short file name but there are some differences shown below:

+

When the string has a drive number, the volume label will be set to the volume specified by the drive number. If not, the volume label will be set to the default drive. If length of the given volume label is zero, the volume label on the volume will be removed. The format of the volume label on the FAT volume is similar to the file name but there are some differences shown below:

    -
  • 11 bytes or less in length as conversion into OEM code page. LFN feature is not applied to the volume label.
  • -
  • Cannot contain period.
  • -
  • Can contain spaces anywhere in it. Trailing spaces are truncated off.
  • +
  • Spaces can be contained anywhere in the volume label. Trailing spaces are truncated off at FAT volume.
  • +
  • Period is not allowed.
  • +
  • Up to 11 bytes long as conversion of OEM code page at FAT volume.
  • +
  • Up to 11 characters long at exFAT volume. Case information is preserved.
-

Remark: The standard system (Windows) has a problem on handling of the volume label with a heading \xE5. To avoid this problem, this function rejects such volume labels as invalid name.

+

Remark: The standard system (Windows) has a problem at handling of the volume label with a heading \xE5 on the FAT volume. To avoid this problem, this function rejects such volume label as invalid name.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/sfatfs.html b/firmware/chibios-portapack/ext/fatfs/doc/en/sfatfs.html index b4c9b71f..e701f441 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/sfatfs.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/sfatfs.html @@ -16,17 +16,20 @@

The FATFS structure (file system object) holds dynamic work area of individual logical drives. It is given by application program and registerd/unregisterd to the FatFs module with f_mount function. Initialization is done on first API call after f_mount function or media change. Application program must not modify any member in this structure, or any data on the FAT volume can be collapsed.

 typedef struct {
-    BYTE    fs_type;      /* FAT sub-type (0:Not mounted, FS_FAT12/FS_FAT16/FS_FAT32) */
+    BYTE    fs_type;      /* File system type (0, FS_FAT12, FS_FAT16, FS_FAT32 or FS_EXFAT) */
     BYTE    drv;          /* Physical drive number */
-    BYTE    csize;        /* Sectors per cluster (1,2,4,...,128) */
     BYTE    n_fats;       /* Number of FAT copies (1,2) */
     BYTE    wflag;        /* win[] flag (b0:win[] is dirty) */
     BYTE    fsi_flag;     /* FSINFO flags (b7:Disabled, b0:Dirty) */
     WORD    id;           /* File system mount ID */
     WORD    n_rootdir;    /* Number of root directory entries (FAT12/16) */
+    WORD    csize;        /* Sectors per cluster */
 #if _MAX_SS != _MIN_SS
     WORD    ssize;        /* Sector size (512,1024,2048 or 4096) */
 #endif
+#if _FS_EXFAT
+    BYTE*   dirbuf;       /* Directory entry block scratchpad buffer */
+#endif
 #if _FS_REENTRANT
     _SYNC_t sobj;         /* Identifier of sync object */
 #endif
@@ -36,6 +39,11 @@
 #endif
 #if _FS_RPATH
     DWORD   cdir;         /* Cluster number of current directory (0:root) */
+#if _FS_EXFAT
+    DWORD   cdc_scl;      /* Containing directory start cluster (invalid when cdir is 0) */
+    DWORD   cdc_size;     /* b31-b8:Size of containing directory, b7-b0: Chain status */
+    DWORD   cdc_ofs;      /* Offset in the containing directory (invalid when cdir is 0) */
+#endif
 #endif
     DWORD   n_fatent;     /* Number of FAT entries (Number of clusters + 2) */
     DWORD   fsize;        /* Sectors per FAT */
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/sfile.html b/firmware/chibios-portapack/ext/fatfs/doc/en/sfile.html
index ee62071f..5e53d167 100644
--- a/firmware/chibios-portapack/ext/fatfs/doc/en/sfile.html
+++ b/firmware/chibios-portapack/ext/fatfs/doc/en/sfile.html
@@ -17,15 +17,12 @@
 
 
 typedef struct {
-    FATFS*  fs;           /* Pointer to the owner file system object */
-    WORD    id;           /* Owner file system mount ID */
+    _FDID   obj;          /* Owner file sytem object and object identifier */
     BYTE    flag;         /* File object status flags */
     BYTE    err;          /* Abort flag (error code) */
-    DWORD   fptr;         /* File read/write pointer (Byte offset origin from top of the file) */
-    DWORD   fsize;        /* File size in unit of byte */
-    DWORD   sclust;       /* File start cluster */
+    FSIZE_t fptr;         /* File read/write pointer (Byte offset origin from top of the file) */
     DWORD   clust;        /* Current cluster of fptr (One cluster behind if fptr is on the cluster boundary. Invalid if fptr == 0.) */
-    DWORD   dsect;        /* Current data sector (Can be invalid if fptr is on the cluster boundary.)*/
+    DWORD   sect;         /* Current data sector (Can be invalid if fptr is on the cluster boundary.)*/
 #if !_FS_READONLY
     DWORD   dir_sect;     /* Sector number containing the directory entry */
     BYTE*   dir_ptr;      /* Ponter to the directory entry in the window */
@@ -33,9 +30,6 @@
 #if _USE_FASTSEEK
     DWORD*  cltbl;        /* Pointer to the cluster link map table (Nulled on file open. Set by application.) */
 #endif
-#if _FS_LOCK
-    UINT    lockid;       /* Fle lock ID */
-#endif
 #if !_FS_TINY
     BYTE    buf[_MAX_SS]; /* File private data transfer buffer (Always valid if fptr is not on the sector boundary but can be invalid if fptr is on the sector boundary.) */
 #endif
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/sfileinfo.html b/firmware/chibios-portapack/ext/fatfs/doc/en/sfileinfo.html
index 70e20e4e..268b8c14 100644
--- a/firmware/chibios-portapack/ext/fatfs/doc/en/sfileinfo.html
+++ b/firmware/chibios-portapack/ext/fatfs/doc/en/sfileinfo.html
@@ -16,14 +16,15 @@
 

The FILINFO structure holds information about the object returned by f_readdir, f_findfirst, f_findnext and f_stat function.

 typedef struct {
-    DWORD fsize;      /* File size */
-    WORD  fdate;      /* Last modified date */
-    WORD  ftime;      /* Last modified time */
-    BYTE  fattrib;    /* Attribute */
-    TCHAR fname[13];  /* Short file name (8.3 format) */
-#if _USE_LFN
-    TCHAR* lfname;    /* Pointer to the LFN buffer */
-    int   lfsize;     /* Size of the LFN buffer in unit of TCHAR */
+    FSIZE_t fsize;               /* File size */
+    WORD    fdate;               /* Last modified date */
+    WORD    ftime;               /* Last modified time */
+    BYTE    fattrib;             /* Attribute */
+#if _USE_LFN != 0
+    TCHAR   altname[13];         /* Alternative object name */
+    TCHAR   fname[_MAX_LFN + 1]; /* Primary object name */
+#else
+    TCHAR   fname[13];           /* Object name */
 #endif
 } FILINFO;
 
@@ -32,9 +33,9 @@

Members

fsize
-
Indicates size of the file in unit of byte. Always zero for directories.
+
Indicates size of the file in unit of byte. Always zero for directories. FSIZE_t is an alias of integer type either DWORD(32-bit) or QWORD(64-bit) depends on the configuration option _FS_EXFAT.
fdate
-
Indicates the date that the file was modified or the directory was created.
+
Indicates the date when the file was modified or the directory was created.
bit15:9
Year origin from 1980 (0..127)
@@ -45,7 +46,7 @@
ftime
-
Indicates the time that the file was modified or the directory was created.
+
Indicates the time when the file was modified or the directory was created.
bit15:11
Hour (0..23)
@@ -58,11 +59,9 @@
fattrib
Indicates the file/directory attribute in combination of AM_DIR, AM_RDO, AM_HID, AM_SYS and AM_ARC.
fname[]
-
The object name in 8.3 format (SFN) null-terminated string is stored. It is always upper case at non-LFN configuration but it can be returned with lower case at LFN configuration. A null string is stored when no item to read and this structure is invalid.
-
lfname
-
Pointer to the string buffer to store the long file name (LFN). This member must be initialized by application program prior to use this structure. Set a null pointer if LFN is not needed. Not available at non-LFN configuration.
-
lfsize
-
Size of the LFN buffer in unit of TCHAR. This member must be initialized by application program prior to use this structure. Not available at non-LFN configuration.
+
The null-terminated object name is stored. A null string is stored when no item to read and it indicates this structure is invalid.
+
altname[]
+
Alternative object name is stored if available. This member is not available at non-LFN configuration.

Return

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/size.html b/firmware/chibios-portapack/ext/fatfs/doc/en/size.html index a25a32cc..08990c61 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/size.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/size.html @@ -15,7 +15,7 @@

f_size

The f_size function gets the size of a file.

-DWORD f_size (
+FSIZE_t f_size (
   FIL* fp   /* [IN] File object */
 );
 
@@ -39,9 +39,9 @@ DWORD f_size (

Description

-

In this revision, the f_size function is implemented as a macro. It has not any validation and mutual exclusion.

+

In this revision, the f_size function is implemented as a macro. It does not have any validation and mutual exclusion.

-#define f_size(fp) ((fp)->fsize)
+#define f_size(fp) ((fp)->obj.objsize)
 
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/stat.html b/firmware/chibios-portapack/ext/fatfs/doc/en/stat.html index 5651c956..2924660e 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/stat.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/stat.html @@ -54,8 +54,7 @@ FRESULT f_stat (

Description

-

The f_stat function checks the existence of a file or sub-directory. If not exist, the function returns with FR_NO_FILE. If exist, the function returns with FR_OK and the informations of the object, file size, timestamp, attribute and SFN, are stored to the file information structure. For details of the file information, refer to the FILINFO structure and f_readdir function.

-

When LFN feature is enabled, lfname in the file information structure must be NULLed prior to use it.

+

The f_stat function checks the existence of a file or sub-directory. If not exist, the function returns with FR_NO_FILE. If exist, the function returns with FR_OK and the informations of the object, file size, timestamp and attribute, are stored to the file information structure. For details of the file information, refer to the FILINFO structure and f_readdir function.

@@ -74,23 +73,20 @@ FRESULT f_stat ( printf("Test for 'file.txt'...\n"); -#if _USE_LFN - fno.lfname = 0; -#endif fr = f_stat("file.txt", &fno); switch (fr) { case FR_OK: - printf("Size: %u\n", fno.fsize); + printf("Size: %lu\n", fno.fsize); printf("Timestamp: %u/%02u/%02u, %02u:%02u\n", (fno.fdate >> 9) + 1980, fno.fdate >> 5 & 15, fno.fdate & 31, fno.ftime >> 11, fno.ftime >> 5 & 63); printf("Attributes: %c%c%c%c%c\n", - (fno.fattrib & AM_DIR) ? 'D' : '-', - (fno.fattrib & AM_RDO) ? 'R' : '-', - (fno.fattrib & AM_HID) ? 'H' : '-', - (fno.fattrib & AM_SYS) ? 'S' : '-', - (fno.fattrib & AM_ARC) ? 'A' : '-'); + (fno.fattrib & AM_DIR) ? 'D' : '-', + (fno.fattrib & AM_RDO) ? 'R' : '-', + (fno.fattrib & AM_HID) ? 'H' : '-', + (fno.fattrib & AM_SYS) ? 'S' : '-', + (fno.fattrib & AM_ARC) ? 'A' : '-'); break; case FR_NO_FILE: diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/tell.html b/firmware/chibios-portapack/ext/fatfs/doc/en/tell.html index 49a2c578..7e0673cf 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/tell.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/tell.html @@ -15,7 +15,7 @@

f_tell

The f_tell function gets the current read/write pointer of a file.

-DWORD f_tell (
+FSIZE_t f_tell (
   FIL* fp   /* [IN] File object */
 );
 
@@ -39,7 +39,7 @@ DWORD f_tell (

Description

-

In this revision, the f_tell function is implemented as a macro. It has not any validation and mutual exclusion.

+

In this revision, the f_tell function is implemented as a macro. It does not have any validation and mutual exclusion.

 #define f_tell(fp) ((fp)->fptr)
 
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/truncate.html b/firmware/chibios-portapack/ext/fatfs/doc/en/truncate.html index 9be17b12..d0079d70 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/truncate.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/truncate.html @@ -36,6 +36,7 @@ FRESULT f_truncate ( FR_OK, FR_DISK_ERR, FR_INT_ERR, +FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/unlink.html b/firmware/chibios-portapack/ext/fatfs/doc/en/unlink.html index 34db349a..4cd1f660 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/unlink.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/unlink.html @@ -59,7 +59,7 @@ FRESULT f_unlink ( If condition of the object to be removed is applicable to the following terms, the function will be rejected.
  • The file/sub-directory must not have read-only attribute (AM_RDO), or the function will be rejected with FR_DENIED.
  • The sub-directory must be empty and must not be current directory, or the function will be rejected with FR_DENIED.
  • -
  • The file/sub-directory must not be opened, or the FAT volume can be collapsed. It will be rejected safely when file lock feature is enabled.
  • +
  • The file/sub-directory must not be opened, or the FAT volume can be collapsed. It will be rejected safely when file lock function is enabled.
diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/utime.html b/firmware/chibios-portapack/ext/fatfs/doc/en/utime.html index ac646e38..6b7f291e 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/utime.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/utime.html @@ -85,7 +85,7 @@ FRESULT set_timestamp (

QuickInfo

-

Available when _FS_READONLY == 0 and _FS_MINIMIZE == 0.

+

Available when _FS_READONLY == 0 and _USE_CHMOD == 1.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/en/write.html b/firmware/chibios-portapack/ext/fatfs/doc/en/write.html index 5bcd5a79..644dd6df 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/en/write.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/en/write.html @@ -34,7 +34,7 @@ FRESULT f_write (
btw
Specifies number of bytes to write in range of UINT type.
bw
-
Pointer to the UINT variable to return the number of bytes written. The value is always valid after the function call regardless of the result.
+
Pointer to the UINT variable to return the number of bytes written. The value is always valid after the function call regardless of the result code.
@@ -53,7 +53,7 @@ FRESULT f_write (

Description

-

The read/write pointer of the file object advances number of bytes written. After the function succeeded, *bw should be checked to detect the disk full. In case of *bw is less than btw, it means the volume got full during the write operation. The function can take a time when the volume is full or close to full.

+

The function starts to write data to the file at the position pointed by the read/write pointer. The read/write pointer advances as number of bytes written. After the function succeeded, *bw should be checked to detect the disk full. In case of *bw is less than btw, it means the volume got full during the write operation. The function can take a time when the volume is full or close to full.

diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f7.png b/firmware/chibios-portapack/ext/fatfs/doc/img/f7.png deleted file mode 100644 index 392e8b8924b078c69424bdbc1ba6a8aa5f173a9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11388 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 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/funcs.png b/firmware/chibios-portapack/ext/fatfs/doc/img/funcs.png deleted file mode 100644 index 81105d711ebbe5f8e2624d916081779e2b517002..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19491 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 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/modules.png b/firmware/chibios-portapack/ext/fatfs/doc/img/modules.png deleted file mode 100644 index ef4c78cb304aabcf2b96b8c227c7b357026d0254..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7932 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 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/rwtest.png b/firmware/chibios-portapack/ext/fatfs/doc/img/rwtest.png deleted file mode 100644 index a34bf06212fb214689ab3e6600041c9c7751713f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19068 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 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/appnote.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/appnote.html index fdc69a9f..b716ebd3 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/appnote.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/appnote.html @@ -17,6 +17,7 @@
  • メモリ使用量
  • モジュール サイズの縮小
  • 長いファイル名
  • +
  • exFATファイルシステム
  • Unicode入出力への対応
  • リエントランシー
  • 多重ファイル アクセス
  • @@ -41,9 +42,9 @@ FatFsモジュールはANSI C(C89)準拠で記述されているので、普通

    システム構成

    下に示す依存関係図は、FatFsモジュール利用の組み込みシステムにおける代表的な構成を示します。

    -

    システム構成図

    +

    システム構成図

    (a) FatFs用に書かれたディスク モジュールがある場合は、そのまま追加するだけです。 (b) しかし、多くの既存のディスク モジュールはそのAPIをFatFsに合わせるため、グルー関数が必要になるでしょう。

    -

    functional diagram

    +

    functional diagram

    ユーザの作成する関数

    ポーティング作業は、要求されるデバイス制御関数を用意することが全てで、それ以外にすることは何もありません。既に動作しているデバイス制御モジュールがあるなら、そのAPIをFatFsに合わせるかグルー関数を介してつなぐだけで済みますが、無い場合はほかから移植するか最初から書くかする必要があります。定義されている全ての関数が常に必要なわけではありません。例えば、リード オンリ構成では書き込み系関数は必要ありません。次の表に構成オプションと要求される関数の対応を示します。

    @@ -63,13 +64,13 @@ FatFsモジュールはANSI C(C89)準拠で記述されているので、普通

    限界値

      -
    • FATタイプ: FAT12, FAT16, FAT32。
    • +
    • ファイルシステム: FAT12, FAT16, FAT32(r0.0) および exFAT(r1.0)。
    • 同時オープン ファイル数: 無制限。(利用可能メモリによる)
    • 同時マウント ボリューム数: 最大 10。
    • -
    • ファイル サイズ: 最大 4G-1バイト。
    • -
    • ボリューム サイズ: 最大 2Tバイト(512バイト/セクタ時)。
    • -
    • クラスタ サイズ: 最大 64Kバイト(512バイト/セクタ時)。
    • -
    • セクタ サイズ: 512, 1024, 2048, 4096バイト。
    • +
    • ファイル サイズ: 最大 4GiB - 1 (FATボリューム) および、事実上無制限(exFATボリューム)。
    • +
    • ボリューム サイズ: 最大 2TiB (512B/セクタ時)。
    • +
    • クラスタ サイズ: 最大 128セクタ (FATボリューム) および、最大 16MiB (exFATボリューム)。
    • +
    • セクタ サイズ: 512B, 1KiB, 2KiB, 4KiB。
    @@ -78,70 +79,72 @@ FatFsモジュールはANSI C(C89)準拠で記述されているので、普通

    次の表にいくつかのターゲットにおけるメモリ使用量の例を示します。テスト時の構成オプションはその下の通りです。数値の単位はバイトで、Vはボリューム数、Fは同時オープン ファイル数を示します。コンパイラの最適化オプションはコード サイズとしています。

    - - - - - - - - - - + + + + + + + + +
    ARM7
    32bit
    ARM7
    Thumb
    CM3
    Thumb-2
    AVRH8/300HPIC24RL78V850ESSH-2ARX600IA-32
    CompilerGCCGCCGCCGCCCH38C30CC78K0RCA850SHCRXCVC6
    _WORD_ACCESS00010001011
    text (Full, R/W)10.6k7.1k6.5k13.3k10.9k11.7k13.3k8.1k9.0k6.0k7.9k
    text (Min, R/W) 6.7k4.6k4.2k 8.6k 7.3k 7.7k 9.1k5.3k5.8k3.9k5.2k
    text (Full, R/O) 4.8k3.2k2.9k 6.2k 5.2k 5.5k 6.5k3.8k4.0k2.9k3.7k
    text (Min, R/O) 3.6k2.5k2.3k 4.6k 4.1k 4.3k 5.0k3.0k3.1k2.2k2.9k
    bssV*4 + 2V*4 + 2V*4 + 2V*2 + 2V*4 + 2V*2 + 2V*2 + 2V*4 + 2V*4 + 2V*4 + 2V*4 + 2
    Work area
    (_FS_TINY == 0)
    V*560
    + F*550
    V*560
    + F*550
    V*560
    + F*550
    V*560
    + F*544
    V*560
    + F*550
    V*560
    + F*544
    V*560
    + F*544
    V*560
    + F*544
    V*560
    + F*550
    V*560
    + F*550
    V*560
    + F*550
    Work area
    (_FS_TINY == 1)
    V*560
    + F*36
    V*560
    + F*36
    V*560
    + F*36
    V*560
    + F*32
    V*560
    + F*36
    V*560
    + F*32
    V*560
    + F*32
    V*560
    + F*36
    V*560
    + F*36
    V*560
    + F*36
    V*560
    + F*36
    CompilerGCCGCCGCCGCCCH38C30CC78K0RCA850SHCRXCMSC
    text (Full, R/W)10.1k6.6k6.2k12.1k10.5k11.2k12.6k8.5k8.7k6.3k8.4k
    text (Min, R/W) 6.6k4.5k4.2k 7.9k 7.0k 7.6k 8.8k5.9k5.8k4.3k5.8k
    text (Full, R/O) 4.8k3.1k2.9k 5.8k 5.1k 5.5k 6.4k4.1k4.0k3.1k4.0k
    text (Min, R/O) 3.5k2.4k2.3k 4.4k 3.9k 4.2k 5.0k3.3k3.1k2.4k3.1k
    bssV*4 + 2V*4 + 2V*4 + 2V*2 + 2V*4 + 2V*2 + 2V*2 + 2V*4 + 2V*4 + 2V*4 + 2V*4 + 2
    Work area
    (_FS_TINY == 0)
    V*564
    + F*552
    V*564
    + F*552
    V*564
    + F*552
    V*560
    + F*546
    V*560
    + F*546
    V*560
    + F*546
    V*560
    + F*546
    V*564
    + F*552
    V*564
    + F*552
    V*564
    + F*552
    V*564
    + F*552
    Work area
    (_FS_TINY == 1)
    V*564
    + F*40
    V*564
    + F*40
    V*564
    + F*40
    V*560
    + F*34
    V*560
    + F*34
    V*560
    + F*34
    V*560
    + F*34
    V*564
    + F*40
    V*564
    + F*40
    V*564
    + F*40
    V*564
    + F*40
    -FatFs R0.11 options:
    +FatFs R0.12 options:
     _FS_READONLY   0 (R/W) or 1 (R/O)
    -_FS_MINIMIZE   0 (Full basic function) or 3 (Minimized function)
    -_VOLUMES       V (Number of logical drives to be used)
    -_WORD_ACCESS   0 or 1 (Set by processor architecture)
    -(Any other options are left not changed from default setting)
    +_FS_MINIMIZE   0 (Full, with all basic functions) or 3 (Min, with fully minimized)
    +_FS_TINY       0 (Default) or 1 (Tiny file object)
    +And any other options are left not changed from default setting.
     

    モジュール サイズの縮小

    -

    次の表は構成オプションの設定値によりどの機能が削除されるかを示します。使用するAPI関数の行にxが無ければその関数は使用可能です。

    +

    次の表は構成オプションの設定値によりどの機能が削除されるかを示します。API関数の行にxが無ければその関数は使用可能です。

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Function_FS_MINIMIZE_FS_READONLY_USE_STRFUNC_FS_RPATH_USE_LABEL_USE_MKFS_USE_FORWARD_MULTI_PARTITION
    0123010  1/20120101010/12
    f_mount
    f_open
    f_close
    f_read
    f_writex
    f_syncx
    f_lseekx
    f_opendirxx
    f_closedirxx
    f_readdirxx
    f_statxxx
    f_getfreexxxx
    f_truncatexxxx
    f_unlinkxxxx
    f_mkdirxxxx
    f_chmodxxxx
    f_utimexxxx
    f_renamexxxx
    f_chdirx
    f_chdrivex
    f_getcwdxx
    f_getlabelx
    f_setlabelxx
    f_forwardx
    f_mkfsxx
    f_fdiskxxx
    f_putcxx
    f_putsxx
    f_printfxx
    f_getsx
    Function_FS_
    MINIMIZE
    _FS_
    READONLY
    _USE_
    STRFUNC
    _FS_
    RPATH
    _USE_
    FIND
    _USE_
    CHMOD
    _USE_
    EXPAND
    _USE_
    LABEL
    _USE_
    MKFS
    _USE_
    FORWARD
    _MULTI_
    PARTITION
    0123010101201010101010101
    f_mount
    f_open
    f_close
    f_read
    f_write x
    f_sync x
    f_lseek x
    f_opendir xx
    f_closedir xx
    f_readdir xx
    f_findfirst xx x
    f_findnext xx x
    f_stat xxx
    f_getfree xxx x
    f_truncate xxx x
    f_unlink xxx x
    f_mkdir xxx x
    f_rename xxx x
    f_chdir x
    f_chdrive x
    f_getcwd xx
    f_chmod x x
    f_utime x x
    f_getlabel x
    f_setlabel x x
    f_expand x x
    f_forward x
    f_mkfs x x
    f_fdisk x x x
    f_putc xx
    f_puts xx
    f_printf xx
    f_gets x

    長いファイル名

    -

    FatFsモジュールは、長いファイル名(LFN)をサポートします。ファイルに付けられた2つの異なる名前(短いファル名と長いファイル名)は、f_readdir関数を除くファイル操作関数において透過です。デフォルト構成では、LFN機能はOFFになっています。LFN機能を有効にするには、_USE_LFNを1,2または3に設定し、option/unicode.cをプロジェクトに追加します。LFN機能は、加えてある程度のワーク エリア(LFN操作バッファ)を必要とします。バッファ長は使用できるメモリに応じて_MAX_LFNオプションで構成されることができます。LFNの長さは最大255文字に達するので、LFN完全対応のためには_MAX_LFNは255に設定されるべきです。与えられたファイル名に対してバッファ長が不足した場合、ファイル関数はFR_INVALID_NAMEで失敗します。

    -

    ファイル関数に再入を行う条件の下でLFN機能を使用する場合は、_USE_LFNは2または3に設定されなければなりません。この場合、ファイル関数はワーク エリアを動的に確保(スタックまたはヒープ)します。ワーク エリアのサイズは、(_MAX_LFN + 1) * 2バイトになるので、スタック等のサイズはそれを考慮した十分な余裕がなければなりません。

    +

    FatFsモジュールは、長いファイル名(LFN)をサポートします。ファイルに付けられた2つの異なる名前(短いファル名と長いファイル名)は、f_readdir関数を除くファイル操作関数において透過です。デフォルト構成では、LFN機能はOFFになっています。LFN機能を有効にするには、_USE_LFNを1,2または3に設定し、option/unicode.cをプロジェクトに追加します。LFN機能は、加えてある程度のワーク エリア(LFN操作バッファ)を必要とします。バッファ長は使用できるメモリに応じて_MAX_LFNで構成されることができます。LFNの長さは最大255文字に達するので、LFN完全対応のためには_MAX_LFNは255に設定されるべきです。与えられたファイル名に対してバッファ長が不足した場合、ファイル関数はFR_INVALID_NAMEで失敗します。

    +

    ファイル関数に再入を行う条件の下でLFN機能を使用する場合は、_USE_LFNは2または3に設定されなければなりません。この場合、ファイル関数はワーク エリアを動的に確保(スタックまたはヒープ)します。ワーク エリアのサイズは、(_MAX_LFN + 1) * 2バイト(exFAT利用時はさらに+608バイト)になるので、スタック等のサイズはそれを考慮した十分な余裕がなければなりません。

    @@ -152,21 +155,29 @@ _WORD_ACCESS 0 or 1 (Set by processor architecture)
    LFN構成 at CM3
    _CODE_PAGE追加コード
    950(Big5)+111k

    LFN機能の上手な使い方は、それを使わないということです。実際、組み込み用途ではLFN機能がどうしても必要になるということはほとんど無いはずです。LFNを有効にすると、選択されたコード ページに応じてモジュール サイズが増大します。右の表に各コード ページにおけるLFNを有効にしたときのモジュール サイズの違いを示します。特に、CJK地域では数万の文字が使われていますが、不幸なことにそれは巨大なOEM-Unicode相互変換テーブルを要求し、モジュール サイズは劇的に増大します。その結果、それらのコード ページにおいてLFNを有効にしたFatFsモジュールは、多くの8ビット マイコンにインプリメントすることができません。

    -

    LFN機能のハードルはそれだけではありません。マイクロソフト社はFATファイル システムについていくつかの特許を保有しています。いずれもLFN機能の実装に関するもので、その利用に対して$0.25/unitのライセンス料を要求しています。このため、商用製品でLFN機能を利用するときは、最終仕向地によってはライセンスが必要になります。最近のFAT32ドライバの多くはLFN機能を含んでいるため、それらの使用に当たってライセンスが必要になりますが、FatFsではLFN機能を構成オプションで任意にON/OFFできるため、無効にしてライセンス問題を回避することもできます。

    +

    LFN機能のハードルはそれだけではありません。マイクロソフト社はFATファイルシステムについていくつかの特許を保有しています。いずれもLFN機能の実装に関するもので、その利用に対して$0.25/unitのライセンス料を要求しています。このため、商用製品でLFN機能を利用する場合は、製品の最終仕向地によってはライセンスが必要になります。最近のFAT32ドライバの多くはLFN機能を含んでいるため、それらの使用に当たってライセンスが必要になりますが、FatFsは構成オプションでLFN機能を任意にON/OFFできるため、無効にしてライセンス問題を回避することもできます。

    Unicode入出力への対応

    -

    FatFs API上におけるファイル名等の文字列データの入出力は、デフォルトではANSI/OEMコードで行われますが、これをUnicode(UTF-16)に切り替えることもできます(_LFN_UNICODEオプションで設定)。つまり、これはFatFsがLFN機能に完全対応していることを意味します。Unicodeのファイル名に関する詳細は、パス名のフォーマットを参照してください。

    +

    FatFs API上におけるファイル名等の文字列データの入出力は、デフォルトではANSI/OEMコードで行われますが、これをUnicode(UTF-16)に切り替えることもできます(_LFN_UNICODEで設定)。つまり、これはFatFsがLFN機能に完全対応していることを意味します。Unicodeのファイル名に関する詳細は、パス名のフォーマットを参照してください。

    +
    + +
    +

    exFATファイルシステム

    +

    exFAT(Microsoft's Extended File Allocation Table)ファイルシステムは、既に組み込みシステムや情報家電で広く使われているFATファイルシステムを置き換える目的で開発されました。exFATは、64GiB以上のSDメモリ カードで標準ファイルシステムに採用されるなど、FATに並びリムーバブル メディアの標準ファイルシステムの一つとなりつつあります。

    +

    exFATボリュームでは、FATボリュームで制約となっていた4GiB以上のサイズのファイルを扱え、ファイルシステムのオーバーヘッド(特にファイル アロケーション ディレイ)も大幅に低減され、書き込みスループットがFATより向上しています。しかし、現リビジョンのFatFsでは、実装上の理由から不連続ファイルへのサイズ拡大を伴う書き込み時のとき、スループットがFATより低下します。f_expand関数による連続領域の割り当て機能は、この問題の回避に有効かもしれません。

    +

    exFATはマイクロソフト社が開発したものなので、マイクロソフト社はexFATについていくつかの特許を保有しています。FatFsのexFAT機能は、それの US. Pat. App. Pub. No. 2009/0164440 A1 に基づいた実装です。このため、商用製品でexFAT機能を利用する場合、製品の最終仕向地によってはライセンスが必要になります。最近のFATドライバの多くはexFAT機能を含んでいるため、それらの使用に当たってライセンスが必要になりますが、FatFsは構成オプションでexFAT機能を任意にON/OFFできるため、無効にしてライセンス問題を回避することもできます。

    +

    exFATを有効にすると、FatFsモジュールのC89互換は失われます(64ビット整数型が必要なため)。

    リエントランシー

    -

    互いに異なるボリュームに対するファイル操作は構成にかかわらずリエントラントで、常に同時平行に動作できます。

    -

    同じボリュームに対してはデフォルトではリエントラントではありませんが、_FS_REENTRANTオプションでリエントラント(スレッド セーフ)にすることはできます。この場合、OS依存の同期オブジェクト操作関数ff_cre_syncobj, ff_del_syncobj, ff_req_grant, ff_rel_grant関数もまたプロジェクトに追加されなければなりません。サンプル コードと解説はoption/syncobj.cにあります。

    +

    互いに異なるボリュームに対するファイル操作は、_USE_LFN == 1を除いて構成にかかわらずリエントラントで、常に同時平行に動作できます。

    +

    同じボリュームに対してはデフォルトではリエントラントではありませんが、_FS_REENTRANTでリエントラント(スレッド セーフ)にすることはできます。この場合、OS依存の同期オブジェクト操作関数ff_cre_syncobj, ff_del_syncobj, ff_req_grant, ff_rel_grant関数もまたプロジェクトに追加されなければなりません。サンプル コードと解説はoption/syncobj.cにあります。

    この場合、あるタスクがボリュームを使用中に他のタスクからそのボリュームに対するファイル関数が呼び出されると、そのアクセスは先のタスクがファイル関数を抜けるまでサスペンドされます。待ち時間が_TIMEOUTで指定された期間を越えた場合、その関数はFR_TIMEOUTでアボートします。いくつかのRTOSではタイムアウト機能はサポートされないかも知れません。

    ひとつの例外がf_mount, f_mkfs, f_fdisk関数にあります。これらのボリューム制御関数は同じボリューム(または関連する物理ドライブ)に対してリエントラントではありません。これらの関数を使用するときは、アプリケーション レベルで排他制御しなければなりません。

    -

    注: このセクションはFatFsモジュールそれ自体のリエントランシーについて説明しています。_FS_REENTRANTは、各ファイル システム オブジェクトの排他制御を行うのみで、下位のディスク関数への再入を防止するものではありません。たとえば、シングル ボリューム構成ではdisk_status関数のみ再入される可能性があり、マルチ ボリューム構成ではどのディスク関数も再入される可能性があります。このように、複数のタスクから同時にFatFs APIを使う条件では、ディスクI/Oモジュールはスレッド セーフである必要があります。

    +

    注: このセクションはFatFsモジュールそれ自体のリエントランシーについて説明しています。_FS_REENTRANTは、各ファイルシステム オブジェクトの排他制御を行うのみで、下位のディスク関数への再入を防止するものではありません。たとえば、シングル ボリューム構成ではdisk_status関数のみ再入される可能性があり、マルチ ボリューム構成ではどのディスク関数も再入される可能性があります。このように、複数のタスクから同時にFatFs APIを使う条件では、ディスクI/Oモジュールはスレッド セーフである必要があります。

    @@ -179,15 +190,15 @@ _WORD_ACCESS 0 or 1 (Set by processor architecture)

    効率的なファイル アクセス

    小規模な組込システムでのファイルの読み書きにおける効率の良いアクセスのため、アプリケーション プログラマはFatFsモジュールの中でどのような処理が行われているか考慮すべきです。ストレージ上のデータはf_read関数により次のシーケンスで転送されます。

    図1. セクタ ミスアラインド リード (ショート)
    -fig.1 +fig.1

    図2. セクタ ミスアラインド リード (ロング)
    -fig.2 +fig.2

    図3. セクタ アラインド リード
    -fig.3 +fig.3

    -

    ファイルI/Oバッファはセクタの一部のデータを読み書きするためのセクタ バッファを意味します。セクタ バッファは、それぞれのファイル オブジェクト内のプライベート セクタ バッファまたはファイル システム オブジェクト内の共有セクタ バッファのどちらかです。バッファ構成オプションの_FS_TINYは、データ転送にどちらを使うかを決定します。タイニー バッファ(1)が選択されるとデータ メモリの消費はそれぞれのファイル オブジェクトで_MAX_SSバイト減少されます。この場合、FatFsモジュールはファイル データの転送とFAT/ディレクトリ アクセスにファイル システム オブジェクト内のセクタ バッファだけを使用します。タイニー バッファの欠点は、セクタ バッファにキャッシュされたFATデータがファイル データの転送により失われ、クラスタ境界の毎にリロードされなければならないことです。でも、悪くない性能と少ないメモリ消費の視点から多くのアプリケーションに適するでしょう。

    +

    ファイルI/Oバッファはセクタの一部のデータを読み書きするためのセクタ バッファを意味します。セクタ バッファは、それぞれのファイル オブジェクト内のプライベート セクタ バッファまたはファイルシステム オブジェクト内の共有セクタ バッファのどちらかです。バッファ構成オプションの_FS_TINYは、データ転送にどちらを使うかを決定します。タイニー バッファ(1)が選択されるとデータ メモリの消費はそれぞれのファイル オブジェクトで_MAX_SSバイト減少されます。この場合、FatFsモジュールはファイル データの転送とFAT/ディレクトリ アクセスにファイルシステム オブジェクト内のセクタ バッファだけを使用します。タイニー バッファの欠点は、セクタ バッファにキャッシュされたFATデータがファイル データの転送により失われ、クラスタ境界の毎にリロードされなければならないことです。でも、悪くない性能と少ないメモリ消費の視点から多くのアプリケーションに適するでしょう。

    図1はセクタの一部のデータがファイルI/Oバッファを経由で転送されることを示します。図2に示される長いデータの転送では、転送データの中間の1セクタまたはそれ以上のセクタにまたがる転送データがアプリケーション バッファに直接転送されています。図3は転送データ全体がセクタ境界にアライメントされている場合を示しています。この場合、ファイルI/Oバッファは使用されません。直接転送においては最大の範囲のセクタがdisk_read関数で一度に読み込まれますが、クラスタ境界を越えるマルチ セクタ転送はそれが隣接であっても行われません。

    このように、セクタにアライメントしたファイルの読み書きへの配慮はバッファ経由のデータ転送を避け、読み書き性能は改善されるでしょう。その効果に加え、タイニー構成でキャッシュされたFATデータがファイル データの転送によりフラッシュされず、非タイニー構成と同じ性能を小さなメモリ フットプリントで達成できます。

    @@ -198,12 +209,12 @@ _WORD_ACCESS 0 or 1 (Set by processor architecture)

    マルチ セクタ書き込み

    図6. マルチ/シングル セクタ ライトの比較
    -fig.6 +fig.6
    -

    フラッシュ メモリ メディアの書き込み速度はシングル セクタ書き込みの時に最も低いものになり、一回のトランザクションで転送されるセクタ数が大きくなるほど書き込み速度は向上します(図6)。この効果はバス速度が高速になるほど大きく、10倍以上の差が現れることも珍しくありません。テスト結果は、マルチ セクタ書き込み(W:16K, 32 sectors)がシングル セクタ書き込み(W:100, 1 sector)よりどの程度速いかを明確に示しています。大容量メディアほどシングル セクタ書き込みが遅くなる点もまた重要です。書き込みトランザクションの回数はまた、メディアの寿命にも影響してきます。つまり、同じ量のデータを書き込む場合、図6上のシングル セクタ書き込みは、図6下のマルチ セクタ書き込みに比べて16倍早くフラッシュ メモリ メディアを消耗させてしまうということです。

    +

    フラッシュ メモリ メディアの書き込み速度はシングル セクタ書き込みの時に最も低いものになり、一回のトランザクションで転送されるセクタ数が大きくなるほど書き込み速度は向上します(図6)。この効果はバス速度が高速になるほど大きく、10倍以上の差が現れることも珍しくありません。テスト結果は、マルチ セクタ書き込み(W:16K, 32 sectors)がシングル セクタ書き込み(W:100, 1 sector)よりどの程度速いかを明確に示しています。大容量メディアほどシングル セクタ書き込みが遅くなる点もまた重要です。書き込みトランザクションの回数はまた、メディアの寿命にも影響してきます。つまり、同じ量のデータを書き込む場合、図6上のシングル セクタ書き込みは、図6下のマルチ セクタ書き込みに比べて16倍早くフラッシュ メモリ メディアを消耗させてしまうということです。

    このように、アプリケーションはなるべく大きなブロック(クラスタ サイズまたは2の累乗セクタ境界にアライメントした)で読み書きを行う必要があります。もちろん、アプリケーションからメディアに至る全てのレイヤがマルチ セクタ転送に対応していないと意味がありません。残念ながら、既存のオープン ソースのドライバの多くはマルチ セクタ転送に未対応です。なお、FatFsモジュールおよびサンプル ドライバはマルチ セクタ転送に対応しています。

    明示的なメモリ消去

    -

    通常のファイル消去では、記録されたデータに対して何らかの制御が行われるわけではなく、単にFAT上に未使用クラスタとして記録されているだけです。このため、ファイルが消去されたあともそれらは有効なメモリ ブロックとしてフラッシュ メモリ上に残ります。そこで、ファイルを消去するとき、占有していたデータ セクタを明示的に消去(つまり未使用ブロックにする)することにより、メディア内の空きブロックを増やすことができます。これにより、次にそのブロックに書き込むときの消去動作が無くなり、書き込み性能が向上する可能性があります。また、ウェアレベリングに使えるブロックが増え、メディアの耐久性も向上するかも知れません。この機能を有効にするには、構成オプションの_USE_TRIMに1を設定します。これはフラッシュ メモリ メディアの内部動作に期待した制御なので、効果があるとは限りません。また、ファイル消去の時間が延びることも考慮に入れるべきです。

    +

    通常のファイル消去では、記録されたデータに対して何らかの処理が行われるわけではなく、単にFAT上にその領域を未使用と記録しているだけです。このため、ファイルが消去されたあともそれらは有効なデータ ブロックとしてフラッシュ メモリ上に残ります。そこで、ファイルを消去するとき、占有していたデータ セクタを明示的に消去(つまり未使用ブロックにする)することにより、メディア内の空きブロックを増やすことができます。これにより、次にそのブロックに書き込むときの消去動作が無くなり、書き込み性能が向上する可能性があります。また、ウェアレベリングに使えるブロックが増え、メディアの耐久性も向上するかも知れません。この機能を有効にするには、_USE_TRIMに1を設定します。これはフラッシュ メモリ ドライブの内部動作に期待した制御なので、効果があるとは限りません。また、ファイル消去の時間が延びることも考慮に入れるべきです。

    @@ -211,11 +222,11 @@ _WORD_ACCESS 0 or 1 (Set by processor architecture)

    ストレージ上のFAT構造を操作している途中で、停電、不正なメディアの取り外し、回復不能なデータ エラー等の障害が発生すると、処理が中途半端な状態で中断され、その結果としてFATボリュームの構造が破壊される可能性があります。次にFatFsモジュールにおけるクリチカル セクションと、その間の障害により起きうるエラーの状態を示します。

    図4. 長いクリチカル セクション
    -fig.4 +fig.4
    図5. 最小化したクリチカル セクション
    -fig.5 +fig.5

    赤で示したセクションを実行中に中断が発生した場合、クロス リンクが発生して操作中のファイルやディレクトリが失われる可能性があります。黄色で示したセクションを実行中に中断が発生した場合、次のうちいずれかまたは複数の結果が生じる可能性があります。

    @@ -233,27 +244,30 @@ _WORD_ACCESS 0 or 1 (Set by processor architecture)

    APIの拡張的使用例

    FatFs APIの拡張的使用例です。有用なコードがあった場合は、随時追加していきます。。

      -
    1. 追記モードでのオープン/新規作成
    2. -
    3. ディレクトリを空にする
    4. -
    5. ファイルに連続領域を割り当てる
    6. -
    7. ディスクI/Oモジュールの機能/互換性チェッカー
    8. -
    9. FATイメージ作成ツール
    10. +
    11. 追記モードでのオープン/新規作成(R0.12以前)
    12. +
    13. ディレクトリを空にする
    14. +
    15. ファイルに連続領域を割り当てる(R0.11a以前)
    16. +
    17. ディスクI/Oモジュールの機能/互換性チェッカー
    18. +
    19. FATイメージ作成ツール

    FatFsのライセンスについて

    -

    ソース ファイルにライセンス条件が記述されているので、利用の際はそれに従うこと。原文は英語ですが、参考までに以下に日本語訳を示しておきます。

    +

    FatFsは、作者(ChaN)の個人プロジェクトとして開発されています。現在のリビジョンにおいてコントリビューターはいないため、作者の書いたソース コード以外は含まれません。ソース ファイルにライセンス条件が記述されているので、利用の際はそれに従うこと。原文は英語ですが、参考までに以下に日本語訳を示しておきます。

     /*----------------------------------------------------------------------------/
    -/  FatFs - FAT file system module  R0.11                 (C)ChaN, 2015
    +/  FatFs - Generic FAT file system module  R0.12a                             /
     /-----------------------------------------------------------------------------/
    -/ FatFsモジュールはフリーソフトウェアで、次に示す条件の下に公開されています。
     /
    -/ Copyright (C) 2015, ChaN, all right reserved.
    +/ Copyright (C) 2016, ChaN, all right reserved.
     /
    -/ 1. ソースコードで再配布するときは、その中に上記の著作権表示、この条文、および
    -/    次の免責事項を保持すること
    +/ FatFsモジュールはオープンソースソフトウェアです。FatFsの再配布および使用は、
    +/ ソースコードかバイナリ形式か、また変更の有無にかかわらず、次の条件が満たされ
    +/ る場合に限り許可されます。
    +/
    +/ 1. ソースコードで再配布するときは、その中に上記の著作権表示、この条件、および
    +/    次の免責事項を保持すること。
     / 
     / このソフトウェアは、著作権者らおよびコントリビューターらによって現状のまま
     / 提供されており、いかなる保証もありません。
    @@ -261,7 +275,7 @@ _WORD_ACCESS   0 or 1 (Set by processor architecture)
     / 損害についても、責任を負いません。
     /----------------------------------------------------------------------------*/
     
    -

    このようにFatFsはBSDライクなライセンスとしていますが、一つ大きな違いがあります。FatFsは主に組み込み向けとして開発されたため、バイナリ形式(ソース コードを含まない形式全て)での再配布については、商用での使いやすさを考慮して配布時の条件を設けていません。つまり、バイナリ配布の場合は、FatFsおよびそのライセンス文書についてドキュメントに明記してもしなくてもかまいません。これは、一条項BSDライセンスと等価ということです。もちろん、GNU GPLなどほとんど全てのオープン ソース ライセンスの下のプロジェクトにおいて共存可能です。FatFsに何らかの修正や拡張を加えてソース コードで再配布する場合は、矛盾しない他のオープン ソース ライセンス(GNU GPLや修正BSDライセンスなど)に変更することも可能です。

    +

    このようにFatFsはBSDライクなライセンスとしていますが、一つ大きな違いがあります。FatFsは主に組み込み向けとして開発されたため、バイナリ形式(ソース コードを含まない形式全て)での再配布については、商用での使いやすさを考慮して配布時の条件を設けていません。つまり、バイナリ配布の場合は、FatFsおよびそのライセンス文書についてドキュメントに明記してもしなくてもかまいません。これは、一条項BSDライセンスと等価ということです。もちろん、GNU GPLなどほとんど全てのオープン ソース ライセンスの下のプロジェクトにおいて共存可能です。FatFsからフォークを作成し公開する場合は、矛盾しない他のオープン ソース ライセンス(GNU GPLや修正BSDライセンスなど)に変更することも可能です。

    戻る

    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/config.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/config.html index 2b059d29..f01fb199 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/config.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/config.html @@ -43,19 +43,25 @@ div.doc h4 {margin-top: 2em }

    _USE_FIND

    -

    フィルタ付きディレクトリ読み出し機能の構成(0:無効 または 1:有効)。有効にすると、f_findfirstf_findnext関数が利用可能になります。

    +

    フィルタ付きディレクトリ読み出し機能の構成(0:無効 または 1:有効)。有効にすると、f_findfirstf_findnext関数が利用可能になります。_FS_MINIMIZEは、1以下でなければなりません。

    _USE_MKFS

    ボリューム作成機能の構成(0:無効 または 1:有効)。有効にするとf_mkfs関数が利用可能になります。

    _USE_FASTSEEK

    -

    高速シーク機能の構成(0:無効 または 1:有効)。有効にすると、f_lseekf_readf_write関数の高速化モードが利用可能になります。詳しくは、こちらを参照してください。

    +

    高速シーク機能の構成(0:無効 または 1:有効)。有効にすると、f_lseekf_readf_write関数において高速化モードが利用可能になります。詳しくは、こちらを参照してください。

    + +

    _USE_EXPAND

    +

    連続領域割り当て機能の構成(0:無効 または 1:有効)。有効にするとf_expand関数が利用可能になります。_FS_READONLYは0でなければなりません。

    + +

    _USE_CHMOD

    +

    メタデータ操作機能の構成(0:無効 または 1:有効)。有効にすると、f_chmodf_utime関数が利用可能になります。_FS_READONLYは0でなければなりません。

    _USE_LABEL

    -

    ボリューム ラベル操作機能の構成(0:無効 または 1:有効)。有効にすると、f_getlabelf_setlabel関数が利用可能になります。

    +

    ボリューム ラベル操作機能の構成(0:無効 または 1:有効)。有効にすると、f_getlabelf_setlabel関数(_FS_READONLY == 0のとき)が利用可能になります。

    _USE_FORWARD

    -

    ストリーミング読み出し機能の構成(0:無効 または 1:有効)。これと_FS_TINYを有効にすると、f_forward関数が利用可能になります。

    +

    ストリーミング読み出し機能(f_forward関数)の構成(0:無効 または 1:有効)。

    @@ -92,13 +98,13 @@ div.doc h4 {margin-top: 2em }

    _USE_LFN

    -

    LFN(長いファイル名)対応を設定します。LFN機能を有効にするときは、Unicode操作関数option/unicode.cをプロジェクトに加える必要があります。また、LFN操作バッファ((_MAX_LFN + 1) * 2バイトを占有)を使用します。バッファをスタックに確保するときは、スタック オーバ フローに注意する必要があります。ヒープに確保するときは、メモリ操作関数、ff_memallocff_memfree(option/syscall.cにサンプルあり)、をプロジェクトに加える必要があります。

    +

    LFN(長いファイル名)対応を設定します。LFN機能を有効にするときは、Unicode操作関数option/unicode.cをプロジェクトに加える必要があります。また、LFN操作のワーク エリアとして(_MAX_LFN + 1) * 2バイト(exFAT構成時はさらに608バイト)を使用します。このため、バッファをスタックに確保するときは、スタック オーバ フローに注意する必要があります。ヒープに確保するときは、メモリ操作関数(ff_memallocff_memfree(option/syscall.cにサンプルあり))をプロジェクトに加える必要があります。

    - - - + + +
    解説
    0LFN機能を使わない。8.3形式の名前のみ使用可能。
    1LFN機能を使う。LFN操作バッファは静的に確保。常にスレッド セーフではない。
    2LFN機能を使う。LFN操作バッファはスタックから確保。
    3LFN機能を使う。LFN操作バッファはヒープから確保。
    1LFN機能を使う。ワーク エリアは静的に確保。常にスレッド セーフではない。
    2LFN機能を使う。ワーク エリアはスタックに確保。
    3LFN機能を使う。ワーク エリアはヒープに確保。

    _MAX_LFN

    @@ -169,6 +175,9 @@ div.doc h4 {margin-top: 2em }

    _FS_TINY

    ファイル データ転送バッファの構成(0:ノーマル または 1:タイニ)。タイニ構成では、ファイル オブジェクトFIL内のプライベート セクタ バッファが削除され、_MAX_SSバイト小さくなります。ファイル データの転送には、代わりにファイル システム オブジェクトFATFS内のボリューム共有セクタ バッファが使われます。

    +

    _FS_EXFAT

    +

    exFATのサポート(0:使用しない または 1:使用する)。exFATを使用するには、LFN機能を有効にしなければなりません。また、exFATの完全サポートのためには、_LFN_UNICODE = 1_MAX_LFN = 255の設定が推奨されます。exFAT機能では64ビット整数を使用するため、これを有効にするとC89(ANSI C)互換が失われます。

    +

    _FS_NORTC

    RTC機能の使用の設定(0:使用する または 1:使用しない)。システムがRTC(カレンダ時計)をサポートしない場合は、1をセットします。この場合、FatFsが変更を加えたオブジェクトのタイムスタンプはデフォルトの日時を持ちます。RTCが使用可能なときは、0を設定し、get_fattime関数をプロジェクトに加えます。リード オンリ構成ではこのオプションは意味を持ちません。

    @@ -193,31 +202,6 @@ div.doc h4 {margin-top: 2em }

    _SYNC_t

    O/S定義の同期オブジェクトの型を設定します。例: HANDLEIDOS_EVENT*SemaphoreHandle_tなど。また、O/S機能のヘッダ ファイルをff.cのスコープ内にインクルードする必要があります。_FS_REENTRANTが0のときは意味を持ちません。

    -

    _WORD_ACCESS

    -

    ボリューム上のワード データへのアクセス方法を設定します。唯一のプラットフォーム依存オプションです。

    - - - - -
    解説
    0Byte-by-byteアクセス。全てのプラットフォームでコンパチブル。
    1ワード アクセス。コード サイズが少し減るが、次の条件を共に満たしていない限り選択できない。
    -・非アライン メモリ アクセスが常に全ての命令で使用可能。
    -・メモリ上のバイト順がリトル エンディアン。
    -

    次にいくつかのプロセッサにおける許可された設定を示します。

    -
    -   ARM7TDMI   0   *2          ColdFire   0    *1         V850E      0    *2
    -   Cortex-M3  0   *3          Z80        0/1             V850ES     0/1
    -   Cortex-M0  0   *2          x86        0/1             TLCS-870   0/1
    -   AVR        0/1             RX600(LE)  0/1             TLCS-900   0/1
    -   AVR32      0   *1          RL78       0    *2         R32C       0    *2
    -   PIC18      0/1             SH-2       0    *1         M16C       0/1
    -   PIC24      0   *2          H8S        0    *1         MSP430     0    *2
    -   PIC32      0   *1          H8/300H    0    *1         8051       0/1
    -
    -   *1:ビッグ エンディアン
    -   *2:非アライン メモリ アクセス不可
    -   *3:いくつかのコンパイラがmem_cpy関数にLDM/STM命令を生成する
    -
    -

    戻る

    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/dioctl.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/dioctl.html index f5715a7b..b37ffeaf 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/dioctl.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/dioctl.html @@ -80,6 +80,9 @@ DRESULT disk_ioctl ( ATA_GET_REVリビジョン コードをbuffの示す16バイトのバッファに読み出します。(ATA/CFカード専用) ATA_GET_MODELモデル コードをbuffの示す40バイトのバッファに読み出します。(ATA/CFカード専用) ATA_GET_SNシリアル番号をbuffの示す20バイトのバッファに読み出します。(ATA/CFカード専用) +ISDIO_READbuffの示すコマンド構造体に従いiSDIOレジスタからデータを読み出します。(FlashAir専用) +ISDIO_WRITEbuffの示すコマンド構造体に従いiSDIOレジスタにデータを書き込みます。(FlashAir専用) +ISDIO_MRITEbuffの示すコマンド構造体に従いiSDIOレジスタの一部のビットを書き換えます。(FlashAir専用) diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/dread.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/dread.html index 24991dbf..4c8ddba8 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/dread.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/dread.html @@ -34,7 +34,7 @@ DRESULT disk_read (
    sector
    読み出しを開始するセクタ番号。32ビットLBAで指定されます。
    count
    -
    読み出すセクタ数が1~128の範囲で指定されます。
    +
    読み出すセクタ数(1以上の値)が指定されます。
    @@ -45,11 +45,11 @@ DRESULT disk_read (
    RES_OK (0)
    正常終了。
    RES_ERROR
    -
    読み込み中にエラーが発生し、その回復にも失敗した。
    +
    回復不能なエラーにより、読み出し操作を完了できなかった。
    RES_PARERR
    パラメータが不正。
    RES_NOTRDY
    -
    ストレージ デバイスが動作可能状態ではない(初期化されていない)。
    +
    ストレージ デバイスが動作可能な状態ではない (初期化されていない)。
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/dwrite.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/dwrite.html index 020d5f1c..fa0de8d1 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/dwrite.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/dwrite.html @@ -30,11 +30,11 @@ DRESULT disk_write (
    pdrv
    対象のデバイスを識別する物理ドライブ番号(0-9)が指定されます。
    buff
    -
    ストレージ デバイスに書き込むセクタ データが格納されたバイト配列が指定されます。バイト数は、セクタ サイズ*countとなります。
    +
    ストレージ デバイスに書き込むセクタ データが格納されたバイト配列が指定されます。データのバイト数は、セクタ サイズ*countとなります。
    sector
    書き込みを開始するセクタ番号。32ビットLBAで指定されます。
    count
    -
    書き込むセクタ数が1~128の範囲で指定されます。
    +
    書き込むセクタ数(1以上の値)が指定されます。
    @@ -45,13 +45,13 @@ DRESULT disk_write (
    RES_OK (0)
    正常終了。
    RES_ERROR
    -
    書き込み中にエラーが発生し、その回復にも失敗した。
    +
    回復不能なエラーにより、書き込み操作を完了できなかった。
    RES_WRPRT
    メディアが書き込み禁止状態。
    RES_PARERR
    パラメータが不正。
    RES_NOTRDY
    -
    ストレージ デバイスが動作可能状態ではない(初期化されていない)。
    +
    ストレージ デバイスが動作可能な状態ではない (初期化されていない)。
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/expand.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/expand.html new file mode 100644 index 00000000..98667d10 --- /dev/null +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/expand.html @@ -0,0 +1,116 @@ + + + + + + + + +FatFs - f_expand + + + + +
    +

    f_expand

    +

    ファイルに連続したデータ領域を割り当てます。

    + +
    +FRESULT f_expand (
    +  FIL*    fp,  /* [IN] ファイル オブジェクト構造体へのポインタ */
    +  FSIZE_t fsz, /* [IN] 割り当てサイズ */
    +  BYTE    opt  /* [IN] 動作オプション */
    +);
    +
    +
    + +
    +

    Parameters

    +
    +
    fp
    +
    対象となるファイル オブジェクト構造体へのポインタを指定します。
    +
    fsz
    +
    ファイルに割り当てるバイト単位のサイズ。データ型FSIZE_tは、DWORD(32-bit)またはQWORD(64-bit)のエリアスで、exFATサポートの有無により切り替わります。
    +
    opt
    +
    実際に割り当てを行うかどうか指定するフラグ。
    +
    +
    + + + + + +
    +

    解説

    +

    optに1を指定すると、ファイルに連続したデータ領域を割り当てます。f_lseekによるサイズ拡張とは異なり、対象ファイルのサイズは0(つまりデータ領域未割り当て)でなければなりません。また、リード/ライト ポインタは、ファイル先頭に留まります。この関数により割り当てられたファイルの内容は未定義なので、それに対して何の前提も持つべきではありません。この関数は、次の理由によりFR_DENIEDで失敗することがあります。

    +
      +
    • ボリューム上に連続した空き領域が見つからなかった。
    • +
    • ファイルのサイズが0ではなかった。
    • +
    • ファイルが非書き込みモードで開かれている。
    • +
    • 指定されたファイル サイズが無効。(FATボリューム上で >=4GiB)
    • +
    +

    optに0を指定したときは、連続したデータ領域を探すのみで、その時点ではファイルへの割り当てを行わず、代わりにそれを検索開始ポイントとしてファイル システム オブジェクトにセットします。これにより、そのボリューム上で別の操作(FAT変更を伴う)が行われない限り、書き込まれるファイルは少なくともそのサイズまでは連続性が保証され、遅延無く書き込めることになります。

    +

    時間的制約のあるファイル読み書き操作において、連続データ領域を割り当てられたファイルは有利となります。これは、分割されたファイルによりもたらされる無用なランダム アクセスが減ることにより、ファイル システムやストレージ デバイスの処理のオーバーヘッドが削減されるからです。特にexFATボリューム上の連続ファイルでは一切のFATアクセスが発生せず、効率的なシーケンシャル アクセスが行えます。

    +

    連続ファイルに対して低レベルI/Oを使用したさらに効率的な直接アクセスも容易に行えますが、これは将来の互換性の点で推奨はされません。

    +
    + +
    +

    対応情報

    +

    _USE_EXPAND == 1で、かつ_FS_READONLY == 0のとき使用可能です。

    +
    + + +
    +

    使用例

    +
    +    /* 連続ファイルの作成 */
    +
    +    /* 新しいファイルの作成 */
    +    res = f_open(fp = malloc(sizeof (FIL)), "file.dat", FA_WRITE|FA_CREATE_ALWAYS);
    +    if (res) { /* ファイルが開かれたかチェック */
    +        free(fp);
    +        ...
    +    }
    +
    +    /* 100 MiB の連続領域を割り当てる */
    +    res = f_expand(fp, 104857600, 1);
    +    if (res) { /* 割り当てられたかチェック */
    +        ...
    +        free(fp);
    +        ...
    +    }
    +    /* 連続ファイル作成成功 fp でアクセス可能 */
    +
    +
    +
    +    /* ファイル システムを介さず直接アクセスする例 */
    +
    +    /* ファイル データの物理的位置を取得 */
    +    drv = fp->obj.fs->drv;
    +    sect = fp->obj.fs->database + fp->obj.fs->csize * (fp->obj.sclust - 2);
    +
    +    /* ファイル先頭から2048セクタを書き込み */
    +    res = disk_write(drv, buffer, sect, 2048);
    +
    +
    +
    + + +
    +

    参照

    +

    f_open, f_lseek, FIL

    +
    + +

    戻る

    + + diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/fdisk.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/fdisk.html index 53b6cbb9..2598f7e6 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/fdisk.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/fdisk.html @@ -16,9 +16,9 @@

    物理ドライブを分割します。

     FRESULT f_fdisk (
    -  BYTE  pdrv,         /* [IN] 物理ドライブ番号 */
    -  const DWORD part[], /* [IN] 区画マップ テーブル */
    -  void* work          /* [-] ワークエリア */
    +  BYTE  pdrv,       /* [IN] 物理ドライブ番号 */
    +  const DWORD* szt, /* [IN] 区画サイズ テーブル */
    +  void* work        /* [-] ワークエリア */
     );
     
    @@ -27,9 +27,9 @@ FRESULT f_fdisk (

    引数

    pdrv
    -
    分割する物理ドライブのドライブ番号を指定します。
    -
    part[]
    -
    区画マップ テーブルへのポインタを指定します。
    +
    分割する物理ドライブを指定します。これは論理ドライブ番号ではなく、ディスク関数に渡される物理ドライブ番号です。
    +
    szt
    +
    区画サイズ テーブルの先頭項目へのポインタを指定します。
    work
    ワークエリアへのポインタを指定します。サイズは_MAX_SSバイト必要です。
    @@ -48,7 +48,7 @@ FRESULT f_fdisk (

    説明

    -

    この関数は、指定された物理ドライブのMBRに区画テーブルを作成します。区画分けは一般的なFDISK形式で行うため、最大4つの基本区画を作成することができます。拡張区画には対応していません。区画マップテーブルpart[]にはドライブをどのように分割するか指定して渡します。この配列は4つの項目から成り、先頭の項目が1番目の、最後の項目が4番目の区画のサイズを示します。値が100以下の場合、ドライブの総容量に対する割合をパーセント単位で指定します。100を超える値の場合はセクタ数の直接指定になります。

    +

    この関数は、指定された物理ドライブのMBRに区画テーブルを作成します。区画分けは一般的なFDISK形式で行うため、最大4つの基本区画を作成することができます。拡張区画には対応していません。区画サイズ テーブルにはドライブをどのように分割するか指定します。この配列は4つの項目から成り、先頭の項目が1番目の区画のサイズを示します。項目の値が100以下の場合、その区画のドライブの総容量に対する割合をパーセント単位で指定します。100を超える値の場合はセクタ数の直接指定になります。ドライブ上への区画の配置順は、項目順になります。

    @@ -71,27 +71,22 @@ FRESULT f_fdisk ( /* 新しい物理ドライブ(0)の初期化 */ FATFS fs; - DWORD plist[] = {50, 50, 0, 0}; /* 2分割 */ + DWORD plist[] = {50, 50, 0, 0}; /* 第1区画,第2区画それぞれに50%ずつ割り当て */ BYTE work[_MAX_SS]; - f_fdisk(0, plist, work); /* 物理ドライブ 0 の分割 */ + f_fdisk(0, plist, work); /* 物理ドライブ 0 の分割 */ - f_mount(&fs "0:", 0); - f_mkfs("0:", 0, 0); /* 論理ドライブ 0 のフォーマット. 第二引数は無視される. */ - f_mount(0, "0:", 0); - - f_mount(&fs, "1:", 0); - f_mkfs("1:", 0, 0); /* 論理ドライブ 0 のフォーマット. 第二引数は無視される. */ - f_mount(0, "1:", 0); + f_mkfs("0:", FMT_ANY, work, sizeof work); /* 論理ドライブ 0: のフォーマット */ + f_mkfs("1:", FMT_ANY, work, sizeof work); /* 論理ドライブ 1: のフォーマット */
    -

    Return

    +

    戻る

    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/filename.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/filename.html index 72c98487..5f38eaad 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/filename.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/filename.html @@ -33,7 +33,8 @@ dir1/..無効カレント ディレクトリ /..無効ルート ディレクトリ(その上は辿れない) -

    また、_STR_VOLUME_IDオプションを有効にすることでドライブ番号の識別には数字のほか、"sd:file1.txt""ram:swapfile.dat"のように、任意の文字列を使用することも可能になります。

    +

    また、_STR_VOLUME_IDオプションを有効にすることでドライブ番号の識別には数字のほか、"sd:file1.txt""ram:swapfile.dat"のように、任意の文字列(もちろんDOS/Windowsライクなドライブ文字も)を使用することも可能になります。

    +

    【注意】現リビジョン(R0.12)では、exFATボリューム上においてダブル ドット".."はシングル ドット"."として機能し、親ディレクトリを辿ることはできません。

    @@ -55,20 +56,20 @@

    ボリューム管理

    -

    デフォルトの構成では、それぞれの論理ドライブは同じ番号の物理ドライブに1:1で結びつけられていて、自動検出機能によりその物理ドライブ上の一つのFATボリュームがマウントされます。FATボリュームの検出は、セクタ0、第一区画~第四区画の順に行われます。

    +

    デフォルトの構成では、それぞれの論理ドライブは同じ番号の物理ドライブに1:1で結びつけられていて、自動検出機能によりその物理ドライブ上の一つのFATボリュームがマウントされます。FATボリュームの検出は、セクタ0(SFD)、第一区画~第四区画(FDISK)の順に行われます。

    _MULTI_PARTITIONに1を指定すると、それぞれの論理ドライブに対して個別に物理ドライブ番号と区画を指定できるようになります。この構成では、論理ドライブと区画の対応を解決するためのテーブルを次に示すように定義する必要があります。

     例:論理ドライブ0~2を物理ドライブ0(非リムーバブル)の3つの基本区画に割り当て、
        論理ドライブ3を物理ドライブ1(リムーバブル)に割り当てる場合。
     
     PARTITION VolToPart[] = {
    -    {0, 1},     /* 論理ドライブ 0 ==> 物理ドライブ 0, 第1区画 */
    -    {0, 2},     /* 論理ドライブ 1 ==> 物理ドライブ 0, 第2区画 */
    -    {0, 3},     /* 論理ドライブ 2 ==> 物理ドライブ 0, 第3区画 */
    -    {1, 0}      /* 論理ドライブ 3 ==> 物理ドライブ 1, 自動検出 */
    +    {0, 1},     /* "0:" ==> 物理ドライブ 0, 第1区画 */
    +    {0, 2},     /* "1:" ==> 物理ドライブ 0, 第2区画 */
    +    {0, 3},     /* "2:" ==> 物理ドライブ 0, 第3区画 */
    +    {1, 0}      /* "3:" ==> 物理ドライブ 1, 自動検出 */
     };
     
    -
    論理ドライブと物理ドライブの関係
    +
    論理ドライブと物理ドライブの関係

    複数区画指定を使用する場合、次の点に注意しなければなりません。

    • 複数のマウントされた区画を持つ物理ドライブは、非リムーバブルでなければならず、システム動作中のメディア交換は禁止。
    • diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/findfirst.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/findfirst.html index b809908c..c788768b 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/findfirst.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/findfirst.html @@ -62,7 +62,7 @@ FRESULT f_findfirst (

      解説

      pathで指定されるディレクトリを開き、そのディレクトリ内の項目の検索を開始します。正常終了すると、ディレクトリ オブジェクト構造体が作成され、最初に検索名文字列に名前がマッチした項目の情報がfnoの指定するファイル情報構造体にストアされます。名前のマッチする項目が見つからなかった場合は、fno->fname[]にヌル文字列が返されます。ファイル情報構造体の使い方については、f_readdir関数を参照してください。

      -

      マッチ パターン文字列は、ワイルドカード文字(?*)を含むことができます。?は任意の1文字に、*は0文字以上の任意の文字列にマッチします。LFN構成では、SFNとLFN(あれば)の両方に対してテストを行います。現リビジョンではパターン マッチングにおいて次の点で標準システムとは異なる動作となります。

      +

      マッチ パターン文字列は、ワイルドカード文字(?*)を含むことができます。?は任意の1文字に、*は0文字以上の任意の文字列にマッチします。LFN構成では、_USE_FIND = 1のときfname[]のみテストし、_USE_FIND = 2のときはaltname[]もテストします。現リビジョンではパターン マッチングにおいて次の点で標準システムとは異なる動作となります。

      • "*.*"は拡張子なしの名前にマッチしない。(標準システムでは全ての名前にマッチ)
      • ピリオドで終わるパターンは、どの名前にもマッチしない。(標準システムでは拡張子無しの名前にマッチ)
      • @@ -73,7 +73,7 @@ FRESULT f_findfirst (

        対応情報

        -

        この関数は、f_opendir関数およびf_readdir関数のラッパー関数です。_USE_FIND == 1で、かつ_FS_MINIMIZE <= 1のとき使用可能になります。

        +

        この関数は、f_opendir関数およびf_readdir関数のラッパー関数です。_USE_FIND >= 1で、かつ_FS_MINIMIZE <= 1のとき使用可能になります。

        @@ -84,23 +84,14 @@ FRESULT f_findfirst ( void find_image (void) { - FRESULT fr; /* 戻り値 */ + FRESULT fr; /* API戻り値 */ DIR dj; /* ディレクトリ オブジェクト */ - FILINFO fno; /* ファイル情報構造体 */ -#if _USE_LFN - char lfn[_MAX_LFN + 1]; - fno.lfname = lfn; - fno.lfsize = _MAX_LFN + 1; -#endif + FILINFO fno; /* ファイル情報 */ fr = f_findfirst(&dj, &fno, "", "dsc*.jpg"); /* "dsc"で始まるJPEGファイルを検索 */ while (fr == FR_OK && fno.fname[0]) { /* 見つかる間繰り返し */ -#if _USE_LFN - printf("%s %s\n", fno.fname, fno.lfname);/* 見つけた項目の名前を表示 */ -#else - printf("%s\n", fno.fname); -#endif + printf("%s\n", fno.fname); /* 見つけた項目の名前を表示 */ fr = f_findnext(&dj, &fno); /* 次を検索 */ } f_closedir(&dj); diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/findnext.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/findnext.html index 40191a02..e7c1331a 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/findnext.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/findnext.html @@ -54,7 +54,7 @@ FRESULT f_findnext (

        対応情報

        -

        この関数は、f_readdir関数のラッパー関数です。_USE_FIND == 1で、かつ_FS_MINIMIZE <= 1のとき使用可能になります。

        +

        この関数は、f_readdir関数のラッパー関数です。_USE_FIND >= 1で、かつ_FS_MINIMIZE <= 1のとき使用可能になります。

        diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/forward.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/forward.html index acbb4677..34f4f483 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/forward.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/forward.html @@ -60,7 +60,7 @@ FRESULT f_forward (

        対応情報

        -

        _USE_FORWARD == 1で、且つ_FS_TINY == 1のときに使用可能です。

        +

        _USE_FORWARD == 1のときに使用可能です。

        @@ -113,7 +113,7 @@ FRESULT play_file ( if (rc) return rc; /* 全てのデータが転送されるかエラーが発生するまで続ける */ - while (rc == FR_OK && !f_eof(&fil)) { + while (rc == FR_OK && !f_eof(&fil)) { /* ほかの処理... */ diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/getcwd.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/getcwd.html index 24e48446..e5e4a62d 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/getcwd.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/getcwd.html @@ -51,6 +51,7 @@ FRESULT f_getcwd (

        解説

        カレント ドライブのカレント ディレクトリのフル パス文字列を取得します。_VOLUMESが2以上のときは、論理ドライブ番号の付加されたパス名となります。

        +

        現リビジョン(R0.12)では、exFATボリューム上ではカレント ディレクトリを得ることが出来ません。常にルート ディレクトリを返します。

        diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/getfree.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/getfree.html index 91a14090..bb2a4527 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/getfree.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/getfree.html @@ -78,7 +78,7 @@ FRESULT f_getfree ( tot_sect = (fs->n_fatent - 2) * fs->csize; fre_sect = fre_clust * fs->csize; - /* ボリューム全体のサイズと空きのサイズを表示 (512バイト/セクタと仮定) */ + /* ボリュームのサイズと空きサイズを表示 (512バイト/セクタと仮定) */ printf("%10lu KiB total drive space.\n%10lu KiB available.\n", tot_sect / 2, fre_sect / 2); diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/getlabel.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/getlabel.html index bfcad0d6..da84632f 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/getlabel.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/getlabel.html @@ -29,7 +29,7 @@ FRESULT f_getlabel (
        path
        対象となる論理ドライブのパス名を示すヌル文字'\0'終端の文字列へのポインタを指定します。ヌル文字列の場合は、デフォルト ドライブを指定したことになります。
        label
        -
        ボリューム名を格納する配列へのポインタを指定します。少なくとも12要素のサイズが必要です。ボリューム名がない場合はヌル文字列が返されます。この情報が不要なときはヌル ポインタを指定してください。
        +
        ボリューム名を格納する配列へのポインタを指定します。_LFN_UNICODE == 0では少なくとも24要素、_LFN_UNICODE == 1では少なくとも12要素のサイズが必要です。ボリューム名がない場合はヌル文字列が返されます。この情報が不要なときはヌル ポインタを指定してください。
        vsn
        ボリューム シリアル番号を格納するDWORD型変数へのポインタを指定します。この情報が不要なときはヌル ポインタを指定してください。
        @@ -60,7 +60,7 @@ FRESULT f_getlabel (

        使用例

        -    char str[12];
        +    char str[24];
         
             /* デフォルト ドライブのボリューム名を得る */
             f_getlabel("", str, 0);
        diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/lseek.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/lseek.html
        index 88bb5ec0..00e4a958 100644
        --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/lseek.html
        +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/lseek.html
        @@ -16,8 +16,8 @@
         

        ファイルのリード/ライト ポインタを移動します。また、高速シーク機能使用時にはCLMT(後述)の作成にも使用します。

         FRESULT f_lseek (
        -  FIL* fp,    /* [IN] ファイル オブジェクト構造体へのポインタ */
        -  DWORD ofs   /* [IN] 移動先オフセット */
        +  FIL* fp,      /* [IN] ファイル オブジェクト構造体へのポインタ */
        +  FSIZE_t ofs   /* [IN] 移動先オフセット */
         );
         
        @@ -28,7 +28,7 @@ FRESULT f_lseek (
        fp
        対象となるファイル オブジェクト構造体へのポインタを指定します。
        ofs
        -
        移動先のオフセット(リード/ライト ポインタ)値。ファイル先頭からのオフセットをバイト単位で指定します。
        +
        移動先のオフセット(リード/ライト ポインタ)値。ファイル先頭からのオフセットをバイト単位で指定します。データ型FSIZE_tは、DWORD(32-bit)またはQWORD(64-bit)のエリアスで、exFATサポートの有無により切り替わります。
      @@ -48,7 +48,7 @@ FRESULT f_lseek (

      解説

      -

      ファイルのリード/ライト ポインタ(次に読み出し・書き込みされるバイトのオフセット)を移動します。オフセットの原点はファイル先頭です。書き込みモードでファイル サイズより大きな値を指定すると、そこまでファイル サイズが拡張され、拡張された部分のデータは未定義となります。データを遅延無く高速に書き込みたいときは、予めこの関数で必要なサイズまでファイル サイズを拡張しておくと良いでしょう。f_lseek関数が正常終了したあとは、リード/ライト ポインタが正しく移動したかチェックするべきです。リード/ライト ポインタが指定より小さいときは、次の原因が考えられます。

      +

      ファイルのリード/ライト ポインタ(次に読み出し・書き込みされるバイトのオフセット)を移動します。オフセットの原点はファイル先頭です。書き込みモードでファイル サイズより大きな値を指定すると、そこまでファイル サイズが拡張され、拡張された部分のデータは未定義となります。データを遅延無く高速に書き込みたいときは、予めこの関数で必要なサイズまでファイル サイズを拡張しておくと良いでしょう。ファイルに連続したデータ領域を割り当てる必要があるときは、f_expand関数を使用してください。f_lseek関数が正常終了したあとは、リード/ライト ポインタが正しく移動したかチェックするべきです。リード/ライト ポインタが指定より小さいときは、次の原因が考えられます。

      • 非書き込みモードまたは高速シーク モードのため、ファイル サイズでクリップされた。
      • ファイル拡張中にディスクが満杯になった。
      • @@ -122,7 +122,7 @@ FRESULT f_lseek (

        戻る

        diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/mkfs.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/mkfs.html index 20bee57a..b237e6bd 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/mkfs.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/mkfs.html @@ -13,12 +13,14 @@

        f_mkfs

        -

        論理ドライブ上にFATボリュームを作成します。

        +

        論理ドライブ上にFAT/exFATボリュームを作成(フォーマット)します。

         FRESULT f_mkfs (
        -  const TCHAR* path, /* [IN] 論理ドライブ番号 */
        -  BYTE  sfd,         /* [IN] 区画作成方法 */
        -  UINT  au           /* [IN] クラス タサイズ */
        +  const TCHAR* path,  /* [IN] 論理ドライブ番号 */
        +  BYTE  opt,          /* [IN] フォーマット オプション */
        +  DWORD au,           /* [IN] クラスタ サイズ */
        +  void* work,         /* [-]  ワーク エリア */
        +  UINT len            /* [IN] ワーク エリアのサイズ */
         );
         
        @@ -27,11 +29,15 @@ FRESULT f_mkfs (

        引数

        path
        -
        対象の論理ドライブを示すパス名を示すヌル文字'\0'終端の文字列へのポインタを指定します。ドライブ番号を含まない場合は、カレント ドライブを意味します。
        -
        sfd
        -
        パーテーション形式。(0(FDISK) または 1(SFD))
        +
        フォーマット対象の論理ドライブを示すパス名を示すヌル文字'\0'終端の文字列へのポインタを指定します。ドライブ番号を含まない場合は、デフォルト ドライブを意味します。論理ドライブにはf_mount関数でワークエリアが与えられている必要はありません。
        +
        opt
        +
        フォーマット オプション。FM_FAT, FM_FAT32, FM_EXFATの各フラグの組み合わせ(FM_ANYは、これらのOR値)で作成するFATボリュームのタイプを指定します。複数のタイプが指定された場合、その中のいずれかが自動選択されます。exFATが無効のときは、FM_EXFATは無視されます。FM_SFDフラグを指定すると、SFD形式(後述)でボリュームを配置します。
        au
        -
        クラスタ サイズをバイト数またはセクタ数で指定します。値が1~128の範囲場合は、セクタ数を示します。値が_MIN_SS以上の場合は、バイト数を示します。無効値(0または2の累乗でない値など)を指定した場合、ボリュームのサイズに応じたデフォルトのクラスタ サイズが自動選択されます。
        +
        クラスタ サイズをバイト単位で指定します。有効値は、セクタ サイズのN倍となります。Nは2の累乗で、FAT/FAT32ボリュームでは1~128、exFATボリュームでは1~32768です。0を指定した場合は、ボリュームのサイズと選択されたFATタイプに応じたデフォルトのクラスタ サイズが選択されます。
        +
        work
        +
        ワークエリアへのポインタを指定します。
        +
        len
        +
        ワークエリアのサイズをバイト単位で指定します。ワークエリアのサイズは少なくとも関連するドライブのセクタサイズは必要です。また、十分に大きなサイズを与えることにより、書き込みトランザクションの回数が減ってフォーマット時間を短縮できます。
      @@ -41,7 +47,6 @@ FRESULT f_mkfs ( FR_OK, FR_DISK_ERR, FR_NOT_READY, -FR_NOT_ENABLED, FR_MKFS_ABORTED, FR_INVALID_PARAMETER

      @@ -49,14 +54,13 @@ FRESULT f_mkfs (

      説明

      -

      物理ドライブ上にFATボリュームを作成(フォーマット)します。FDISK形式が指定された場合は、物理ドライブ全体を占める基本区画(パーテーション)が作成され、その中にFATボリュームが作成されます。SFD形式では、FATボリュームが物理ドライブの先頭セクタからベタで作成されます。

      -

      マルチ パーテーション機能(_MULTI_PARTITION)が有効で、かつフォーマット対象の論理ドライブが特定の区画(1~4)に結び付けられている場合は、その区画の中にFATボリュームが作成されます。sfdは無視され、その物理ドライブはこれに先立ち、f_fdisk関数または他のツールで適切に区画設定されている必要があります。

      -

      パーテーション形式には、FDISK形式とSFD形式の二通りあります。FDISK形式は、ハードディスク、MMC、SDC、CFC、U Diskなどで標準的に使用されます。FDISK形式では一台の物理ドライブ上に一つまたは複数の区画を作成することができます。区画管理情報はMBR(物理ドライブの先頭セクタ)に記録されます。SFD形式は単に何の分割も行わない形式で、ボリュームは物理ドライブの先頭セクタから開始します。SFD形式は、フロッピー ディスク、マイクロドライブ、光学ディスク、およびその他スーパー フロッピー メディアで標準的に使用されています。

      -

      FATタイプ(FAT12/FAT16/FAT32)は、そのボリューム上のクラスタ数によってのみ決定される決まり[FAT仕様書より]になっていて、それ以外の要因はありません。したがって、どのFATタイプになるかはボリューム サイズとクラスタ サイズに依存します。クラスタ サイズは大きくするほど性能が上がります。

      -

      クラスタ数がFATタイプの境界に近くなるときは、FR_MKFS_ABORTEDで関数が失敗する可能性があります。

      +

      exFAT以外のボリュームのFATタイプ(FAT12/FAT16/FAT32)は、そのボリューム上のクラスタ数によってのみ決定される決まり[FAT仕様書より]になっていて、それ以外の要因はありません。したがって、どのFATタイプになるかはボリューム サイズとクラスタ サイズに依存します。そのボリュームのサイズにおいて、指定されたFATタイプとクラスタ サイズの組み合わせが成立し得ないときは、関数はFR_MKFS_ABORTEDで失敗します。

      +

      クラスタとは、データ格納領域の管理の単位のことで、これを単位にファイルにデータ領域が割り当てられます。たとえば、クラスタ サイズが32768のときは、100バイトのファイルも32768バイトのスペースを消費することになります。このように、クラスタ サイズを大きくするほどボリュームの利用効率が悪くなりますが、その一方で読み書きの性能は上がります。クラスタ サイズによる利用効率と性能はトレード オフの関係にあります。GBクラスのストレージでは、極端に多くのファイルを扱わない限り32768バイト以上に(デフォルト指定ではそのようになる)しておくとよいでしょう。

      +

      パーテーション形式には、FDISK形式とSFD形式の二通りあります。FDISK形式は、ハードディスク、マルチメディアカード、SDカード、CFカード、USBメモリなどで標準的に使用されます。FDISK形式では一台の物理ドライブ上に一つまたは複数の区画を作成することができ、区画管理情報はMBR(物理ドライブの先頭セクタ)に記録されます。SFD形式は単に何の分割も行わない形式で、ボリュームは物理ドライブの先頭セクタから開始します。SFD形式は、フロッピー ディスク、マイクロドライブ、光学ディスク、およびその他スーパー フロッピー メディアで標準的に使用されています。システムによっては、FDISK形式またはSFD形式のどちらか一方のみをサポートし他方をサポートしません。

      +

      FM_SFDが指定されないときはFDISK形式となり、その物理ドライブ全体を占める1個の基本区画(パーテーション)が作成され、その中にFATボリュームが作成されます。FM_SFDが指定されたときはSFD形式となり、FATボリュームがその物理ドライブの先頭セクタからベタで作成されます。

      +

      マルチ パーテーション機能(_MULTI_PARTITION)により、その論理ドライブが特定の区画(1~4)に結び付けられている場合は、その区画の中にFATボリュームが作成されます。FM_SFDの指定は無視され、その物理ドライブはこれに先立ち、f_fdisk関数または他のツールで適切に区画設定されている必要があります。

      -

      対応情報

      _FS_READONLY == 0で、且つ_USE_MKFS == 1のとき使用可能です。

      @@ -69,19 +73,20 @@ FRESULT f_mkfs ( /* Format default drive and create a file */ int main (void) { - FATFS fs; /* File system object (volume work area) */ - FIL fil; /* File object */ - FRESULT res; /* API result code */ - UINT bw; /* Bytes written */ + FATFS fs; /* File system object */ + FIL fil; /* File object */ + FRESULT res; /* API result code */ + UINT bw; /* Bytes written */ + BYTE work[_MAX_SS]; /* Work area (larger is better for process time) */ - /* Register work area (do not care about error) */ - f_mount(&fs, "", 0); - - /* Create FAT volume with default cluster size */ - res = f_mkfs("", 0, 0); + /* Create FAT volume */ + res = f_mkfs("", FM_ANY, 0, work, sizeof work); if (res) ... + /* Register work area */ + f_mount(&fs, "", 0); + /* Create a file as new */ res = f_open(&fil, "hello.txt", FA_CREATE_NEW | FA_WRITE); if (res) ... @@ -93,15 +98,14 @@ int main (void) /* Close the file */ f_close(&fil); - /* Unregister work area */ - f_mount(0, "", 0); + ...
      diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/mount.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/mount.html index 239ae20c..d7906bec 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/mount.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/mount.html @@ -18,7 +18,7 @@ FRESULT f_mount ( FATFS* fs, /* [IN] ファイル システム オブジェクト */ const TCHAR* path, /* [IN] 論理ドライブ番号 */ - BYTE opt /* [IN] オプション */ + BYTE opt /* [IN] 動作オプション */ );
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/open.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/open.html index 016341de..9fb76427 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/open.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/open.html @@ -37,9 +37,10 @@ FRESULT f_open ( FA_READ読み出しモードで開きます。読み書きする場合はFA_WRITEと共に指定します。 FA_WRITE書き込みモードで開きます。読み書きする場合はFA_READと共に指定します。 FA_OPEN_EXISTING既存のファイルを開きます。ファイルが無いときはエラーになります。(デフォルト) -FA_OPEN_ALWAYS既存のファイルを開きます。ファイルが無いときはファイルを作成します。追記の場合は、この方法でオープンした後、f_lseek関数でファイルの最後尾に移動してください。 FA_CREATE_NEWファイルを作成します。同名のファイルがある場合は、FR_EXISTで失敗します。 FA_CREATE_ALWAYSファイルを作成します。同名のファイルがある場合は、サイズを0にしてから開きます。 +FA_OPEN_ALWAYS既存のファイルを開きます。ファイルが無いときはファイルを作成します。 +FA_OPEN_APPENDFA_OPEN_ALWAYSと同じですが、リード/ライト ポインタはファイルの最後尾にセットされます。 @@ -75,13 +76,13 @@ FRESULT f_open (

    解説

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

    既に開かれているファイルを開く必要がある場合は、多重アクセス制御を参照してください。しかし、一つのファイルに対する書き込みモードを含む重複オープンは常に禁止です。

    -

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

    +

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

    対応情報

    -

    全ての構成で使用可能です。_FS_READONLY == 1のときは、FA_WRITE, FA_CREATE_ALWAYS, FA_CREATE_NEW, FA_OPEN_ALWAYSの各フラグはサポートされません。

    +

    全ての構成で使用可能です。_FS_READONLY == 1のときは、FA_READFA_OPEN_EXISTING以外の各フラグはサポートされません。

    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/rc.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/rc.html index 37bd11f4..561f3846 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/rc.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/rc.html @@ -37,11 +37,11 @@
    そのオブジェクトに対する操作の拒否。原因としては次のようなことが考えられます。
    • 書き込み禁止属性(AM_RDO)を持つファイルを書き込みモードで開こうとした。
    • -
    • 書き込み禁止属性を持つファイルやディレクトリを削除しようとした。
    • +
    • 書き込み禁止属性を持つオブジェクトを削除しようとした。
    • 空でないディレクトリまたはカレント ディレクトリを削除しようとした。
    • FA_READフラグを付けずに開いたファイルに対して読み出しを行った。
    • -
    • FA_WRITEフラグを付けずに開いたファイルに対して書き込みまたはそれに類する操作を行った。
    • -
    • ボリュームまたはディレクトリ テーブルが満杯でファイルやディレクトリを作成できなかった。
    • +
    • FA_WRITEフラグを付けずに開いたファイルに対して変更を加えようとした。
    • +
    • ボリュームまたは静的ディレクトリが満杯でオブジェクトの新規作成ができなかった。
    FR_EXIST
    @@ -65,8 +65,9 @@
    FR_MKFS_ABORTED
    f_mkfs関数の処理が開始前に中断された。原因としては次のようなことが考えられます。
      -
    • ボリュームが小さすぎる。
    • -
    • FATタイプの計算に矛盾が見つかった。クラスタ数がFATタイプの境界付近になるときに発生する場合があります。
    • +
    • 指定されたパラメータでのフォーマットが不可能。
    • +
    • ボリュームのサイズが小さすぎる。
    • +
    • 与えられたワークエリアが小さすぎる。
    • その論理ドライブに対応する区画が見つからなかった。(関連オプション: _MULTI_PARTITION)
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/readdir.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/readdir.html index 2480a6b5..5305b0a3 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/readdir.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/readdir.html @@ -28,7 +28,7 @@ FRESULT f_readdir (
    dp
    f_opendir関数で作成された有効なディレクトリ オブジェクトへのポインタを指定します。
    fno
    -
    読み出したディレクトリ項目を格納するファイル情報構造体へのポインタを指定します。
    +
    読み出したディレクトリ項目を格納するファイル情報構造体へのポインタ、またはヌル ポインタを指定します。
    @@ -48,17 +48,16 @@ FRESULT f_readdir (

    解説

    -

    ディレクトリの項目(ファイルおよびサブ ディレクトリ)を順次読み出します。この関数を繰り返し実行することによりそのディレクトリの全ての項目を読み出すことができます。得られるファイル情報の詳細については FILINFO構造体を参照してください。全ての項目が読み出され、読み出す項目がもう無いときは、fno->fname[]にヌル文字列が返されます。fnoにヌル ポインタを指定すると、そのディレクトリのリード インデックスを先頭に巻き戻します。また、この関数は次に示すように関連する構成オプションにより動作が変わります。

    -

    ドット エントリ(".""..")は、相対パスが有効なとき(_FS_RPATH >= 1)にのみ出力に現れます。

    -

    LFN機能が有効な時は、この関数の呼び出しに先立ってfno->lfnamefno->lfsizeが有効な値で初期化されていなければなりません。lfnameはLFNを格納するバッファを示し、lfsizeはそのバッファの要素数を示します。LFNを読み出す必要がないときは、lfnameにヌル ポインタをセットしてください。次の条件に一つでも該当する場合は、LFN格納バッファにヌル文字列が返されます。

    +

    ディレクトリの項目(ファイルおよびサブ ディレクトリ)の情報を順次読み出します。この関数を繰り返し実行することによりそのディレクトリの全ての項目を読み出すことができます。得られるファイル情報の詳細については FILINFO構造体を参照してください。全ての項目が読み出され、読み出す項目がもう無いときは、fno->fname[]にヌル文字列が返されます。fnoにヌル ポインタを指定すると、そのディレクトリのリード インデックスを先頭に巻き戻します。サブ ディレクトリのドット エントリ(".""..")は、出力に現れません。

    +

    LFN構成では、altname[]が新たに定義され、そのオブジェクトの短いファイル名がストアされます。次の条件のときは長いファイル名を返せないのでfname[]に短いファイル名がストアされ、altname[]はヌル文字列になります。

      -
    • その項目にLFNが存在しない。このとき、fname[]に英小文字が含まれる場合があります。
    • -
    • LFNの長さに対してLFN格納バッファまたはLFN操作バッファのサイズが不十分。
    • -
    • LFNに現在のOEMコードで表現できない文字が含まれている。(非Unicode構成のとき)
    • +
    • オブジェクトが長いファイル名を持っていない。(exFATボリュームでは該当せず)
    • +
    • _MAX_LFNの設定がその長いファイル名の長さに対して不十分 (_MAX_LFN == 255では該当せず)
    • +
    • 長いファイル名にANSI/OEMコードに無い文字が含まれている。(_LFN_UNICODE == 1では該当せず)
    +

    exFATボリュームのディレクトリを読み出すとき、構成によっては問題が発生します。exFATでは短いファイル名がサポートされません。つまり、上記の条件のとき代わりに返すファイル名が無いということです。このような場合はfname[]に"?"が返され、そのオブジェクトにアクセスできないことを示します。この問題を避けるには、FatFsの構成を_LFN_UNICODE = 1および_MAX_LFN = 255として長いファイル名に完全対応とする必要があります。

    -

    対応情報

    _FS_MINIMIZE <= 1のときに使用可能です。

    @@ -68,44 +67,50 @@ FRESULT f_readdir (

    使用例

    +FATFS fs;
    +char buff[256];
    +
     FRESULT scan_files (
         char* path        /* 開始ノード (ワークエリアとしても使用) */
     )
     {
         FRESULT res;
    -    FILINFO fno;
         DIR dir;
    -    int i;
    -    char *fn;   /* 非Unicode構成を想定 */
    -#if _USE_LFN
    -    static char lfn[_MAX_LFN + 1];
    -    fno.lfname = lfn;
    -    fno.lfsize = sizeof lfn;
    -#endif
    +    UINT i;
    +    static FILINFO fno;
     
     
         res = f_opendir(&dir, path);                       /* ディレクトリを開く */
         if (res == FR_OK) {
    -        i = strlen(path);
             for (;;) {
                 res = f_readdir(&dir, &fno);                   /* ディレクトリ項目を1個読み出す */
                 if (res != FR_OK || fno.fname[0] == 0) break;  /* エラーまたは項目無しのときは抜ける */
    -            if (fno.fname[0] == '.') continue;             /* ドットエントリは無視 */
    -#if _USE_LFN
    -            fn = *fno.lfname ? fno.lfname : fno.fname;
    -#else
    -            fn = fno.fname;
    -#endif
                 if (fno.fattrib & AM_DIR) {                    /* ディレクトリ */
    -                sprintf(&path[i], "/%s", fn);
    -                res = scan_files(path);
    -                path[i] = 0;
    +                i = strlen(path);
    +                sprintf(&path[i], "/%s", fno.fname);
    +                res = scan_files(path);                    /* 一つ下へ */
                     if (res != FR_OK) break;
    +                path[i] = 0;
                 } else {                                       /* ファイル */
    -                printf("%s/%s\n", path, fn);
    +                printf("%s/%s\n", path, fno.fname);
                 }
             }
    -        f_closedir(&dir);
    +        f_closedir(&dir)
    +    }
    +
    +    return res;
    +}
    +
    +
    +int main (void)
    +{
    +    FRESULT res;
    +
    +
    +    res = f_mount(&fs, "", 1);
    +    if (res == FR_OK) {
    +        strcpy(buff, "/");
    +        res = scan_files(buff);
         }
     
         return res;
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/sdir.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/sdir.html
    index 4ee3e53a..0ac0b0e5 100644
    --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/sdir.html
    +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/sdir.html
    @@ -16,20 +16,15 @@
     

    DIR構造体は、f_opendir/f_readdir/f_findfirst/f_findnext関数のワーク エリアとして使用されます。アプリケーションは、この構造体のメンバを書き換えてはなりません。

     typedef struct {
    -    FATFS*  fs;        /* 親ファイル システム オブジェクトへのポインタ */
    -    WORD    id;        /* 親ファイル システム オブジェクトのマウントID */
    -    WORD    index;     /* 次に検索開始するディレクトリ インデックス番号 */
    -    DWORD   sclust;    /* テーブル開始クラスタ (0:ルート) */
    +    _FDID   obj;       /* オブジェクトID */
    +    DOWRD   dptr;      /* 現在のread/writeオフセット */
         DWORD   clust;     /* 現在のクラスタ番号 */
         DWORD   sect;      /* 現在のセクタ番号 */
         BYTE*   dir;       /* 現在のSFNエントリ(Win[]内)へのポインタ */
         BYTE*   fn;        /* SFNバッファへのポインタ (in/out) {file[8],ext[3],status[1]} */
    -#if _FS_LOCK
    -    UINT    lockid;    /* サブ ディレクトリ ロックID (0:ルート) */
    -#endif
     #if _USE_LFN
    +    DWORD   blk_ofs;   /* 現在のエントリブロックの先頭 (0xFFFFFFFF:無効) */
         WCHAR*  lfn;       /* LFNバッファへのポインタ (in/out) */
    -    WORD    lfn_idx;   /* LFNエントリの先頭インデックス (0xFFFF:無効) */
     #endif
     #if _USE_FIND
         const TCHAR*  pat; /* マッチング パターンへのポインタ */
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/setlabel.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/setlabel.html
    index 26dce4b6..d578fa18 100644
    --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/setlabel.html
    +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/setlabel.html
    @@ -49,11 +49,12 @@ FRESULT f_setlabel (
     
     

    解説

    -

    文字列の先頭にドライブ番号を含む場合は、その論理ドライブに対して設定されます。含まない場合は、デフォルト ドライブに設定されます。ボリューム ラベルを削除するときは、ヌル文字列を指定します。ボリューム ラベルのフォーマットは、ファイル名(SFN)とほぼ同じですが、次の点が異なります。

    +

    文字列の先頭にドライブ番号を含む場合は、その論理ドライブに対して設定されます。含まない場合は、デフォルト ドライブに設定されます。ボリューム ラベルを削除するときは、ヌル文字列を指定します。FATボリューム上では、ボリューム ラベルのフォーマットは、ファイル名とほぼ同じですが、次の点が異なります。

      -
    • OEMコード換算で11バイト以下。ボリューム ラベルにはLFN拡張は適用されません。
    • +
    • 任意の位置にスペースを置くことができる。ただし、FATボリュームではトレーリング スペースは除去される。
    • ピリオドを含むことはできない。
    • -
    • 任意の位置にスペースを置くことができる。ただし、最後尾となるスペースは除去される。
    • +
    • FATボリュームでは、OEMコード換算で11バイト以下。
    • +
    • exFATボリュームでは、11文字以下で、大文字小文字は保持される。

    【補足】 標準システム(Windows)では\xE5で始まるボーリューム ラベル(CP932なら「薔薇」など)の扱いに問題があります。このため、この関数ではそのような名前は無効として処理しています。

    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/sfatfs.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/sfatfs.html index fd7405dd..12e54e16 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/sfatfs.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/sfatfs.html @@ -17,17 +17,20 @@
     typedef struct {
    -    BYTE    fs_type;      /* FATタイプ (0:無効, FS_FAT12, FS_FAT16 or FS_FAT32) */
    +    BYTE    fs_type;      /* ファイル システム (0, FS_FAT12, FS_FAT16, FS_FAT32 or FS_EXFAT) */
         BYTE    drv;          /* 物理ドライブ番号 */
    -    BYTE    csize;        /* クラスタ当たりのセクタ数 (1,2,4,8,...,128) */
         BYTE    n_fats;       /* FATの多重化数 (1,2) */
         BYTE    wflag;        /* win[]ダーティ フラグ */
         BYTE    fsi_flag;     /* FSINFOフラグ (b7:Disabled, b0:Dirty) */
         WORD    id;           /* ファイル システム マウントID */
         WORD    n_rootdir;    /* ルート ディレクトリのエントリ数 (FAT12/16) */
    +    WORD    csize;        /* クラスタ当たりのセクタ数 */
     #if _MAX_SS != _MIN_SS
         WORD    ssize;        /* セクタ サイズ (512, 1024, 2048 or 4096) */
     #endif
    +#if _FS_EXFAT
    +    BYTE*   dirbuf;       /* ディレクトリ エントリ ブロック操作バッファへのポインタ */
    +#endif
     #if _FS_REENTRANT
         _SYNC_t sobj;         /* 同期オブジェクトID */
     #endif
    @@ -37,6 +40,11 @@
     #endif
     #if _FS_RPATH
         DWORD   cdir;         /* カレント ディレクトリのクラスタ番号 (0:ルート) */
    +#if _FS_EXFAT
    +    DWORD   cdc_scl;      /* カレント ディレクトリを含むディレクトリの開始クラスタ番号 (cdir == 0では無効) */
    +    DWORD   cdc_size;     /* b31-b8:カレント ディレクトリを含むディレクトリのサイズ, b7-b0: チェーン ステータス */
    +    DWORD   cdc_ofs;      /* カレント ディレクトリを含むディレクトリ内の位置 (cdir == 0では無効) */
    +#endif
     #endif
         DWORD   n_fatent;     /* FATエントリ数 (総クラスタ数 + 2) */
         DWORD   fsize;        /* FAT 1個のセクタ数 */
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/sfile.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/sfile.html
    index f5f70256..da6bc6a2 100644
    --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/sfile.html
    +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/sfile.html
    @@ -17,14 +17,11 @@
     
     
     typedef struct {
    -    FATFS*  fs;           /* 親ファイル システム オブジェクトへのポインタ */
    -    WORD    id;           /* 親ファイル システム オブジェクトのマウントID */
    +    _FDID   obj;          /* オブジェクトID */
         BYTE    flag;         /* ファイル ステータス フラグ */
         BYTE    err;          /* エラー中断フラグ */
    -    DWORD   fptr;         /* ファイル読み書きポインタ (ファイル先頭からのバイト オフセット) */
    -    DWORD   fsize;        /* ファイル サイズ(バイト単位) */
    -    DWORD   sclust;       /* ファイル開始クラスタ番号 (0:割り当て無し) */
    -    DWORD   clust;        /* 現在のクラスタ (fptrが0のときは無効、fptrがクラスタ境界上のときは前のクラスタ) */
    +    FSIZE_t fptr;         /* ファイル読み書きポインタ (ファイル先頭からのバイト オフセット) */
    +    DWORD   clust;        /* 現在のクラスタ (fptrがクラスタ境界上のときは前のクラスタ、fptrが0のときは無効) */
         DWORD   dsect;        /* 現在のデータ セクタ */
     #if !_FS_READONLY
         DWORD   dir_sect;     /* このファイルのディレクトリ エントリのあるセクタ */
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/sfileinfo.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/sfileinfo.html
    index 108e332e..f6694109 100644
    --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/sfileinfo.html
    +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/sfileinfo.html
    @@ -16,14 +16,15 @@
     

    FILINFO構造体は、f_stat/f_readdir/f_findfirst/f_findnext関数で返されるオブジェクトに関する情報を保持します。

     typedef struct {
    -    DWORD fsize;     /* ファイル サイズ */
    -    WORD fdate;      /* 最後に更新された日付 */
    -    WORD ftime;      /* 最後に更新された時刻  */
    -    BYTE fattrib;    /* アトリビュート */
    -    TCHAR fname[13]; /* 短いファイル名 (8.3フォーマット) */
    -#if _USE_LFN
    -    TCHAR* lfname;   /* 長いファイル名のバッファへのポインタ */
    -    int lfsize;      /* 長いファイル名のバッファのサイズ [文字数] */
    +    FSIZE_t fsize;               /* ファイル サイズ */
    +    WORD    fdate;               /* 最後に更新された日付 */
    +    WORD    ftime;               /* 最後に更新された時刻  */
    +    BYTE    fattrib;             /* アトリビュート */
    +#if _USE_LFN != 0
    +    TCHAR   altname[13];         /* 代替ファイル名 */
    +    TCHAR   fname[_MAX_LFN + 1]; /* 主ファイル名 */
    +#else
    +    TCHAR   fname[13];           /* ファイル名 */
     #endif
     } FILINFO;
     
    @@ -32,7 +33,7 @@

    メンバ

    fsize
    -
    ファイルのバイト単位のサイズが格納されます。ディレクトリの場合は常に0です。
    +
    ファイルのバイト単位のサイズが格納されます。ディレクトリの場合は常に0です。データ型FSIZE_tは、DWORD(32-bit)またはQWORD(64-bit)のエリアスで、exFATサポートの有無により切り替わります。
    fdate
    ファイルの変更された日付、またはディレクトリの作成された日付が格納されます。
    @@ -58,11 +59,9 @@
    fattrib
    属性フラグが格納されます。フラグはAM_DIR, AM_RDO, AM_HID, AM_SYS, AM_ARCの組み合わせとなります。
    fname[]
    -
    8.3形式の名前(SFN)が'\0'で終わる文字列として格納されます。非LFN構成のときは、常に大文字で返されます。LFN構成のときは、文字列に含まれるASCII英字が小文字になる場合があります。
    -
    lfname
    -
    長いファイル名(LFN)を格納するバッファへのポインタ。このメンバは、この構造体を使用する前にアプリケーションにより初期化されなければなりません。NULLが設定されるとLFNは返されません。非LFN構成のときはこのメンバは存在しません。
    -
    lfsize
    -
    長いファイル名を格納するバッファのサイズ(要素数)。このメンバは、この構造体を使用する前にアプリケーションにより初期化されなければなりません。非LFN構成のときはこのメンバは存在しません。
    +
    オブジェクト名が'\0'で終わる文字列として格納されます。読み出すべき項目が無いときは、ヌル文字列が返され、この構造体が無効であることを示します。
    +
    altname[]
    +
    代替ファイル名があるときは、それが'\0'で終わる文字列として格納されます。非LFN構成のときは、このメンバはありません。

    戻る

    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/size.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/size.html index 207b4f9e..17d4adf3 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/size.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/size.html @@ -15,7 +15,7 @@

    f_size

    ファイルのサイズを取得します。

    -DWORD f_size (
    +FSIZE_t f_size (
       FIL* fp   /* [IN] ファイル オブジェクト */
     );
     
    @@ -41,7 +41,7 @@ DWORD f_size (

    解説

    この関数は、現リビジョンではマクロとして実装されています。ファイル オブジェクトの正当性チェックや排他制御は行いません。

    -#define f_size(fp) ((fp)->fsize)
    +#define f_size(fp) ((fp)->obj.objsize)
     
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/stat.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/stat.html index 6e89c3ee..deba89b3 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/stat.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/stat.html @@ -54,8 +54,7 @@ FRESULT f_stat (

    解説

    -

    指定されたファイルまたはサブ ディレクトリの存在を調べます。存在しない場合は、FR_NO_FILEが帰ります。存在する場合はFR_OKが帰り、ファイル情報構造体にそれ関する情報(サイズ、タイムスタンプ、属性および短いファイル名)がストアされます。

    -

    LFN構成のときは、ファイル情報構造体を使う前にfno.lfnameをヌルに設定しておく必要があります。

    +

    指定されたファイルまたはサブ ディレクトリの存在を調べます。存在しない場合は、FR_NO_FILEが帰ります。存在する場合はFR_OKが帰り、それ関する情報(サイズ、タイムスタンプおよび属性)がファイル情報構造体にストアされます。

    @@ -74,23 +73,20 @@ FRESULT f_stat ( printf("Test for 'file.txt'...\n"); -#if _USE_LFN - fno.lfname = 0; -#endif fr = f_stat("file.txt", &fno); switch (fr) { case FR_OK: - printf("Size: %u\n", fno.fsize); + printf("Size: %lu\n", fno.fsize); printf("Timestamp: %u/%02u/%02u, %02u:%02u\n", (fno.fdate >> 9) + 1980, fno.fdate >> 5 & 15, fno.fdate & 31, fno.ftime >> 11, fno.ftime >> 5 & 63); printf("Attributes: %c%c%c%c%c\n", - (fno.fattrib & AM_DIR) ? 'D' : '-', - (fno.fattrib & AM_RDO) ? 'R' : '-', - (fno.fattrib & AM_HID) ? 'H' : '-', - (fno.fattrib & AM_SYS) ? 'S' : '-', - (fno.fattrib & AM_ARC) ? 'A' : '-'); + (fno.fattrib & AM_DIR) ? 'D' : '-', + (fno.fattrib & AM_RDO) ? 'R' : '-', + (fno.fattrib & AM_HID) ? 'H' : '-', + (fno.fattrib & AM_SYS) ? 'S' : '-', + (fno.fattrib & AM_ARC) ? 'A' : '-'); break; case FR_NO_FILE: diff --git a/firmware/chibios-portapack/ext/fatfs/doc/ja/tell.html b/firmware/chibios-portapack/ext/fatfs/doc/ja/tell.html index c0194447..48628d3c 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/ja/tell.html +++ b/firmware/chibios-portapack/ext/fatfs/doc/ja/tell.html @@ -15,7 +15,7 @@

    f_tell

    現在のリード/ライト ポインタを取得します。

    -DWORD f_tell (
    +FSIZE_t f_tell (
       FIL* fp   /* [IN] ファイル オブジェクト */
     );
     
    diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/app1.c b/firmware/chibios-portapack/ext/fatfs/doc/res/app1.c similarity index 90% rename from firmware/chibios-portapack/ext/fatfs/doc/img/app1.c rename to firmware/chibios-portapack/ext/fatfs/doc/res/app1.c index c7e690be..85ce9e25 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/img/app1.c +++ b/firmware/chibios-portapack/ext/fatfs/doc/res/app1.c @@ -1,5 +1,6 @@ /*------------------------------------------------------------/ / Open or create a file in append mode +/ (This function was sperseded by FA_OPEN_APPEND at FatFs R0.12a) /------------------------------------------------------------*/ FRESULT open_append ( diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/app2.c b/firmware/chibios-portapack/ext/fatfs/doc/res/app2.c similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/app2.c rename to firmware/chibios-portapack/ext/fatfs/doc/res/app2.c diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/app3.c b/firmware/chibios-portapack/ext/fatfs/doc/res/app3.c similarity index 94% rename from firmware/chibios-portapack/ext/fatfs/doc/img/app3.c rename to firmware/chibios-portapack/ext/fatfs/doc/res/app3.c index 6733ee61..c4cfcf5f 100644 --- a/firmware/chibios-portapack/ext/fatfs/doc/img/app3.c +++ b/firmware/chibios-portapack/ext/fatfs/doc/res/app3.c @@ -6,7 +6,8 @@ / If the file has been opened without FA_WRITE flag, it only checks if / the file is contiguous and returns the resulut. /-----------------------------------------------------------------------/ -/ This function can work with FatFs R0.09 to R0.11a. +/ This function can work with FatFs R0.09 - R0.11a. +/ It is incompatible with R0.12+. Use f_expand function instead. /----------------------------------------------------------------------*/ /* Declarations of FatFs internal functions accessible from applications. diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/app4.c b/firmware/chibios-portapack/ext/fatfs/doc/res/app4.c similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/app4.c rename to firmware/chibios-portapack/ext/fatfs/doc/res/app4.c diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f1.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f1.png similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/f1.png rename to firmware/chibios-portapack/ext/fatfs/doc/res/f1.png diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f2.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f2.png similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/f2.png rename to firmware/chibios-portapack/ext/fatfs/doc/res/f2.png diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f3.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f3.png similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/f3.png rename to firmware/chibios-portapack/ext/fatfs/doc/res/f3.png diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f4.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f4.png similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/f4.png rename to firmware/chibios-portapack/ext/fatfs/doc/res/f4.png diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f5.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f5.png similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/f5.png rename to firmware/chibios-portapack/ext/fatfs/doc/res/f5.png diff --git a/firmware/chibios-portapack/ext/fatfs/doc/img/f6.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f6.png similarity index 100% rename from firmware/chibios-portapack/ext/fatfs/doc/img/f6.png rename to firmware/chibios-portapack/ext/fatfs/doc/res/f6.png diff --git a/firmware/chibios-portapack/ext/fatfs/doc/res/f7.png b/firmware/chibios-portapack/ext/fatfs/doc/res/f7.png new file mode 100644 index 0000000000000000000000000000000000000000..dee738615053e9dade2641ca6e5a9b5edb10c36e GIT binary patch literal 30461 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 literal 0 HcmV?d00001 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/res/funcs.png b/firmware/chibios-portapack/ext/fatfs/doc/res/funcs.png new file mode 100644 index 0000000000000000000000000000000000000000..022cd74ba1fbb5c69e45861eb6031634ed7686f3 GIT binary patch literal 22722 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

    ibJ;TP@*J|1x#UR7G?jI_XxGEVt3<4A+z4 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

    7BO2aVs==>?9s$P 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 pM30I7k5#9ow;*ozbr3U6T{ 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�(M=sVE_l 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�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�jL30GR^`2~aCp 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

    j-U#BHRI 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
    Aafug0h)yp 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≠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 YE)4k$$zV66f@6R*_gIkO|0*Q=0eBx1`Tzg` literal 0 HcmV?d00001 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/res/modules.png b/firmware/chibios-portapack/ext/fatfs/doc/res/modules.png new file mode 100644 index 0000000000000000000000000000000000000000..b1ab987275a0b9b3583b3af5983416b82802e24f GIT binary patch literal 17469 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 A>Hq)$ literal 0 HcmV?d00001 diff --git a/firmware/chibios-portapack/ext/fatfs/doc/res/rwtest1.png b/firmware/chibios-portapack/ext/fatfs/doc/res/rwtest1.png new file mode 100644 index 0000000000000000000000000000000000000000..af51c5f9cf13ff09c65ba7fe0a8dc973dd476bcb GIT binary patch literal 27860 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 = (BYTE)(res); LEAVE_FF(fs, res); } + + /* Reentrancy related */ #if _FS_REENTRANT #if _USE_LFN == 1 @@ -43,7 +48,6 @@ #define LEAVE_FF(fs, res) return res #endif -#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } /* Definitions of sector size */ @@ -57,7 +61,7 @@ #endif -/* Timestamp feature */ +/* Timestamp */ #if _FS_NORTC == 1 #if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 #error Invalid _FS_NORTC settings @@ -68,15 +72,15 @@ #endif -/* File access control feature */ -#if _FS_LOCK +/* File lock controls */ +#if _FS_LOCK != 0 #if _FS_READONLY #error _FS_LOCK must be 0 at read-only configuration #endif typedef struct { FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, directory (0:root) */ - WORD idx; /* Object ID 3, directory index */ + DWORD ofs; /* Object ID 3, directory offset */ WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif @@ -309,8 +313,8 @@ typedef struct { 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ -#if _USE_LFN -#error Cannot use LFN feature without valid code page. +#if _USE_LFN != 0 +#error Cannot enable LFN without valid code page. #endif #define _DF1S 0 @@ -325,7 +329,7 @@ typedef struct { #define IsLower(c) (((c)>='a')&&((c)<='z')) #define IsDigit(c) (((c)>='0')&&((c)<='9')) -#if _DF1S /* Code page is DBCS */ +#if _DF1S != 0 /* Code page is DBCS */ #ifdef _DF2S /* Two 1st byte areas */ #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) @@ -347,6 +351,18 @@ typedef struct { #endif /* _DF1S */ +/* File attribute bits (internal use) */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* File access control and file status flags (internal use) */ +#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ +#define FA_MODIFIED 0x40 /* File has been modified */ +#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ + + /* Name status flags */ #define NSFLAG 11 /* Index of name status byte in fn[] */ #define NS_LOSS 0x01 /* Out of 8.3 format */ @@ -355,92 +371,154 @@ typedef struct { #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ +#define NS_NOLFN 0x40 /* Do not find LFN */ +#define NS_NONAME 0x80 /* Not followed */ -/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ -#define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */ -#define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */ +/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */ +#define MAX_FAT12 0xFF5 /* Maximum number of FAT12 clusters */ +#define MAX_FAT16 0xFFF5 /* Maximum number of FAT16 clusters */ +#define MAX_FAT32 0xFFFFFF5 /* Maximum number of FAT32 clusters */ +#define MAX_EXFAT 0x7FFFFFFD /* Maximum number of exFAT clusters (limited by implementation) */ +#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ /* FatFs refers the members in the FAT structures as byte array instead of / structure members because the structure is not binary compatible between / different platforms */ -#define BS_jmpBoot 0 /* x86 jump instruction (3) */ -#define BS_OEMName 3 /* OEM name (8) */ -#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ -#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ -#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ -#define BPB_NumFATs 16 /* Number of FAT copies (1) */ -#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */ -#define BPB_TotSec16 19 /* Volume size [sector] (2) */ -#define BPB_Media 21 /* Media descriptor (1) */ -#define BPB_FATSz16 22 /* FAT size [sector] (2) */ -#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ -#define BPB_NumHeads 26 /* Number of heads (2) */ -#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ -#define BPB_TotSec32 32 /* Volume size [sector] (4) */ -#define BS_DrvNum 36 /* Physical drive number (1) */ -#define BS_NTres 37 /* Error flag (1) */ -#define BS_BootSig 38 /* Extended boot signature (1) */ -#define BS_VolID 39 /* Volume serial number (4) */ -#define BS_VolLab 43 /* Volume label (8) */ -#define BS_FilSysType 54 /* File system type (1) */ -#define BPB_FATSz32 36 /* FAT size [sector] (4) */ -#define BPB_ExtFlags 40 /* Extended flags (2) */ -#define BPB_FSVer 42 /* File system version (2) */ -#define BPB_RootClus 44 /* Root directory first cluster (4) */ -#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ -#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ -#define BS_DrvNum32 64 /* Physical drive number (1) */ -#define BS_NTres32 65 /* Error flag (1) */ -#define BS_BootSig32 66 /* Extended boot signature (1) */ -#define BS_VolID32 67 /* Volume serial number (4) */ -#define BS_VolLab32 71 /* Volume label (8) */ -#define BS_FilSysType32 82 /* File system type (1) */ -#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ -#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ -#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ -#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ -#define MBR_Table 446 /* MBR: Partition table offset (2) */ -#define SZ_PTE 16 /* MBR: Size of a partition table entry */ -#define BS_55AA 510 /* Signature word (2) */ +#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_OEMName 3 /* OEM name (8-byte) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ +#define BPB_NumFATs 16 /* Number of FATs (BYTE) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ +#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ +#define BPB_Media 21 /* Media descriptor (BYTE) */ +#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ +#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ +#define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ +#define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ +#define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ +#define BS_NTres 37 /* Error flag (BYTE) */ +#define BS_BootSig 38 /* Extended boot signature (BYTE) */ +#define BS_VolID 39 /* Volume serial number (DWORD) */ +#define BS_VolLab 43 /* Volume label string (8-byte) */ +#define BS_FilSysType 54 /* File system type string (8-byte) */ +#define BS_BootCode 62 /* Boot code (448-byte) */ -#define DIR_Name 0 /* Short file name (11) */ -#define DIR_Attr 11 /* Attribute (1) */ -#define DIR_NTres 12 /* Lower case flag (1) */ -#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ -#define DIR_CrtTime 14 /* Created time (2) */ -#define DIR_CrtDate 16 /* Created date (2) */ -#define DIR_LstAccDate 18 /* Last accessed date (2) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ -#define DIR_WrtTime 22 /* Modified time (2) */ -#define DIR_WrtDate 24 /* Modified date (2) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ -#define DIR_FileSize 28 /* File size (4) */ -#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ -#define LDIR_Attr 11 /* LFN attribute (1) */ -#define LDIR_Type 12 /* LFN type (1) */ -#define LDIR_Chksum 13 /* Checksum of corresponding SFN entry */ -#define LDIR_FstClusLO 26 /* Must be zero (0) */ -#define SZ_DIRE 32 /* Size of a directory entry */ +#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ +#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ +#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ +#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ +#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ +#define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ +#define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ +#define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ +#define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ +#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ +#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ +#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ + +#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ +#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ +#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ +#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ +#define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ +#define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ +#define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ +#define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ +#define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ +#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ +#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ + +#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ +#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ +#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ +#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ + +#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define PTE_Boot 0 /* MBR PTE: Boot indicator */ +#define PTE_StHead 1 /* MBR PTE: Start head */ +#define PTE_StSec 2 /* MBR PTE: Start sector */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_System 4 /* MBR PTE: System ID */ +#define PTE_EdHead 5 /* MBR PTE: End head */ +#define PTE_EdSec 6 /* MBR PTE: End sector */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_StLba 8 /* MBR PTE: Start in LBA */ +#define PTE_SizLba 12 /* MBR PTE: Size in LBA */ + +#define BS_55AA 510 /* Signature word (WORD) */ + +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN entry order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN type (BYTE) */ +#define LDIR_Chksum 13 /* Checksum of the SFN entry (BYTE) */ +#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ +#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* File attribute (WORD) */ +#define XDIR_CrtTime 8 /* Created time (DWORD) */ +#define XDIR_ModTime 12 /* Modified time (DWORD) */ +#define XDIR_AccTime 16 /* Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* Gneral secondary flags (WORD) */ +#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ -#define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ + /*-------------------------------------------------------------------------- Module Private Work Area ---------------------------------------------------------------------------*/ -/* Remark: Uninitialized variables with static duration are guaranteed -/ zero/null at start-up. If not, either the linker or start-up routine -/ being used is not compliance with ANSI-C standard. -*/ +/* Remark: Variables here without initial value shall be guaranteed zero/null +/ at start-up. If not, either the linker or start-up routine being used is +/ not compliance with C standard. */ #if _VOLUMES < 1 || _VOLUMES > 9 #error Wrong _VOLUMES setting @@ -448,35 +526,54 @@ typedef struct { static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ static WORD Fsid; /* File system mount ID */ -#if _FS_RPATH && _VOLUMES >= 2 +#if _FS_RPATH != 0 && _VOLUMES >= 2 static BYTE CurrVol; /* Current drive */ #endif -#if _FS_LOCK +#if _FS_LOCK != 0 static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non LFN feature */ -#define DEFINE_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) (dobj).fn = sfn -#define FREE_BUF() +#if _USE_LFN == 0 /* Non-LFN configuration */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() #else #if _MAX_LFN < 12 || _MAX_LFN > 255 #error Wrong _MAX_LFN setting #endif -#if _USE_LFN == 1 /* LFN feature with static working buffer */ -static WCHAR LfnBuf[_MAX_LFN + 1]; -#define DEFINE_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } -#define FREE_BUF() -#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ -#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1] -#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } -#define FREE_BUF() -#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ -#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn -#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; } -#define FREE_BUF() ff_memfree(lfn) + +#if _USE_LFN == 1 /* LFN enabled with static working buffer */ +#if _FS_EXFAT +static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +#endif +static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() + +#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if _FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMBUF() +#else +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMBUF() +#endif + +#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if _FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#define FREE_NAMBUF() ff_memfree(lfn) +#else +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMBUF() ff_memfree(lfn) +#endif + #else #error Wrong _USE_LFN setting #endif @@ -498,6 +595,85 @@ static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended ---------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ +/* Load/Store multi-byte word in the FAT structure */ +/*-----------------------------------------------------------------------*/ + +static +WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static +DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if _FS_EXFAT +static +QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +{ + QWORD rv; + + rv = ptr[7]; + rv = rv << 8 | ptr[6]; + rv = rv << 8 | ptr[5]; + rv = rv << 8 | ptr[4]; + rv = rv << 8 | ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} +#endif + +#if !_FS_READONLY +static +void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +static +void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +#if _FS_EXFAT +static +void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} +#endif +#endif /* !_FS_READONLY */ + + + /*-----------------------------------------------------------------------*/ /* String functions */ /*-----------------------------------------------------------------------*/ @@ -508,39 +684,35 @@ void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; -#if _WORD_ACCESS == 1 - while (cnt >= sizeof (int)) { - *(int*)d = *(int*)s; - d += sizeof (int); s += sizeof (int); - cnt -= sizeof (int); + if (cnt) { + do *d++ = *s++; while (--cnt); } -#endif - while (cnt--) - *d++ = *s++; } -/* Fill memory */ +/* Fill memory block */ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; - while (cnt--) - *d++ = (BYTE)val; + do *d++ = (BYTE)val; while (--cnt); } -/* Compare memory to memory */ +/* Compare memory block */ static -int mem_cmp (const void* dst, const void* src, UINT cnt) { +int mem_cmp (const void* dst, const void* src, UINT cnt) { /* ZR:same, NZ:different */ const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; - while (cnt-- && (r = *d++ - *s++) == 0) ; + do { + r = *d++ - *s++; + } while (--cnt && r == 0); + return r; } /* Check if chr is contained in the string */ static -int chk_chr (const char* str, int chr) { +int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ while (*str && *str != chr) str++; return *str; } @@ -548,10 +720,10 @@ int chk_chr (const char* str, int chr) { +#if _FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -#if _FS_REENTRANT static int lock_fs ( FATFS* fs /* File system object */ @@ -567,23 +739,19 @@ void unlock_fs ( FRESULT res /* Result code to be returned */ ) { - if (fs && - res != FR_NOT_ENABLED && - res != FR_INVALID_DRIVE && - res != FR_INVALID_OBJECT && - res != FR_TIMEOUT) { + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { ff_rel_grant(fs->sobj); } } + #endif - +#if _FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ -#if _FS_LOCK static FRESULT chk_lock ( /* Check if the file can be accessed */ @@ -596,15 +764,16 @@ FRESULT chk_lock ( /* Check if the file can be accessed */ /* Search file semaphore table */ for (i = be = 0; i < _FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ - if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */ - Files[i].clu == dp->sclust && - Files[i].idx == dp->index) break; + if (Files[i].fs == dp->obj.fs && /* Check if the object matched with an open object */ + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } - if (i == _FS_LOCK) /* The object is not opened */ + if (i == _FS_LOCK) { /* The object is not opened */ return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + } /* The object has been opened. Reject any open against writing file and all write mode open */ return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; @@ -631,17 +800,17 @@ UINT inc_lock ( /* Increment object open counter and returns its index (0:Intern for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ - if (Files[i].fs == dp->fs && - Files[i].clu == dp->sclust && - Files[i].idx == dp->index) break; + if (Files[i].fs == dp->obj.fs && + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; } if (i == _FS_LOCK) { /* Not opened. Register it as new. */ for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ - Files[i].fs = dp->fs; - Files[i].clu = dp->sclust; - Files[i].idx = dp->index; + Files[i].fs = dp->obj.fs; + Files[i].clu = dp->obj.sclust; + Files[i].ofs = dp->dptr; Files[i].ctr = 0; } @@ -665,9 +834,9 @@ FRESULT dec_lock ( /* Decrement object open counter */ if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ - if (n) n--; /* Decrement read mode open count */ + if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; - if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ res = FR_OK; } else { res = FR_INT_ERR; /* Invalid index nunber */ @@ -687,8 +856,8 @@ void clear_lock ( /* Clear lock entries of the volume */ if (Files[i].fs == fs) Files[i].fs = 0; } } -#endif +#endif /* _FS_LOCK != 0 */ @@ -697,8 +866,8 @@ void clear_lock ( /* Clear lock entries of the volume */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static -FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */ - FATFS* fs /* File system object */ +FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs /* File system object */ ) { DWORD wsect; @@ -726,9 +895,9 @@ FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */ static -FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */ - FATFS* fs, /* File system object */ - DWORD sector /* Sector number to make appearance in the fs->win[] */ +FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK; @@ -752,10 +921,11 @@ FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */ +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Synchronize file system and strage device */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY + static FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ FATFS* fs /* File system object */ @@ -770,33 +940,32 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* Create FSInfo structure */ mem_set(fs->win, 0, SS(fs)); - ST_WORD(fs->win + BS_55AA, 0xAA55); - ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); - ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); - ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); - ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); + st_word(fs->win + BS_55AA, 0xAA55); + st_dword(fs->win + FSI_LeadSig, 0x41615252); + st_dword(fs->win + FSI_StrucSig, 0x61417272); + st_dword(fs->win + FSI_Free_Count, fs->free_clst); + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Write it into the FSInfo sector */ fs->winsect = fs->volbase + 1; disk_write(fs->drv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } /* Make sure that no pending write process in the physical drive */ - if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) - res = FR_DISK_ERR; + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } return res; } -#endif +#endif /*-----------------------------------------------------------------------*/ /* Get sector# from cluster# */ /*-----------------------------------------------------------------------*/ -/* Hidden API for hacks and disk tools */ +static DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* File system object */ DWORD clst /* Cluster# to be converted */ @@ -813,16 +982,16 @@ DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ /*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ -/* Hidden API for hacks and disk tools */ -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ - FATFS* fs, /* File system object */ - DWORD clst /* FAT index number (cluster number) to get the value */ +static +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; - BYTE *p; DWORD val; + FATFS *fs = obj->fs; if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ @@ -838,21 +1007,42 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluste wc = fs->win[bc++ % SS(fs)]; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc |= fs->win[bc % SS(fs)] << 8; - val = clst & 1 ? wc >> 4 : (wc & 0xFFF); + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - p = &fs->win[clst * 2 % SS(fs)]; - val = LD_WORD(p); + val = ld_word(fs->win + clst * 2 % SS(fs)); break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - p = &fs->win[clst * 4 % SS(fs)]; - val = LD_DWORD(p) & 0x0FFFFFFF; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; break; +#if _FS_EXFAT + case FS_EXFAT : + if (obj->objsize) { + DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ + DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ + if (obj->stat == 2) { /* Is there no valid chain on the FAT? */ + if (cofs <= clen) { + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */ + break; + } + } + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + val = clst + 1; /* Generate the value */ + break; + } + if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + break; + } + } + /* go next */ +#endif default: val = 1; /* Internal error */ } @@ -864,209 +1054,366 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluste +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ -/* Hidden API for hacks and disk tools */ -#if !_FS_READONLY +static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ - FATFS* fs, /* File system object */ + FATFS* fs, /* Corresponding file system object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) { UINT bc; BYTE *p; - FRESULT res; + FRESULT res = FR_INT_ERR; - if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ - res = FR_INT_ERR; - - } else { + if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { - case FS_FAT12 : + case FS_FAT12 : /* Bitfield items */ bc = (UINT)clst; bc += bc / 2; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; - p = &fs->win[bc++ % SS(fs)]; + p = fs->win + bc++ % SS(fs); *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; - p = &fs->win[bc % SS(fs)]; + p = fs->win + bc % SS(fs); *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); fs->wflag = 1; break; - case FS_FAT16 : + case FS_FAT16 : /* WORD aligned items */ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - p = &fs->win[clst * 2 % SS(fs)]; - ST_WORD(p, (WORD)val); + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); fs->wflag = 1; break; - case FS_FAT32 : + case FS_FAT32 : /* DWORD aligned items */ +#if _FS_EXFAT + case FS_EXFAT : +#endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; - p = &fs->win[clst * 4 % SS(fs)]; - val |= LD_DWORD(p) & 0xF0000000; - ST_DWORD(p, val); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + } + st_dword(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; - - default : - res = FR_INT_ERR; } } - return res; } + #endif /* !_FS_READONLY */ +#if _FS_EXFAT && !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* FAT handling - Remove a cluster chain */ +/* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY + +/*---------------------------------------------*/ +/* exFAT: Find a contiguous free cluster block */ +/*---------------------------------------------*/ + static -FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ - FATFS* fs, /* File system object */ - DWORD clst /* Cluster# to remove a chain from */ +DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to scan from */ + DWORD ncl /* Number of contiguous clusters to find (1..) */ +) +{ + BYTE bm, bv; + UINT i; + DWORD val, scl, ctr; + + + clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ + if (clst >= fs->n_fatent - 2) clst = 0; + scl = val = clst; ctr = 0; + for (;;) { + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; + i = val / 8 % SS(fs); bm = 1 << (val % 8); + do { + do { + bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ + if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ + val = 0; bm = 0; i = 4096; + } + if (!bv) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check run length */ + } else { + scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + } + if (val == clst) return 0; /* All cluster scanned? */ + } while (bm); + bm = 1; + } while (++i < SS(fs)); + } +} + + +/*------------------------------------*/ +/* exFAT: Set/Clear a block of bitmap */ +/*------------------------------------*/ + +static +FRESULT change_bitmap ( + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to change from */ + DWORD ncl, /* Number of clusters to be changed */ + int bv /* bit value to be set (0 or 1) */ +) +{ + BYTE bm; + UINT i; + DWORD sect; + + + clst -= 2; /* The first bit corresponds to cluster #2 */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ + for (;;) { + if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; + do { + do { + if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ + fs->win[i] ^= bm; /* Flip the bit */ + fs->wflag = 1; + if (--ncl == 0) return FR_OK; /* All bits processed? */ + } while (bm <<= 1); /* Next bit */ + bm = 1; + } while (++i < SS(fs)); /* Next byte */ + } +} + + +/*---------------------------------------------*/ +/* Complement contiguous part of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_fat_chain ( + _FDID* obj /* Pointer to the corresponding object */ ) { FRESULT res; - DWORD nxt; -#if _USE_TRIM - DWORD scl = clst, ecl = clst, rt[2]; -#endif + DWORD cl, n; - if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ - res = FR_INT_ERR; - - } else { - res = FR_OK; - while (clst < fs->n_fatent) { /* Not a last link? */ - nxt = get_fat(fs, clst); /* Get cluster status */ - if (nxt == 0) break; /* Empty cluster? */ - if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ - if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ - res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ - if (res != FR_OK) break; - if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ - fs->free_clust++; - fs->fsi_flag |= 1; - } -#if _USE_TRIM - if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ - ecl = nxt; - } else { /* End of contiguous clusters */ - rt[0] = clust2sect(fs, scl); /* Start sector */ - rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ - disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */ - scl = ecl = nxt; - } -#endif - clst = nxt; /* Next cluster */ + if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */ + for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ + res = put_fat(obj->fs, cl, cl + 1); + if (res != FR_OK) return res; } + obj->stat = 0; /* Change status 'FAT chain is valid' */ + } + return FR_OK; +} + +#endif /* _FS_EXFAT && !_FS_READONLY */ + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +static +FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + _FDID* obj, /* Corresponding object */ + DWORD clst, /* Cluster to remove a chain from */ + DWORD pclst /* Previous cluster of clst (0:an entire chain) */ +) +{ + FRESULT res = FR_OK; + DWORD nxt; + FATFS *fs = obj->fs; +#if _FS_EXFAT || _USE_TRIM + DWORD scl = clst, ecl = clst; +#endif +#if _USE_TRIM + DWORD rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ + + /* Mark the previous cluster 'EOC' on the FAT if it exists */ + if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) return res; } - return res; -} + /* Remove the chain */ + do { + nxt = get_fat(obj, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) return FR_INT_ERR; /* Internal error? */ + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ + if (res != FR_OK) return res; + } + if (fs->free_clst != 0xFFFFFFFF) { /* Update FSINFO */ + fs->free_clst++; + fs->fsi_flag |= 1; + } +#if _FS_EXFAT || _USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous cluster block */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ + if (res != FR_OK) return res; + } #endif +#if _USE_TRIM + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */ +#endif + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } while (clst < fs->n_fatent); /* Repeat while not the last link */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + if (pclst == 0) { /* Does object have no chain? */ + obj->stat = 0; /* Change the object status 'initial' */ + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ + obj->stat = 2; /* Change the object status 'contiguous' */ + } + } + } +#endif + return FR_OK; +} /*-----------------------------------------------------------------------*/ -/* FAT handling - Stretch or Create a cluster chain */ +/* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ - FATFS* fs, /* File system object */ + _FDID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { DWORD cs, ncl, scl; FRESULT res; + FATFS *fs = obj->fs; - if (clst == 0) { /* Create a new chain */ - scl = fs->last_clust; /* Get suggested start point */ - if (!scl || scl >= fs->n_fatent) scl = 1; + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clst; /* Get suggested cluster to start at */ + if (scl == 0 || scl >= fs->n_fatent) scl = 1; } - else { /* Stretch the current chain */ - cs = get_fat(fs, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ + else { /* Stretch current chain */ + cs = get_fat(obj, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Invalid value */ if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; } - ncl = scl; /* Start cluster */ - for (;;) { - ncl++; /* Next cluster */ - if (ncl >= fs->n_fatent) { /* Check wrap around */ - ncl = 2; - if (ncl > scl) return 0; /* No free cluster */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ + if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ + res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ + if (res == FR_INT_ERR) return 1; + if (res == FR_DISK_ERR) return 0xFFFFFFFF; + if (clst == 0) { /* Is it a new chain? */ + obj->stat = 2; /* Set status 'contiguous chain' */ + } else { /* This is a stretched chain */ + if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ + obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ + obj->stat = 3; /* Change status 'just fragmented' */ + } + } + } else +#endif + { /* At the FAT12/16/32 */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ + if (ncl == scl) return 0; /* No free cluster */ } - cs = get_fat(fs, ncl); /* Get the cluster status */ - if (cs == 0) break; /* Found a free cluster */ - if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ - return cs; - if (ncl == scl) return 0; /* No free cluster */ } - res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ - if (res == FR_OK && clst != 0) { - res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ - } - if (res == FR_OK) { - fs->last_clust = ncl; /* Update FSINFO */ - if (fs->free_clust != 0xFFFFFFFF) { - fs->free_clust--; - fs->fsi_flag |= 1; - } + if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ + res = FR_OK; /* FAT does not need to be written */ } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + } } - return ncl; /* Return new cluster number or error code */ + if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + fs->last_clst = ncl; + if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + fs->fsi_flag |= 1; + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ + } + + return ncl; /* Return new cluster number or error status */ } + #endif /* !_FS_READONLY */ +#if _USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ -#if _USE_FASTSEEK static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ - DWORD ofs /* File offset to be converted to cluster# */ + FSIZE_t ofs /* File offset to be converted to cluster# */ ) { DWORD cl, ncl, *tbl; + FATFS *fs = fp->obj.fs; tbl = fp->cltbl + 1; /* Top of CLMT */ - cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ + cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ for (;;) { ncl = *tbl++; /* Number of cluters in the fragment */ - if (!ncl) return 0; /* End of table? (error) */ + if (ncl == 0) return 0; /* End of table? (error) */ if (cl < ncl) break; /* In this fragment? */ cl -= ncl; tbl++; /* Next fragment */ } return cl + *tbl; /* Return the cluster number */ } + #endif /* _USE_FASTSEEK */ @@ -1079,40 +1426,41 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ - UINT idx /* Index of directory table */ + DWORD ofs /* Offset of directory table */ ) { - DWORD clst, sect; - UINT ic; + DWORD csz, clst; + FATFS *fs = dp->obj.fs; - dp->index = (WORD)idx; /* Current index */ - clst = dp->sclust; /* Table start cluster (0:root) */ - if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ + if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; - if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ - clst = dp->fs->dirbase; + } + dp->dptr = ofs; /* Set current offset */ + clst = dp->obj.sclust; /* Table start cluster (0:root) */ + if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ + clst = fs->dirbase; + if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + } if (clst == 0) { /* Static table (root-directory in FAT12/16) */ - if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ - return FR_INT_ERR; - sect = dp->fs->dirbase; - } - else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ - ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */ - while (idx >= ic) { /* Follow cluster chain */ - clst = get_fat(dp->fs, clst); /* Get next cluster */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + dp->sect = fs->dirbase; + + } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */ + csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ + while (ofs >= csz) { /* Follow cluster chain */ + clst = get_fat(&dp->obj, clst); /* Get next cluster */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */ - return FR_INT_ERR; - idx -= ic; + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ + ofs -= csz; } - sect = clust2sect(dp->fs, clst); + dp->sect = clust2sect(fs, clst); } - dp->clust = clst; /* Current cluster# */ - if (!sect) return FR_INT_ERR; - dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */ - dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */ + dp->clust = clst; /* Current cluster# */ + if (!dp->sect) return FR_INT_ERR; + dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ + dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ return FR_OK; } @@ -1130,59 +1478,58 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { - DWORD clst; - UINT i; + DWORD ofs, clst; + FATFS *fs = dp->obj.fs; #if !_FS_READONLY - UINT c; + UINT n; #endif + ofs = dp->dptr + SZDIRE; /* Next entry */ + if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ - i = dp->index + 1; - if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ - return FR_NO_FILE; - - if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */ - dp->sect++; /* Next sector */ + if (ofs % SS(fs) == 0) { /* Sector changed? */ + dp->sect++; /* Next sector */ if (!dp->clust) { /* Static table */ - if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */ - return FR_NO_FILE; + if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ + dp->sect = 0; return FR_NO_FILE; + } } else { /* Dynamic table */ - if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ - clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ - if (clst <= 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */ + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* Reached end of dynamic table */ #if !_FS_READONLY - if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */ - clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */ - if (clst == 0) return FR_DENIED; /* No free cluster */ - if (clst == 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - /* Clean-up stretched table */ - if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */ - mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */ - dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */ - for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */ - dp->fs->wflag = 1; - if (sync_window(dp->fs)) return FR_DISK_ERR; - dp->fs->winsect++; + if (!stretch) { /* If no stretch, report EOT */ + dp->sect = 0; return FR_NO_FILE; } - dp->fs->winsect -= c; /* Rewind window offset */ + clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + /* Clean-up the stretched table */ + if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */ + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ + for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */ + fs->wflag = 1; + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; + } + fs->winsect -= n; /* Restore window offset */ #else - if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */ - return FR_NO_FILE; /* Report EOT */ + if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } - dp->clust = clst; /* Initialize data for new cluster */ - dp->sect = clust2sect(dp->fs, clst); + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(fs, clst); } } } - - dp->index = (WORD)i; /* Current index */ - dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */ + dp->dptr = ofs; /* Current entry */ + dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ return FR_OK; } @@ -1190,58 +1537,66 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Directory handling - Reserve directory entry */ +/* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate (1-21) */ + UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; UINT n; + FATFS *fs = dp->obj.fs; res = dir_sdi(dp, 0); if (res == FR_OK) { n = 0; do { - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */ +#if _FS_EXFAT + if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { +#else + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { +#endif if (++n == nent) break; /* A block of contiguous free entries is found */ } else { n = 0; /* Not a blank entry. Restart to search */ } - res = dir_next(dp, 1); /* Next entry with table stretch enabled */ - } while (res == FR_OK); + res = dir_next(dp, 1); + } while (res == FR_OK); /* Next entry with table stretch enabled */ } + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ return res; } -#endif + +#endif /* !_FS_READONLY */ /*-----------------------------------------------------------------------*/ -/* Directory handling - Load/Store start cluster number */ +/* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ FATFS* fs, /* Pointer to the fs object */ - const BYTE* dir /* Pointer to the SFN entry */ + const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; - cl = LD_WORD(dir + DIR_FstClusLO); - if (fs->fs_type == FS_FAT32) - cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16; + cl = ld_word(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) { + cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + } return cl; } @@ -1250,59 +1605,67 @@ DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ #if !_FS_READONLY static void st_clust ( - BYTE* dir, /* Pointer to the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ ) { - ST_WORD(dir + DIR_FstClusLO, cl); - ST_WORD(dir + DIR_FstClusHI, cl >> 16); + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } } #endif - -/*-----------------------------------------------------------------------*/ -/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ -/*-----------------------------------------------------------------------*/ -#if _USE_LFN +#if _USE_LFN != 0 +/*------------------------------------------------------------------------*/ +/* FAT-LFN: LFN handling */ +/*------------------------------------------------------------------------*/ static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ +/*--------------------------------------------------------*/ +/* FAT-LFN: Compare a part of file name with an LFN entry */ +/*--------------------------------------------------------*/ static -int cmp_lfn ( /* 1:matched, 0:not matched */ - WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ - BYTE* dir /* Pointer to the directory entry containing the part of LFN */ +int cmp_lfn ( /* 1:matched, 0:not matched */ + const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ + BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) { UINT i, s; WCHAR wc, uc; - if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ - uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc) { - if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) /* Compare it */ + if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ + } wc = uc; } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } - if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ - return 0; + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ return 1; /* The part of LFN matched */ } - +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +/*-----------------------------------------------------*/ +/* FAT-LFN: Pick a part of file name from an LFN entry */ +/*-----------------------------------------------------*/ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ @@ -1313,12 +1676,12 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR wc, uc; - if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ - uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc) { if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ @@ -1334,15 +1697,19 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ return 1; /* The part of LFN is valid */ } +#endif #if !_FS_READONLY +/*-----------------------------------------*/ +/* FAT-LFN: Create an entry of LFN entries */ +/*-----------------------------------------*/ static -void fit_lfn ( - const WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ - BYTE* dir, /* Pointer to the LFN entry to be processed */ - BYTE ord, /* LFN order (1-20) */ - BYTE sum /* Checksum of the corresponding SFN */ +void put_lfn ( + const WCHAR* lfn, /* Pointer to the LFN */ + BYTE* dir, /* Pointer to the LFN entry to be created */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* Checksum of the corresponding SFN */ ) { UINT i, s; @@ -1352,29 +1719,29 @@ void fit_lfn ( dir[LDIR_Chksum] = sum; /* Set checksum */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Type] = 0; - ST_WORD(dir + LDIR_FstClusLO, 0); + st_word(dir + LDIR_FstClusLO, 0); i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ s = wc = 0; do { - if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ - ST_WORD(dir+LfnOfs[s], wc); /* Put it */ - if (!wc) wc = 0xFFFF; /* Padding characters following last character */ + if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ + st_word(dir + LfnOfs[s], wc); /* Put it */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ } while (++s < 13); - if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */ + if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ } -#endif -#endif - +#endif /* !_FS_READONLY */ +#endif /* _USE_LFN != 0 */ +#if _USE_LFN != 0 && !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Create numbered name */ +/* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ -#if _USE_LFN + static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ @@ -1391,7 +1758,7 @@ void gen_numname ( mem_cpy(dst, src, 11); - if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ + if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sr = seq; while (*lfn) { /* Create a CRC */ wc = *lfn++; @@ -1425,15 +1792,15 @@ void gen_numname ( dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } -#endif - +#endif /* _USE_LFN != 0 && !_FS_READONLY */ +#if _USE_LFN != 0 /*-----------------------------------------------------------------------*/ -/* Calculate checksum of an SFN entry */ +/* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ -#if _USE_LFN + static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ @@ -1445,9 +1812,350 @@ BYTE sum_sfn ( do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); return sum; } + +#endif /* _USE_LFN != 0 */ + + + +#if _FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* exFAT: Checksum */ +/*-----------------------------------------------------------------------*/ + +static +WORD xdir_sum ( /* Get checksum of the directoly block */ + const BYTE* dir /* Directory entry block to be calculated */ +) +{ + UINT i, szblk; + WORD sum; + + + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + for (i = sum = 0; i < szblk; i++) { + if (i == XDIR_SetSum) { /* Skip sum field */ + i++; + } else { + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; + } + } + return sum; +} + + + +static +WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ + const WCHAR* name /* File name to be calculated */ +) +{ + WCHAR chr; + WORD sum = 0; + + + while ((chr = *name++) != 0) { + chr = ff_wtoupper(chr); /* File name needs to be ignored case */ + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); + } + return sum; +} + + +#if !_FS_READONLY && _USE_MKFS +static +DWORD xsum32 ( + BYTE dat, /* Data to be sumed */ + DWORD sum /* Previous value */ +) +{ + sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; + return sum; +} #endif +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +/*------------------------------------------------------*/ +/* exFAT: Get object information from a directory block */ +/*------------------------------------------------------*/ + +static +void get_xdir_info ( + BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ + FILINFO* fno /* Buffer to store the extracted file information */ +) +{ + UINT di, si; + WCHAR w; +#if !_LFN_UNICODE + UINT nc; +#endif + + /* Get file name */ +#if _LFN_UNICODE + if (dirb[XDIR_NumName] <= _MAX_LFN) { + for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + fno->fname[di] = w; /* Store it */ + } + } else { + di = 0; /* Buffer overflow and inaccessible object */ + } +#else + for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[di++] = (char)(w >> 8); + } + if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ + fno->fname[di++] = (char)w; + } +#endif + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ + fno->fname[di] = 0; /* Terminate file name */ + + fno->altname[0] = 0; /* No SFN */ + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ +} + +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + + +/*-----------------------------------*/ +/* exFAT: Get a directry entry block */ +/*-----------------------------------*/ + +static +FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ +) +{ + FRESULT res; + UINT i, nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + + + /* Load 85 entry */ + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; + mem_cpy(dirb, dp->dir, SZDIRE); + nent = dirb[XDIR_NumSec] + 1; + + /* Load C0 entry */ + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; + mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + + /* Load C1 entries */ + if (nent < 3 || nent > 19) return FR_NO_FILE; + i = SZDIRE * 2; nent *= SZDIRE; + do { + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; + mem_cpy(dirb + i, dp->dir, SZDIRE); + i += SZDIRE; + } while (i < nent); + + /* Sanity check */ + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + + return FR_OK; +} + + +#if !_FS_READONLY || _FS_RPATH != 0 +/*------------------------------------------------*/ +/* exFAT: Load the object's directory entry block */ +/*------------------------------------------------*/ +static +FRESULT load_obj_dir ( + DIR* dp, /* Blank directory object to be used to access containing direcotry */ + const _FDID* obj /* Object with containing directory information */ +) +{ + FRESULT res; + + + /* Open object containing directory */ + dp->obj.fs = obj->fs; + dp->obj.sclust = obj->c_scl; + dp->obj.stat = (BYTE)obj->c_size; + dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->blk_ofs = obj->c_ofs; + + res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + if (res == FR_OK) { + res = load_xdir(dp); /* Load the object's entry block */ + } + return res; +} +#endif + + +#if !_FS_READONLY +/*-----------------------------------------------*/ +/* exFAT: Store the directory block to the media */ +/*-----------------------------------------------*/ +static +FRESULT store_xdir ( + DIR* dp /* Pointer to the direcotry object */ +) +{ + FRESULT res; + UINT nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + + /* Create set sum */ + st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); + nent = dirb[XDIR_NumSec] + 1; + + /* Store the set of directory to the volume */ + res = dir_sdi(dp, dp->blk_ofs); + while (res == FR_OK) { + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; + mem_cpy(dp->dir, dirb, SZDIRE); + dp->obj.fs->wflag = 1; + if (--nent == 0) break; + dirb += SZDIRE; + res = dir_next(dp, 0); + } + return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; +} + + + +/*-------------------------------------------*/ +/* exFAT: Create a new directory enrty block */ +/*-------------------------------------------*/ + +static +void create_xdir ( + BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + const WCHAR* lfn /* Pointer to the nul terminated file name */ +) +{ + UINT i; + BYTE nb, nc; + WCHAR chr; + + + mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ + dirb[XDIR_Type] = 0x85; + dirb[XDIR_Type + SZDIRE] = 0xC0; + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ + + i = SZDIRE * 2; /* C1 offset */ + nc = 0; nb = 1; chr = 1; + do { + dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + do { /* Fill name field */ + if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ + st_word(dirb + i, chr); i += 2; /* Store it */ + } while (i % SZDIRE); + nb++; + } while (lfn[nc]); /* Fill next entry if any char follows */ + + dirb[XDIR_NumName] = nc; /* Set name length */ + dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_EXFAT */ + + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE a, c; +#if _USE_LFN != 0 + BYTE ord = 0xFF, sum = 0xFF; +#endif + + while (dp->sect) { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; /* Test for the entry type */ + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (_USE_LABEL && vol) { + if (c == 0x83) break; /* Volume label entry? */ + } else { + if (c == 0x85) { /* Start of the file entry block? */ + dp->blk_ofs = dp->dptr; /* Get location of the block */ + res = load_xdir(dp); /* Load the entry block */ + if (res == FR_OK) { + dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ + } + break; + } + } + } else +#endif + { /* At the FAT12/16/32 */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if _USE_LFN != 0 /* LFN configuration */ + if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of an LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= ~LLEF; ord = c; + dp->blk_ofs = dp->dptr; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ + } + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + break; + } +#endif + } + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ + return res; +} + +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ + /*-----------------------------------------------------------------------*/ @@ -1456,53 +2164,70 @@ BYTE sum_sfn ( static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ - DIR* dp /* Pointer to the directory object linked to the file name */ + DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; - BYTE c, *dir; -#if _USE_LFN + FATFS *fs = dp->obj.fs; + BYTE c; +#if _USE_LFN != 0 BYTE a, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + BYTE nc; + UINT di, ni; + WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ -#if _USE_LFN - ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ + for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ + if ((di % SZDIRE) == 0) di += 2; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + } + if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ + } + return res; + } +#endif + /* At the FAT12/16/32 */ +#if _USE_LFN != 0 + ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif do { - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - dir = dp->dir; /* Ptr to the directory entry of current index */ - c = dir[DIR_Name]; + c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ -#if _USE_LFN /* LFN configuration */ - a = dir[DIR_Attr] & AM_MASK; +#if _USE_LFN != 0 /* LFN configuration */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ - ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { if (a == AM_LFN) { /* An LFN entry is found */ - if (dp->lfn) { + if (!(dp->fn[NSFLAG] & NS_NOLFN)) { if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; + sum = dp->dir[LDIR_Chksum]; c &= ~LLEF; ord = c; /* LFN start order */ - dp->lfn_idx = dp->index; /* Start index of LFN */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ } /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ - if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ - if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */ - ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } } #else /* Non LFN configuration */ - if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ - break; + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ #endif - res = dir_next(dp, 0); /* Next entry */ + res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); return res; @@ -1511,288 +2236,290 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ -/*-----------------------------------------------------------------------*/ -/* Read an object from the directory */ -/*-----------------------------------------------------------------------*/ -#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 -static -FRESULT dir_read ( - DIR* dp, /* Pointer to the directory object */ - int vol /* Filtered by 0:file/directory or 1:volume label */ -) -{ - FRESULT res; - BYTE a, c, *dir; -#if _USE_LFN - BYTE ord = 0xFF, sum = 0xFF; -#endif - - res = FR_NO_FILE; - while (dp->sect) { - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - dir = dp->dir; /* Ptr to the directory entry of current index */ - c = dir[DIR_Name]; - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ - a = dir[DIR_Attr] & AM_MASK; -#if _USE_LFN /* LFN configuration */ - if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ - ord = 0xFF; - } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; - dp->lfn_idx = dp->index; - } - /* Check LFN validity and capture it */ - ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; - } else { /* An SFN entry is found */ - if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ - dp->lfn_idx = 0xFFFF; /* It has no LFN. */ - break; - } - } -#else /* Non LFN configuration */ - if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */ - break; -#endif - res = dir_next(dp, 0); /* Next entry */ - if (res != FR_OK) break; - } - - if (res != FR_OK) dp->sect = 0; - - return res; -} -#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ - - - - +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY + static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; -#if _USE_LFN /* LFN configuration */ - UINT n, nent; - BYTE sn[12], *fn, sum; - WCHAR *lfn; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + UINT n, nlen, nent; + BYTE sn[12], sum; - fn = dp->fn; lfn = dp->lfn; - mem_cpy(sn, fn, 12); + if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ - if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */ - return FR_INVALID_NAME; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + DIR dj; + nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res != FR_OK) return res; + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + + if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */ + dp->obj.stat &= 3; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ + res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + if (res != FR_OK) return res; + res = load_obj_dir(&dj, &dp->obj); + if (res != FR_OK) return res; /* Load the object status */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } + + create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ + return FR_OK; + } +#endif + /* At the FAT12/16/32 */ + mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ - fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ + dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { - gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ + gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } if (n == 100) return FR_DENIED; /* Abort if too many collisions */ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ - fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn; + dp->fn[NSFLAG] = sn[NSFLAG]; } - if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */ - for (n = 0; lfn[n]; n++) ; - nent = (n + 25) / 13; - } else { /* Otherwise allocate an entry for an SFN */ - nent = 1; - } + /* Create an SFN with/without LFNs. */ + nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ res = dir_alloc(dp, nent); /* Allocate entries */ - if (res == FR_OK && --nent) { /* Set LFN entry if needed */ - res = dir_sdi(dp, dp->index - nent); + res = dir_sdi(dp, dp->dptr - nent * SZDIRE); if (res == FR_OK) { sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ do { /* Store LFN entries in bottom first */ - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); - dp->fs->wflag = 1; + put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); + fs->wflag = 1; res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK && --nent); } } + #else /* Non LFN configuration */ res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ + #endif - if (res == FR_OK) { /* Set SFN entry */ - res = move_window(dp->fs, dp->sect); + /* Set SFN entry */ + if (res == FR_OK) { + res = move_window(fs, dp->sect); if (res == FR_OK) { - mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */ - mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ -#if _USE_LFN + mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ + mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ +#if _USE_LFN != 0 dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif - dp->fs->wflag = 1; + fs->wflag = 1; } } return res; } + #endif /* !_FS_READONLY */ - +#if !_FS_READONLY && _FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY && !_FS_MINIMIZE + static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; -#if _USE_LFN /* LFN configuration */ - UINT i; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + DWORD last = dp->dptr; - i = dp->index; /* SFN index */ - res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ + res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ if (res == FR_OK) { do { - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ - *dp->dir = DDEM; - dp->fs->wflag = 1; - if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ - res = dir_next(dp, 0); /* Next entry */ + /* Mark an entry 'deleted' */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* At the exFAT */ + dp->dir[XDIR_Type] &= 0x7F; + } else { /* At the FAT12/16/32 */ + dp->dir[DIR_Name] = DDEM; + } + fs->wflag = 1; + if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR; } - #else /* Non LFN configuration */ - res = dir_sdi(dp, dp->index); + + res = move_window(fs, dp->sect); if (res == FR_OK) { - res = move_window(dp->fs, dp->sect); - if (res == FR_OK) { - mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ - *dp->dir = DDEM; - dp->fs->wflag = 1; - } + dp->dir[DIR_Name] = DDEM; + fs->wflag = 1; } #endif return res; } -#endif /* !_FS_READONLY */ +#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */ +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 + static void get_fileinfo ( /* No return code */ DIR* dp, /* Pointer to the directory object */ FILINFO* fno /* Pointer to the file information to be filled */ ) { - UINT i; - TCHAR *p, c; - BYTE *dir; -#if _USE_LFN - WCHAR w, *lfn; + UINT i, j; + TCHAR c; + DWORD tm; +#if _USE_LFN != 0 + WCHAR w, lfv; + FATFS *fs = dp->obj.fs; #endif - p = fno->fname; - if (dp->sect) { /* Get SFN */ - dir = dp->dir; - i = 0; - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */ -#if _USE_LFN - if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) - c += 0x20; /* To lower */ -#if _LFN_UNICODE - if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) - c = c << 8 | dir[i++]; - c = ff_convert(c, 1); /* OEM -> Unicode */ - if (!c) c = '?'; -#endif -#endif - *p++ = c; - } - fno->fattrib = dir[DIR_Attr]; /* Attribute */ - fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */ - fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */ - fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */ - } - *p = 0; /* Terminate SFN string by a \0 */ -#if _USE_LFN - if (fno->lfname) { - i = 0; p = fno->lfname; - if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ - lfn = dp->lfn; - while ((w = *lfn++) != 0) { /* Get an LFN character */ + fno->fname[0] = 0; /* Invaidate file info */ + if (!dp->sect) return; /* Exit if read pointer has reached end of directory */ + +#if _USE_LFN != 0 /* LFN configuration */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + get_xdir_info(fs->dirbuf, fno); + return; + } else +#endif + { /* At the FAT12/16/32 */ + if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ + i = j = 0; + while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ #if !_LFN_UNICODE w = ff_convert(w, 0); /* Unicode -> OEM */ - if (!w) { i = 0; break; } /* No LFN if it could not be converted */ - if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ - p[i++] = (TCHAR)(w >> 8); + if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[i++] = (char)(w >> 8); + } #endif - if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */ - p[i++] = (TCHAR)w; + if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ + fno->fname[i++] = (char)w; } + fno->fname[i] = 0; /* Terminate the LFN */ } - p[i] = 0; /* Terminate LFN string by a \0 */ } + + i = j = 0; + lfv = fno->fname[i]; /* LFN is exist if non-zero */ + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) { /* Insert a . if extension is exist */ + if (!lfv) fno->fname[j] = '.'; + fno->altname[j++] = '.'; + } +#if _LFN_UNICODE + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) { + c = c << 8 | dp->dir[i++]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; #endif + fno->altname[j] = c; + if (!lfv) { + if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { + c += 0x20; /* To lower */ + } + fno->fname[j] = c; + } + j++; + } + if (!lfv) { + fno->fname[j] = 0; + if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */ + } + fno->altname[j] = 0; /* Terminate the SFN */ + +#else /* Non-LFN configuration */ + i = j = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */ + fno->fname[j++] = c; + } + fno->fname[j] = 0; +#endif + + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */ + fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); } + #endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ - +#if _USE_FIND && _FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ -#if _USE_FIND && _FS_MINIMIZE <= 1 + static WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ ) { +#if !_LFN_UNICODE WCHAR chr; -#if !_LFN_UNICODE chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ - if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */ - chr = chr << 8 | (BYTE)*(*ptr)++; #ifdef _EXCVT if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ -#endif #else - chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ + if (IsDBCS1(chr) && IsDBCS2(**ptr)) { /* Get DBC 2nd byte if needed */ + chr = chr << 8 | (BYTE)*(*ptr)++; + } #endif return chr; +#else + return ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ +#endif } static -int pattern_matching ( /* 0:mismatched, 1:matched */ +int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ @@ -1823,15 +2550,15 @@ int pattern_matching ( /* 0:mismatched, 1:matched */ pc = get_achar(&pp); /* Get a pattern char */ nc = get_achar(&np); /* Get a name char */ if (pc != nc) break; /* Branch mismatched? */ - if (!pc) return 1; /* Branch matched? (matched at end of both strings) */ + if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ } get_achar(&nam); /* nam++ */ } while (inf && nc); /* Retry until end of name if infinite search is specified */ return 0; } -#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ +#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ @@ -1845,41 +2572,40 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { -#if _USE_LFN /* LFN configuration */ +#if _USE_LFN != 0 /* LFN configuration */ BYTE b, cf; WCHAR w, *lfn; UINT i, ni, si, di; const TCHAR *p; /* Create LFN in Unicode */ - for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ - lfn = dp->lfn; - si = di = 0; + p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0; for (;;) { w = p[si++]; /* Get a character */ - if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ - if (di >= _MAX_LFN) /* Reject too long name */ - return FR_INVALID_NAME; + if (w < ' ') break; /* Break if end of the path name */ + if (w == '/' || w == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ #if !_LFN_UNICODE w &= 0xFF; if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ b = (BYTE)p[si++]; /* Get 2nd byte */ w = (w << 8) + b; /* Create a DBC */ - if (!IsDBCS2(b)) - return FR_INVALID_NAME; /* Reject invalid sequence */ + if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ } w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ if (!w) return FR_INVALID_NAME; /* Reject invalid code */ #endif - if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ - return FR_INVALID_NAME; + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ lfn[di++] = w; /* Store the Unicode character */ } *path = &p[si]; /* Return pointer to the next segment */ - cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ -#if _FS_RPATH + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ +#if _FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || - (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot entry? */ + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; @@ -1892,8 +2618,8 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ if (w != ' ' && w != '.') break; di--; } - if (!di) return FR_INVALID_NAME; /* Reject nul string */ lfn[di] = 0; /* LFN is created */ + if (di == 0) return FR_INVALID_NAME; /* Reject nul name */ /* Create SFN in directory form */ mem_set(dp->fn, ' ', 11); @@ -1953,8 +2679,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ if (ni == 8) b <<= 2; - if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ - cf |= NS_LFN; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ @@ -1965,17 +2690,16 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ return FR_OK; -#else /* Non-LFN configuration */ - BYTE b, c, d, *sfn; +#else /* _USE_LFN != 0 : Non-LFN configuration */ + BYTE c, d, *sfn; UINT ni, si, i; const char *p; /* Create file name in directory form */ - for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Skip duplicated separator */ - sfn = dp->fn; + p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); - si = i = b = 0; ni = 8; -#if _FS_RPATH + si = i = 0; ni = 8; +#if _FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; @@ -1983,62 +2707,51 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ sfn[i++] = c; } if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; - *path = &p[si]; /* Return pointer to the next segment */ - sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ + *path = p + si; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; } #endif for (;;) { c = (BYTE)p[si++]; - if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ - if (c == '.' || i >= ni) { - if (ni != 8 || c != '.') return FR_INVALID_NAME; - i = 8; ni = 11; - b <<= 2; continue; + if (c <= ' ') break; /* Break if end of the path name */ + if (c == '/' || c == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (c == '.' || i >= ni) { /* End of body or over size? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */ + i = 8; ni = 11; /* Goto extension */ + continue; } if (c >= 0x80) { /* Extended character? */ - b |= 3; /* Eliminate NT flag */ #ifdef _EXCVT c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ #else #if !_DF1S - return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ + return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */ #endif #endif } if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ d = (BYTE)p[si++]; /* Get 2nd byte */ - if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ - return FR_INVALID_NAME; + if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ - if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ - return FR_INVALID_NAME; - if (IsUpper(c)) { /* ASCII large capital? */ - b |= 2; - } else { - if (IsLower(c)) { /* ASCII small capital? */ - b |= 1; c -= 0x20; - } - } + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ + if (IsLower(c)) c -= 0x20; /* To upper */ sfn[i++] = c; } } - *path = &p[si]; /* Return pointer to the next segment */ - c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + *path = p + si; /* Return pointer to the next segment */ + if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ - if (!i) return FR_INVALID_NAME; /* Reject nul string */ - if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */ - - if (ni == 8) b <<= 2; - if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ - if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ - - sfn[NSFLAG] = c; /* Store NT flag, File name is created */ + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; -#endif +#endif /* _USE_LFN != 0 */ } @@ -2055,36 +2768,50 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ ) { FRESULT res; - BYTE *dir, ns; + BYTE ns; + _FDID *obj = &dp->obj; + FATFS *fs = obj->fs; -#if _FS_RPATH - if (*path == '/' || *path == '\\') { /* There is a heading separator */ - path++; dp->sclust = 0; /* Strip it and start from the root directory */ - } else { /* No heading separator */ - dp->sclust = dp->fs->cdir; /* Start from the current directory */ +#if _FS_RPATH != 0 + if (*path != '/' && *path != '\\') { /* Without heading separator */ + obj->sclust = fs->cdir; /* Start from the current directory */ + } else +#endif + { /* With heading separator */ + while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ + obj->sclust = 0; /* Start from the root directory */ + } +#if _FS_EXFAT && _FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ + DIR dj; + + obj->c_scl = fs->cdc_scl; + obj->c_size = fs->cdc_size; + obj->c_ofs = fs->cdc_ofs; + res = load_obj_dir(&dj, obj); + if (res != FR_OK) return res; + obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; } -#else - if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ - path++; - dp->sclust = 0; /* Always start from the root directory */ #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + dp->fn[NSFLAG] = NS_NONAME; res = dir_sdi(dp, 0); - dp->dir = 0; + } else { /* Follow path */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; - res = dir_find(dp); /* Find an object with the sagment name */ + res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ - if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */ - dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ - res = FR_OK; /* Ended at the root directroy. Function completed. */ + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; } else { /* Could not find the object */ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ } @@ -2092,11 +2819,23 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ break; } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ - dir = dp->dir; /* Follow the sub-directory */ - if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + /* Get into the sub-directory */ + if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } - dp->sclust = ld_clust(dp->fs, dir); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + } else +#endif + { + obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + } } } @@ -2155,7 +2894,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ #endif return vol; } -#if _FS_RPATH && _VOLUMES >= 2 +#if _FS_RPATH != 0 && _VOLUMES >= 2 vol = CurrVol; /* Current drive */ #else vol = 0; /* Drive 0 */ @@ -2172,24 +2911,24 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ /*-----------------------------------------------------------------------*/ static -BYTE check_fs ( /* 0:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk error */ +BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ FATFS* fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ + DWORD sect /* Sector# (lba) to check if it is an FAT-VBR or not */ ) { - fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ - if (move_window(fs, sect) != FR_OK) /* Load boot record */ - return 3; + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ - return 2; + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ - if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ - return 0; - if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ - return 0; - - return 1; + if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { + if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ + if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */ + } +#if _FS_EXFAT + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; +#endif + return 2; } @@ -2201,9 +2940,9 @@ BYTE check_fs ( /* 0:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk er static FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ - FATFS** rfs, /* Pointer to pointer to the found file system object */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ - BYTE wmode /* !=0: Check write protection for write access */ + FATFS** rfs, /* Pointer to pointer to the found file system object */ + BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; @@ -2227,11 +2966,13 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ ENTER_FF(fs); /* Lock the volume */ *rfs = fs; /* Return pointer to the file system object */ + mode &= ~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type) { /* If the volume has been mounted */ stat = disk_status(fs->drv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ - if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; + } return FR_OK; /* The file system object is valid */ } } @@ -2242,122 +2983,172 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ fs->fs_type = 0; /* Clear the file system object */ fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->drv); /* Initialize the physical drive */ - if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ - if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */ + } + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; + } #if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ - if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK - || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ bsect = 0; - fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ - if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ + if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ for (i = 0; i < 4; i++) { /* Get partition offset */ - pt = fs->win + MBR_Table + i * SZ_PTE; - br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; + pt = fs->win + (MBR_Table + i * SZ_PTE); + br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ if (i) i--; do { /* Find an FAT volume */ bsect = br[i]; - fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ - } while (!LD2PT(vol) && fmt && ++i < 4); + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } while (!LD2PT(vol) && fmt >= 2 && ++i < 4); } - if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ - if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ /* An FAT volume is found. Following code initializes the file system object */ - if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ - return FR_NO_FILESYSTEM; +#if _FS_EXFAT + if (fmt == 1) { + QWORD maxlba; - fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ - if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32); - fs->fsize = fasize; + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ - if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ - return FR_NO_FILESYSTEM; - fasize *= fs->n_fats; /* Number of sectors for FAT area */ + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ - fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ - if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ - return FR_NO_FILESYSTEM; + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; - fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ - if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ - return FR_NO_FILESYSTEM; + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ + if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ - tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ - if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32); + fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ - nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ - /* Determine the FAT sub type */ - sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - fmt = FS_FAT12; - if (nclst >= MIN_FAT16) fmt = FS_FAT16; - if (nclst >= MIN_FAT32) fmt = FS_FAT32; + fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ - /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ - if (fmt == FS_FAT32) { - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ - fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ - } else { - if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ - fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); - } - if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ - return FR_NO_FILESYSTEM; + nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = nclst + 2; + + /* Boundaries and Limits */ + fs->volbase = bsect; + fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); + if (maxlba < fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + + /* Check if bitmap location is in assumption (at the first cluster) */ + if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; + for (i = 0; i < SS(fs); i += SZDIRE) { + if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + } + if (i == SS(fs)) return FR_NO_FILESYSTEM; +#if !_FS_READONLY + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ +#endif + fmt = FS_EXFAT; /* FAT sub-type */ + } else +#endif /* _FS_EXFAT */ + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ + + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT32; + if (nclst <= MAX_FAT16) fmt = FS_FAT16; + if (nclst <= MAX_FAT12) fmt = FS_FAT12; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ #if !_FS_READONLY - /* Initialize cluster allocation information */ - fs->last_clust = fs->free_clust = 0xFFFFFFFF; - - /* Get fsinfo if available */ - fs->fsi_flag = 0x80; + /* Get FSINFO if available */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->fsi_flag = 0x80; #if (_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */ - && LD_WORD(fs->win + BPB_FSInfo) == 1 - && move_window(fs, bsect + 1) == FR_OK) - { - fs->fsi_flag = 0; - if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ - && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 - && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ + && ld_word(fs->win + BPB_FSInfo32) == 1 + && move_window(fs, bsect + 1) == FR_OK) { + fs->fsi_flag = 0; + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 + && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + { #if (_FS_NOFSINFO & 1) == 0 - fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif #if (_FS_NOFSINFO & 2) == 0 - fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif + } } +#endif /* (_FS_NOFSINFO & 3) != 3 */ +#endif /* !_FS_READONLY */ } -#endif -#endif + fs->fs_type = fmt; /* FAT sub-type */ fs->id = ++Fsid; /* File system mount ID */ -#if _FS_RPATH - fs->cdir = 0; /* Set current directory to root */ +#if _USE_LFN == 1 + fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ +#if _FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block working buuffer */ #endif -#if _FS_LOCK /* Clear file lock semaphores */ +#endif +#if _FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ +#endif +#if _FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif - return FR_OK; } @@ -2369,29 +3160,34 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ /*-----------------------------------------------------------------------*/ static -FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ - void* obj /* Pointer to the object FIL/DIR to check validity */ +FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + void* dfp, /* Pointer to the FIL/DIR object to check validity */ + FATFS** fs /* Pointer to pointer to the owner file system object to return */ ) { - FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ + _FDID *obj = (_FDID*)dfp; /* Assuming .obj in the FIL/DIR is the first member */ + FRESULT res; - if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT)) - return FR_INVALID_OBJECT; - - ENTER_FF(fil->fs); /* Lock file system */ - - return FR_OK; + if (!dfp || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { + *fs = 0; /* The object is invalid */ + res = FR_INVALID_OBJECT; + } else { + *fs = obj->fs; /* Owner file sytem object */ + ENTER_FF(obj->fs); /* Lock file system */ + res = FR_OK; + } + return res; } -/*-------------------------------------------------------------------------- +/*--------------------------------------------------------------------------- - Public Functions + Public Functions (FatFs API) ----------------------------------------------------------------------------*/ +----------------------------------------------------------------------------*/ @@ -2402,7 +3198,7 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ FRESULT f_mount ( FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ - BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ + BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ ) { FATFS *cfs; @@ -2416,7 +3212,7 @@ FRESULT f_mount ( cfs = FatFs[vol]; /* Pointer to fs object */ if (cfs) { -#if _FS_LOCK +#if _FS_LOCK != 0 clear_lock(cfs); #endif #if _FS_REENTRANT /* Discard sync object of the current volume */ @@ -2435,7 +3231,7 @@ FRESULT f_mount ( if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ - res = find_volume(&fs, &path, 0); /* Force mounted the volume */ + res = find_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } @@ -2454,126 +3250,190 @@ FRESULT f_open ( { FRESULT res; DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; + FATFS *fs; #if !_FS_READONLY - DWORD dw, cl; + DWORD dw, cl, bcs, clst, sc; + FSIZE_t ofs; #endif + DEF_NAMBUF if (!fp) return FR_INVALID_OBJECT; - fp->fs = 0; /* Clear file object */ /* Get logical drive number */ -#if !_FS_READONLY - mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; - res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); -#else - mode &= FA_READ; - res = find_volume(&dj.fs, &path, 0); -#endif + mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; + res = find_volume(&path, &fs, mode); if (res == FR_OK) { - INIT_BUF(dj); + dj.obj.fs = fs; + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - dir = dj.dir; #if !_FS_READONLY /* R/W configuration */ if (res == FR_OK) { - if (!dir) /* Default directory itself */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; -#if _FS_LOCK - else + } +#if _FS_LOCK != 0 + else { res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ -#if _FS_LOCK +#if _FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif mode |= FA_CREATE_ALWAYS; /* File is created */ - dir = dj.dir; /* New entry */ } else { /* Any object is already existing */ - if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { - if (mode & FA_CREATE_NEW) /* Cannot create as new file */ - res = FR_EXIST; + if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ dw = GET_FATTIME(); - ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */ - ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */ - dir[DIR_Attr] = 0; /* Reset attribute */ - ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */ - cl = ld_clust(dj.fs, dir); /* Get cluster chain */ - st_clust(dir, 0); /* Reset cluster */ - dj.fs->wflag = 1; - if (cl) { /* Remove the cluster chain if exist */ - dw = dj.fs->winsect; - res = remove_chain(dj.fs, cl); - if (res == FR_OK) { - dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ - res = move_window(dj.fs, dw); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + /* Get current allocation info */ + fp->obj.fs = fs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ + fs->dirbuf[XDIR_CrtTime10] = 0; + st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */ + st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */ + st_qword(fs->dirbuf + XDIR_FileSize, 0); + st_qword(fs->dirbuf + XDIR_ValidFileSize, 0); + fs->dirbuf[XDIR_GenFlags] = 1; + res = store_xdir(&dj); + if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ + } + } else +#endif + { + /* Clean directory info */ + st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ + st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */ + dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ + cl = ld_clust(fs, dj.dir); /* Get cluster chain */ + st_clust(fs, dj.dir, 0); /* Reset file allocation info */ + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + + if (cl) { /* Remove the cluster chain if exist */ + dw = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) { + res = move_window(fs, dw); + fs->last_clst = cl - 1; /* Reuse the cluster hole */ + } } } } } else { /* Open an existing file */ if (res == FR_OK) { /* Following succeeded */ - if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ + if (dj.obj.attr & AM_DIR) { /* It is a directory */ res = FR_NO_FILE; } else { - if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */ res = FR_DENIED; + } } } } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ - mode |= FA__WRITTEN; - fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ - fp->dir_ptr = dir; -#if _FS_LOCK - fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); - if (!fp->lockid) res = FR_INT_ERR; + mode |= FA_MODIFIED; + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dj.dir; +#if _FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->obj.lockid) res = FR_INT_ERR; #endif } - -#else /* R/O configuration */ - if (res == FR_OK) { /* Follow succeeded */ - dir = dj.dir; - if (!dir) { /* Current directory itself */ +#else /* R/O configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } else { - if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ + if (dj.obj.attr & AM_DIR) { /* It is a directory */ res = FR_NO_FILE; + } } } #endif - FREE_BUF(); if (res == FR_OK) { - fp->flag = mode; /* File access mode */ - fp->err = 0; /* Clear error flag */ - fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ - fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ - fp->fptr = 0; /* File pointer */ - fp->dsect = 0; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fp->obj.c_ofs = dj.blk_ofs; + } else +#endif + { + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } #if _USE_FASTSEEK - fp->cltbl = 0; /* Normal seek mode */ + fp->cltbl = 0; /* Disable fast seek mode */ +#endif + fp->obj.fs = fs; /* Validate the file object */ + fp->obj.id = fs->id; + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ +#if !_FS_READONLY +#if !_FS_TINY + mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */ +#endif + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + fp->fptr = fp->obj.objsize; /* Offset to seek */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ + clst = fp->obj.sclust; /* Follow the cluster chain */ + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ + if ((sc = clust2sect(fs, clst)) == 0) { + res = FR_INT_ERR; + } else { + fp->sect = sc + (DWORD)(ofs / SS(fs)); +#if !_FS_TINY + if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; +#endif + } + } + } #endif - fp->fs = dj.fs; /* Validate file object */ - fp->id = fp->fs->id; } + + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ + + LEAVE_FF(fs, res); } @@ -2584,96 +3444,99 @@ FRESULT f_open ( /*-----------------------------------------------------------------------*/ FRESULT f_read ( - FIL* fp, /* Pointer to the file object */ - void* buff, /* Pointer to data buffer */ - UINT btr, /* Number of bytes to read */ - UINT* br /* Pointer to number of bytes read */ + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ ) { FRESULT res; - DWORD clst, sect, remain; - UINT rcnt, cc; - BYTE csect, *rbuff = (BYTE*)buff; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE*)buff; *br = 0; /* Clear read byte counter */ - - res = validate(fp); /* Check validity */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_READ)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - remain = fp->fsize - fp->fptr; + res = validate(fp, &fs); + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until all data read */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->sclust; /* Follow from the origin */ + clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ #if _USE_FASTSEEK - if (fp->cltbl) + if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ - else + } else #endif - clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ + { + clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ + } } - if (clst < 2) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst < 2) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } - sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); sect += csect; - cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + cc = btr / SS(fs); /* When remaining bytes >= sector size, */ if (cc) { /* Read maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; - if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if _FS_TINY - if (fp->fs->wflag && fp->fs->winsect - sect < cc) - mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); + if (fs->wflag && fs->winsect - sect < cc) { + mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } #else - if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) - mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); + if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { + mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + } #endif #endif - rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if !_FS_TINY - if (fp->dsect != sect) { /* Load data sector if not in cache */ + if (fp->sect != sect) { /* Load data sector if not in cache */ #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= ~FA_DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { /* Fill sector cache */ + ABORT(fs, FR_DISK_ERR); + } } #endif - fp->dsect = sect; + fp->sect = sect; } - rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ - if (rcnt > btr) rcnt = btr; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if _FS_TINY - if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else - mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ + mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #endif } - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fs, FR_OK); } @@ -2686,117 +3549,120 @@ FRESULT f_read ( FRESULT f_write ( FIL* fp, /* Pointer to the file object */ - const void *buff, /* Pointer to the data to be written */ + const void* buff, /* Pointer to the data to be written */ UINT btw, /* Number of bytes to write */ UINT* bw /* Pointer to number of bytes written */ ) { FRESULT res; + FATFS *fs; DWORD clst, sect; - UINT wcnt, cc; + UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; - BYTE csect; *bw = 0; /* Clear write byte counter */ + res = validate(fp, &fs); + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - res = validate(fp); /* Check validity */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ + /* Check fptr wrap-around (file size cannot exceed the limit on each FAT specs) */ + if ((_FS_EXFAT && fs->fs_type == FS_EXFAT && fp->fptr + btw < fp->fptr) + || (DWORD)fp->fptr + btw < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } for ( ; btw; /* Repeat until all data written */ - wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ + wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->sclust; /* Follow from the origin */ - if (clst == 0) /* When no cluster is allocated, */ - clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ - } else { /* Middle or end of the file */ + clst = fp->obj.sclust; /* Follow from the origin */ + if (clst == 0) { /* If no cluster is allocated, */ + clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ + } + } else { /* On the middle or end of the file */ #if _USE_FASTSEEK - if (fp->cltbl) + if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ - else + } else #endif - clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ + { + clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } } if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ - if (clst == 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ - if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ + if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } #if _FS_TINY - if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else - if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= ~FA_DIRTY; } #endif - sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); sect += csect; - cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + cc = btw / SS(fs); /* When remaining bytes >= sector size, */ if (cc) { /* Write maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; - if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } #if _FS_MINIMIZE <= 2 #if _FS_TINY - if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); - fp->fs->wflag = 0; + if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; } #else - if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); - fp->flag &= ~FA__DIRTY; + if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + fp->flag &= ~FA_DIRTY; } #endif #endif - wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if _FS_TINY - if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ - if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); - fp->fs->winsect = sect; + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling at growing edge */ + if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; } #else - if (fp->dsect != sect) { /* Fill sector cache with file data */ - if (fp->fptr < fp->fsize && - disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (fp->sect != sect) { /* Fill sector cache with file data */ + if (fp->fptr < fp->obj.objsize && + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } } #endif - fp->dsect = sect; + fp->sect = sect; } - wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ - if (wcnt > btw) wcnt = btw; + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if _FS_TINY - if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ - fp->fs->wflag = 1; + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fs->wflag = 1; #else - mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ - fp->flag |= FA__DIRTY; + mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fp->flag |= FA_DIRTY; #endif } - if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ - fp->flag |= FA__WRITTEN; /* Set file change flag */ + fp->flag |= FA_MODIFIED; /* Set file change flag */ - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fs, FR_OK); } @@ -2811,38 +3677,68 @@ FRESULT f_sync ( ) { FRESULT res; + FATFS *fs; DWORD tm; BYTE *dir; + DEF_NAMBUF - res = validate(fp); /* Check validity of the object */ + res = validate(fp, &fs); /* Check validity of the object */ if (res == FR_OK) { - if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */ + if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !_FS_TINY - if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - LEAVE_FF(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + fp->flag &= ~FA_DIRTY; } #endif /* Update the directory entry */ - res = move_window(fp->fs, fp->dir_sect); - if (res == FR_OK) { - dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ - ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ - st_clust(dir, fp->sclust); /* Update start cluster */ - tm = GET_FATTIME(); /* Update modified time */ - ST_DWORD(dir + DIR_WrtTime, tm); - ST_WORD(dir + DIR_LstAccDate, 0); - fp->flag &= ~FA__WRITTEN; - fp->fs->wflag = 1; - res = sync_fs(fp->fs); + tm = GET_FATTIME(); /* Modified time */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + if (res == FR_OK) { + DIR dj; + + INIT_NAMBUF(fs); + res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ + if (res == FR_OK) { + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + st_dword(fs->dirbuf + XDIR_AccTime, 0); + res = store_xdir(&dj); /* Restore it to the directory */ + if (res == FR_OK) { + res = sync_fs(fs); + fp->flag &= ~FA_MODIFIED; + } + } + FREE_NAMBUF(); + } + } else +#endif + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_dword(dir + DIR_ModTime, tm); /* Update modified time */ + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); /* Restore it to the directory */ + fp->flag &= ~FA_MODIFIED; + } } } } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fs, res); } #endif /* !_FS_READONLY */ @@ -2855,27 +3751,26 @@ FRESULT f_sync ( /*-----------------------------------------------------------------------*/ FRESULT f_close ( - FIL *fp /* Pointer to the file object to be closed */ + FIL* fp /* Pointer to the file object to be closed */ ) { FRESULT res; - + FATFS *fs; #if !_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { - res = validate(fp); /* Lock volume */ + res = validate(fp, &fs); /* Lock volume */ if (res == FR_OK) { -#if _FS_REENTRANT - FATFS *fs = fp->fs; -#endif -#if _FS_LOCK - res = dec_lock(fp->lockid); /* Decrement file open counter */ +#if _FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) #endif - fp->fs = 0; /* Invalidate file object */ + { + fp->obj.fs = 0; /* Invalidate file object */ + } #if _FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif @@ -2887,11 +3782,11 @@ FRESULT f_close ( +#if _FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ -#if _FS_RPATH >= 1 #if _VOLUMES >= 2 FRESULT f_chdrive ( const TCHAR* path /* Drive number */ @@ -2916,29 +3811,48 @@ FRESULT f_chdir ( { FRESULT res; DIR dj; - DEFINE_NAMEBUF; - + FATFS *fs; + DEF_NAMBUF /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); + res = find_volume(&path, &fs, 0); if (res == FR_OK) { - INIT_BUF(dj); + dj.obj.fs = fs; + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ - FREE_BUF(); if (res == FR_OK) { /* Follow completed */ - if (!dj.dir) { - dj.fs->cdir = dj.sclust; /* Start directory itself */ + if (dj.fn[NSFLAG] & NS_NONAME) { + fs->cdir = dj.obj.sclust; /* It is the start directory itself */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdc_scl = dj.obj.c_scl; + fs->cdc_size = dj.obj.c_size; + fs->cdc_ofs = dj.obj.c_ofs; + } +#endif } else { - if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ - dj.fs->cdir = ld_clust(dj.fs, dj.dir); - else + if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ + fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ + fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fs->cdc_ofs = dj.blk_ofs; + } else +#endif + { + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + } + } else { res = FR_NO_PATH; /* Reached but a file */ + } } } + FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } @@ -2950,51 +3864,47 @@ FRESULT f_getcwd ( { FRESULT res; DIR dj; + FATFS *fs; UINT i, n; DWORD ccl; TCHAR *tp; FILINFO fno; - DEFINE_NAMEBUF; + DEF_NAMBUF *buff = 0; /* Get logical drive number */ - res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ + res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { - INIT_BUF(dj); + dj.obj.fs = fs; + INIT_NAMBUF(fs); i = len; /* Bottom of buffer (directory stack base) */ - dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ - while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ - res = dir_sdi(&dj, 1); /* Get parent directory */ - if (res != FR_OK) break; - res = dir_read(&dj, 0); - if (res != FR_OK) break; - dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ - res = dir_sdi(&dj, 0); - if (res != FR_OK) break; - do { /* Find the entry links to the child directory */ - res = dir_read(&dj, 0); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; - if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ - res = dir_next(&dj, 0); - } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ - if (res != FR_OK) break; -#if _USE_LFN - fno.lfname = buff; - fno.lfsize = i; -#endif - get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - tp = fno.fname; -#if _USE_LFN - if (*buff) tp = buff; -#endif - for (n = 0; tp[n]; n++) ; - if (i < n + 3) { - res = FR_NOT_ENOUGH_CORE; break; + res = move_window(fs, dj.sect); + if (res != FR_OK) break; + dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) break; + if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (n = 0; fno.fname[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = fno.fname[--n]; + buff[--i] = '/'; } - while (n) buff[--i] = tp[--n]; - buff[--i] = '/'; } tp = buff; if (res == FR_OK) { @@ -3011,11 +3921,12 @@ FRESULT f_getcwd ( } } *tp = 0; - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } + #endif /* _FS_RPATH >= 2 */ #endif /* _FS_RPATH >= 1 */ @@ -3028,70 +3939,67 @@ FRESULT f_getcwd ( FRESULT f_lseek ( FIL* fp, /* Pointer to the file object */ - DWORD ofs /* File pointer from top of file */ + FSIZE_t ofs /* File pointer from top of file */ ) { FRESULT res; - DWORD clst, bcs, nsect, ifptr; + FATFS *fs; + DWORD clst, bcs, nsect; + FSIZE_t ifptr; #if _USE_FASTSEEK DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif - - res = validate(fp); /* Check validity of the object */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ #if _USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ - cl = fp->sclust; /* Top of the chain */ + cl = fp->obj.sclust; /* Origin of the chain */ if (cl) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ do { pcl = cl; ncl++; - cl = get_fat(fp->fs, cl); - if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); - if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + cl = get_fat(&fp->obj, cl); + if (cl <= 1) ABORT(fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); } while (cl == pcl + 1); if (ulen <= tlen) { /* Store the length and top of the fragment */ *tbl++ = ncl; *tbl++ = tcl; } - } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ + } while (cl < fs->n_fatent); /* Repeat until end of chain */ } *fp->cltbl = ulen; /* Number of items used */ - if (ulen <= tlen) + if (ulen <= tlen) { *tbl = 0; /* Terminate table */ - else + } else { res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ - + } } else { /* Fast seek */ - if (ofs > fp->fsize) /* Clip offset at the file size */ - ofs = fp->fsize; + if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ if (ofs) { fp->clust = clmt_clust(fp, ofs - 1); - dsc = clust2sect(fp->fs, fp->clust); - if (!dsc) ABORT(fp->fs, FR_INT_ERR); - dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); - if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ + dsc = clust2sect(fs, fp->clust); + if (!dsc) ABORT(fs, FR_INT_ERR); + dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); + if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fp, FR_DISK_ERR); + fp->flag &= ~FA_DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ - ABORT(fp->fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) { /* Load current sector */ + ABORT(fs, FR_DISK_ERR); + } #endif - fp->dsect = dsc; + fp->sect = dsc; } } } @@ -3100,29 +4008,26 @@ FRESULT f_lseek ( /* Normal Seek */ { - if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ -#if !_FS_READONLY - && !(fp->flag & FA_WRITE) -#endif - ) ofs = fp->fsize; - + if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + ofs = fp->obj.objsize; + } ifptr = fp->fptr; fp->fptr = nsect = 0; if (ofs) { - bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ - clst = fp->sclust; /* start from the first cluster */ + clst = fp->obj.sclust; /* start from the first cluster */ #if !_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ - clst = create_chain(fp->fs, 0); - if (clst == 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->sclust = clst; + clst = create_chain(&fp->obj, 0); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->obj.sclust = clst; } #endif fp->clust = clst; @@ -3131,50 +4036,50 @@ FRESULT f_lseek ( while (ofs > bcs) { /* Cluster following loop */ #if !_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ + clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */ if (clst == 0) { /* When disk gets full, clip file size */ ofs = bcs; break; } } else #endif - clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); + clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; fp->fptr += bcs; ofs -= bcs; } fp->fptr += ofs; - if (ofs % SS(fp->fs)) { - nsect = clust2sect(fp->fs, clst); /* Current sector */ - if (!nsect) ABORT(fp->fs, FR_INT_ERR); - nsect += ofs / SS(fp->fs); + if (ofs % SS(fs)) { + nsect = clust2sect(fs, clst); /* Current sector */ + if (!nsect) ABORT(fs, FR_INT_ERR); + nsect += (DWORD)(ofs / SS(fs)); } } } - if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ + if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= ~FA_DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) { /* Fill sector cache */ + ABORT(fs, FR_DISK_ERR); + } #endif - fp->dsect = nsect; + fp->sect = nsect; } #if !_FS_READONLY - if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ - fp->fsize = fp->fptr; - fp->flag |= FA__WRITTEN; + if (fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; } #endif } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fs, res); } @@ -3190,45 +4095,59 @@ FRESULT f_opendir ( ) { FRESULT res; - FATFS* fs; - DEFINE_NAMEBUF; + FATFS *fs; + _FDID *obj; + DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive number */ - res = find_volume(&fs, &path, 0); + obj = &dp->obj; + res = find_volume(&path, &fs, 0); if (res == FR_OK) { - dp->fs = fs; - INIT_BUF(*dp); + obj->fs = fs; + INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ - FREE_BUF(); if (res == FR_OK) { /* Follow completed */ - if (dp->dir) { /* It is not the origin directory itself */ - if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ - dp->sclust = ld_clust(fs, dp->dir); - else /* The object is a file */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (obj->attr & AM_DIR) { /* This object is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Save containing directory inforamation */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + } + } else { /* This object is a file */ res = FR_NO_PATH; + } } if (res == FR_OK) { - dp->id = fs->id; + obj->id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if _FS_LOCK +#if _FS_LOCK != 0 if (res == FR_OK) { - if (dp->sclust) { - dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ - if (!dp->lockid) - res = FR_TOO_MANY_OPEN_FILES; + if (obj->sclust) { + obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES; } else { - dp->lockid = 0; /* Root directory need not to be locked */ + obj->lockid = 0; /* Root directory need not to be locked */ } } #endif } } + FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } @@ -3245,19 +4164,20 @@ FRESULT f_closedir ( ) { FRESULT res; + FATFS *fs; - res = validate(dp); + res = validate(dp, &fs); if (res == FR_OK) { -#if _FS_REENTRANT - FATFS *fs = dp->fs; -#endif -#if _FS_LOCK - if (dp->lockid) /* Decrement sub-directory open counter */ - res = dec_lock(dp->lockid); +#if _FS_LOCK != 0 + if (dp->obj.lockid) { /* Decrement sub-directory open counter */ + res = dec_lock(dp->obj.lockid); + } if (res == FR_OK) #endif - dp->fs = 0; /* Invalidate directory object */ + { + dp->obj.fs = 0; /* Invalidate directory object */ + } #if _FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif @@ -3278,40 +4198,34 @@ FRESULT f_readdir ( ) { FRESULT res; - DEFINE_NAMEBUF; + FATFS *fs; + DEF_NAMBUF - res = validate(dp); /* Check validity of the object */ + res = validate(dp, &fs); /* Check validity of the object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { - INIT_BUF(*dp); + INIT_NAMBUF(fs); res = dir_read(dp, 0); /* Read an item */ - if (res == FR_NO_FILE) { /* Reached end of directory */ - dp->sect = 0; - res = FR_OK; - } + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ - if (res == FR_NO_FILE) { - dp->sect = 0; - res = FR_OK; - } + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } - FREE_BUF(); + FREE_NAMBUF(); } } - - LEAVE_FF(dp->fs, res); + LEAVE_FF(fs, res); } #if _USE_FIND /*-----------------------------------------------------------------------*/ -/* Find next file */ +/* Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( @@ -3325,19 +4239,18 @@ FRESULT f_findnext ( for (;;) { res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ -#if _USE_LFN - if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */ + if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ +#if _USE_LFN != 0 && _USE_FIND == 2 + if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif - if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */ } return res; - } /*-----------------------------------------------------------------------*/ -/* Find first file */ +/* Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( @@ -3352,8 +4265,9 @@ FRESULT f_findfirst ( dp->pat = pattern; /* Save pointer to pattern string */ res = f_opendir(dp, path); /* Open the target directory */ - if (res == FR_OK) + if (res == FR_OK) { res = f_findnext(dp, fno); /* Find the first item */ + } return res; } @@ -3373,25 +4287,25 @@ FRESULT f_stat ( { FRESULT res; DIR dj; - DEFINE_NAMEBUF; + DEF_NAMBUF /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); + res = find_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ - if (dj.dir) { /* Found an object */ - if (fno) get_fileinfo(&dj, fno); - } else { /* It is root directory */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ res = FR_INVALID_NAME; + } else { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); } } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(dj.obj.fs, res); } @@ -3411,52 +4325,73 @@ FRESULT f_getfree ( FATFS *fs; DWORD nfree, clst, sect, stat; UINT i; - BYTE fat, *p; + BYTE *p; + _FDID obj; /* Get logical drive number */ - res = find_volume(fatfs, &path, 0); - fs = *fatfs; + res = find_volume(&path, &fs, 0); if (res == FR_OK) { - /* If free_clust is valid, return it without full cluster scan */ - if (fs->free_clust <= fs->n_fatent - 2) { - *nclst = fs->free_clust; + *fatfs = fs; /* Return ptr to the fs object */ + /* If free_clst is valid, return it without full cluster scan */ + if (fs->free_clst <= fs->n_fatent - 2) { + *nclst = fs->free_clst; } else { /* Get number of free clusters */ - fat = fs->fs_type; nfree = 0; - if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */ - clst = 2; + if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */ + clst = 2; obj.fs = fs; do { - stat = get_fat(fs, clst); + stat = get_fat(&obj, clst); if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); - } else { /* Sector alighed entries: Accelerate the FAT search. */ - clst = fs->n_fatent; sect = fs->fatbase; - i = 0; p = 0; - do { - if (!i) { - res = move_window(fs, sect++); - if (res != FR_OK) break; - p = fs->win; - i = SS(fs); - } - if (fat == FS_FAT16) { - if (LD_WORD(p) == 0) nfree++; - p += 2; i -= 2; - } else { - if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++; - p += 4; i -= 4; - } - } while (--clst); + } else { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */ + BYTE bm; + UINT b; + + clst = fs->n_fatent - 2; + sect = fs->database; + i = 0; + do { + if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break; + for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { + if (!(bm & 1)) nfree++; + bm >>= 1; + } + i = (i + 1) % SS(fs); + } while (clst); + } else +#endif + { /* FAT16/32: Sector alighed FAT entries */ + clst = fs->n_fatent; sect = fs->fatbase; + i = 0; p = 0; + do { + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + p = fs->win; + i = SS(fs); + } + if (fs->fs_type == FS_FAT16) { + if (ld_word(p) == 0) nfree++; + p += 2; i -= 2; + } else { + if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++; + p += 4; i -= 4; + } + } while (--clst); + } } - fs->free_clust = nfree; /* free_clust is valid */ - fs->fsi_flag |= 1; /* FSInfo is to be updated */ *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FSInfo is to be updated */ } } + LEAVE_FF(fs, res); } @@ -3472,55 +4407,49 @@ FRESULT f_truncate ( ) { FRESULT res; + FATFS *fs; DWORD ncl; - res = validate(fp); /* Check validity of the object */ - if (res == FR_OK) { - if (fp->err) { /* Check error */ - res = (FRESULT)fp->err; - } else { - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - res = FR_DENIED; - } - } - if (res == FR_OK) { - if (fp->fsize > fp->fptr) { - fp->fsize = fp->fptr; /* Set file size to current R/W point */ - fp->flag |= FA__WRITTEN; - if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ - res = remove_chain(fp->fs, fp->sclust); - fp->sclust = 0; - } else { /* When truncate a part of the file, remove remaining clusters */ - ncl = get_fat(fp->fs, fp->clust); - res = FR_OK; - if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (ncl == 1) res = FR_INT_ERR; - if (res == FR_OK && ncl < fp->fs->n_fatent) { - res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); - if (res == FR_OK) res = remove_chain(fp->fs, ncl); - } + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + if (fp->obj.objsize > fp->fptr) { + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fp->obj.sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(&fp->obj, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fs->n_fatent) { + res = remove_chain(&fp->obj, ncl, fp->clust); } + } + fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA_MODIFIED; #if !_FS_TINY - if (res == FR_OK && (fp->flag & FA__DIRTY)) { - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - res = FR_DISK_ERR; - else - fp->flag &= ~FA__DIRTY; + if (res == FR_OK && (fp->flag & FA_DIRTY)) { + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fp->flag &= ~FA_DIRTY; } -#endif } - if (res != FR_OK) fp->err = (FRESULT)res; +#endif + if (res != FR_OK) ABORT(fs, res); } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ -/* Delete a File or Directory */ +/* Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( @@ -3529,60 +4458,86 @@ FRESULT f_unlink ( { FRESULT res; DIR dj, sdj; - BYTE *dir; DWORD dclst = 0; - DEFINE_NAMEBUF; + FATFS *fs; +#if _FS_EXFAT + _FDID obj; +#endif + DEF_NAMBUF /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); + res = find_volume(&path, &fs, FA_WRITE); + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ -#if _FS_LOCK - if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */ + } +#if _FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ - dir = dj.dir; - if (!dir) { + if (dj.fn[NSFLAG] & NS_NONAME) { res = FR_INVALID_NAME; /* Cannot remove the origin directory */ } else { - if (dir[DIR_Attr] & AM_RDO) + if (dj.obj.attr & AM_RDO) { res = FR_DENIED; /* Cannot remove R/O object */ + } } if (res == FR_OK) { - dclst = ld_clust(dj.fs, dir); - if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ -#if _FS_RPATH - if (dclst == dj.fs->cdir) { /* Is it the current directory? */ +#if _FS_EXFAT + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus); + obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ +#if _FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { - mem_cpy(&sdj, &dj, sizeof (DIR)); /* Open the sub-directory */ - sdj.sclust = dclst; - res = dir_sdi(&sdj, 2); + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } +#endif + res = dir_sdi(&sdj, 0); if (res == FR_OK) { - res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */ - if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */ - if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */ + res = dir_read(&sdj, 0); /* Read an item */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } } if (res == FR_OK) { - res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst) /* Remove the cluster chain if exist */ - res = remove_chain(dj.fs, dclst); - if (res == FR_OK) res = sync_fs(dj.fs); + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */ +#if _FS_EXFAT + res = remove_chain(&obj, dclst, 0); +#else + res = remove_chain(&dj.obj, dclst, 0); +#endif + } + if (res == FR_OK) res = sync_fs(fs); } } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } @@ -3598,70 +4553,191 @@ FRESULT f_mkdir ( { FRESULT res; DIR dj; - BYTE *dir, n; - DWORD dsc, dcl, pcl, tm = GET_FATTIME(); - DEFINE_NAMEBUF; + FATFS *fs; + BYTE *dir; + UINT n; + DWORD dsc, dcl, pcl, tm; + DEF_NAMBUF /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); + res = find_volume(&path, &fs, FA_WRITE); + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; + } if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ + dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ + dj.obj.objsize = (DWORD)fs->csize * SS(fs); res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ if (dcl == 1) res = FR_INT_ERR; if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) /* Flush FAT */ - res = sync_window(dj.fs); + if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + tm = GET_FATTIME(); if (res == FR_OK) { /* Initialize the new directory table */ - dsc = clust2sect(dj.fs, dcl); - dir = dj.fs->win; - mem_set(dir, 0, SS(dj.fs)); - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - ST_DWORD(dir + DIR_WrtTime, tm); - st_clust(dir, dcl); - mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ - dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust; - if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) - pcl = 0; - st_clust(dir + SZ_DIRE, pcl); - for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ - dj.fs->winsect = dsc++; - dj.fs->wflag = 1; - res = sync_window(dj.fs); + dsc = clust2sect(fs, dcl); + dir = fs->win; + mem_set(dir, 0, SS(fs)); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + st_dword(dir + DIR_ModTime, tm); + st_clust(fs, dir, dcl); + mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ + dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0; + st_clust(fs, dir + SZDIRE, pcl); + } + for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + fs->winsect = dsc++; + fs->wflag = 1; + res = sync_window(fs); if (res != FR_OK) break; - mem_set(dir, 0, SS(dj.fs)); + mem_set(dir, 0, SS(fs)); } } if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ - if (res != FR_OK) { - remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ + st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */ + fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ + res = store_xdir(&dj); + } else +#endif + { + dir = dj.dir; + st_dword(dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dir, dcl); /* Table start cluster */ + dir[DIR_Attr] = AM_DIR; /* Attribute */ + fs->wflag = 1; + } + if (res == FR_OK) res = sync_fs(fs); } else { - dir = dj.dir; - dir[DIR_Attr] = AM_DIR; /* Attribute */ - ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ - st_clust(dir, dcl); /* Table start cluster */ - dj.fs->wflag = 1; - res = sync_fs(dj.fs); + remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ } } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } +/*-----------------------------------------------------------------------*/ +/* Rename a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR* path_old, /* Pointer to the object name to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + FATFS *fs; + BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; + DWORD dw; + DEF_NAMBUF + + + get_ldnumber(&path_new); /* Ignore drive number of new name */ + res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive number of the old object */ + if (res == FR_OK) { + djo.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&djo, path_old); /* Check old object */ + if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ +#if _FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&djo, 2); +#endif + if (res == FR_OK) { /* Object to be renamed is found */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT */ + BYTE nf, nn; + WORD nh; + + mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + mem_cpy(&djn, &djo, sizeof djo); + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; + nh = ld_word(fs->dirbuf + XDIR_NameHash); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; + st_word(fs->dirbuf + XDIR_NameHash, nh); +/* Start of critical section where any interruption can cause a cross-link */ + res = store_xdir(&djn); + } + } + } else +#endif + { /* At FAT12/FAT16/FAT32 */ + mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ + mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + dir = djn.dir; /* Copy information about object except name */ + mem_cpy(dir + 13, buf + 2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ + dw = clust2sect(fs, ld_clust(fs, dir)); + if (!dw) { + res = FR_INT_ERR; + } else { +/* Start of critical section where any interruption can cause a cross-link */ + res = move_window(fs, dw); + dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(fs, dir, djn.obj.sclust); + fs->wflag = 1; + } + } + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { + res = sync_fs(fs); + } + } +/* End of critical section */ + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + +#if _USE_CHMOD && !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ @@ -3674,109 +4750,34 @@ FRESULT f_chmod ( { FRESULT res; DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; + FATFS *fs; + DEF_NAMBUF - res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */ + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - FREE_BUF(); - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { - dir = dj.dir; - if (!dir) { /* Is it a root directory? */ - res = FR_INVALID_NAME; - } else { /* File or sub directory */ - mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ - dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } - } - } - - LEAVE_FF(dj.fs, res); -} - - - - -/*-----------------------------------------------------------------------*/ -/* Rename File/Directory */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_rename ( - const TCHAR* path_old, /* Pointer to the object to be renamed */ - const TCHAR* path_new /* Pointer to the new name */ -) -{ - FRESULT res; - DIR djo, djn; - BYTE buf[21], *dir; - DWORD dw; - DEFINE_NAMEBUF; - - - /* Get logical drive number of the source object */ - res = find_volume(&djo.fs, &path_old, 1); - if (res == FR_OK) { - djn.fs = djo.fs; - INIT_BUF(djo); - res = follow_path(&djo, path_old); /* Check old object */ - if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; -#if _FS_LOCK - if (res == FR_OK) res = chk_lock(&djo, 2); + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = store_xdir(&dj); + } else #endif - if (res == FR_OK) { /* Old object is found */ - if (!djo.dir) { /* Is root dir? */ - res = FR_NO_FILE; - } else { - mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */ - mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ - if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ - res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */ - else - res = FR_INVALID_DRIVE; - if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ - if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ - res = dir_register(&djn); /* Register the new entry */ - if (res == FR_OK) { -/* Start of critical section where any interruption can cause a cross-link */ - dir = djn.dir; /* Copy information about object except name */ - mem_cpy(dir + 13, buf + 2, 19); - dir[DIR_Attr] = buf[0] | AM_ARC; - djo.fs->wflag = 1; - if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */ - dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); - if (!dw) { - res = FR_INT_ERR; - } else { - res = move_window(djo.fs, dw); - dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */ - if (res == FR_OK && dir[1] == '.') { - st_clust(dir, djn.sclust); - djo.fs->wflag = 1; - } - } - } - if (res == FR_OK) { - res = dir_remove(&djo); /* Remove old entry */ - if (res == FR_OK) - res = sync_fs(djo.fs); - } -/* End of critical section */ - } - } + { + dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + fs->wflag = 1; } + if (res == FR_OK) res = sync_fs(fs); } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(djo.fs, res); + LEAVE_FF(fs, res); } @@ -3793,45 +4794,42 @@ FRESULT f_utime ( { FRESULT res; DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; + FATFS *fs; + DEF_NAMBUF - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - FREE_BUF(); - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { - dir = dj.dir; - if (!dir) { /* Root directory */ - res = FR_INVALID_NAME; - } else { /* File or sub-directory */ - ST_WORD(dir + DIR_WrtTime, fno->ftime); - ST_WORD(dir + DIR_WrtDate, fno->fdate); - dj.fs->wflag = 1; - res = sync_fs(dj.fs); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + res = store_xdir(&dj); + } else +#endif + { + st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->wflag = 1; } + if (res == FR_OK) res = sync_fs(fs); } + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ -#endif /* _FS_MINIMIZE == 0 */ -#endif /* _FS_MINIMIZE <= 1 */ -#endif /* _FS_MINIMIZE <= 2 */ - +#endif /* _USE_CHMOD && !_FS_READONLY */ #if _USE_LABEL /*-----------------------------------------------------------------------*/ -/* Get volume label */ +/* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( @@ -3842,63 +4840,85 @@ FRESULT f_getlabel ( { FRESULT res; DIR dj; - UINT i, j; -#if _USE_LFN && _LFN_UNICODE + FATFS *fs; + UINT si, di; +#if _LFN_UNICODE || _FS_EXFAT WCHAR w; #endif - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); + res = find_volume(&path, &fs, 0); /* Get volume label */ if (res == FR_OK && label) { - dj.sclust = 0; /* Open root directory */ + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ - if (res == FR_OK) { /* A volume label is exist */ -#if _USE_LFN && _LFN_UNICODE - i = j = 0; - do { - w = (i < 11) ? dj.dir[i++] : ' '; - if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) - w = w << 8 | dj.dir[i++]; - label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ - } while (j < 11); + res = dir_read(&dj, 1); /* Find a volume label entry */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + w = ld_word(dj.dir + XDIR_Label + si * 2); +#if _LFN_UNICODE + label[di++] = w; #else - mem_cpy(label, dj.dir, 11); + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) w = '?'; /* Replace wrong character */ + if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8); + label[di++] = (char)w; #endif - j = 11; - do { - label[j] = 0; - if (!j) break; - } while (label[--j] == ' '); - } - if (res == FR_NO_FILE) { /* No label, return nul string */ - label[0] = 0; - res = FR_OK; + } + label[di] = 0; + } else +#endif + { + si = di = 0; /* Extract volume label from AM_VOL entry with code comversion */ + do { +#if _LFN_UNICODE + w = (si < 11) ? dj.dir[si++] : ' '; + if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) { + w = w << 8 | dj.dir[si++]; + } + label[di++] = ff_convert(w, 1); /* OEM -> Unicode */ +#else + label[di++] = dj.dir[si++]; +#endif + } while (di < 11); + do { /* Truncate trailing spaces */ + label[di] = 0; + if (di == 0) break; + } while (label[--di] == ' '); + } } } + if (res == FR_NO_FILE) { /* No label entry and return nul string */ + label[0] = 0; + res = FR_OK; + } } /* Get volume serial number */ if (res == FR_OK && vsn) { - res = move_window(dj.fs, dj.fs->volbase); + res = move_window(fs, fs->volbase); if (res == FR_OK) { - i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; - *vsn = LD_DWORD(&dj.fs->win[i]); + switch (fs->fs_type) { + case FS_EXFAT: di = BPB_VolIDEx; break; + case FS_FAT32: di = BS_VolID32; break; + default: di = BS_VolID; + } + *vsn = ld_dword(fs->win + di); } } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } #if !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Set volume label */ +/* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( @@ -3907,84 +4927,115 @@ FRESULT f_setlabel ( { FRESULT res; DIR dj; - BYTE vn[11]; - UINT i, j, sl; + FATFS *fs; + BYTE dirvn[22]; + UINT i, j, slen; WCHAR w; - DWORD tm; + static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; /* Get logical drive number */ - res = find_volume(&dj.fs, &label, 1); - if (res) LEAVE_FF(dj.fs, res); + res = find_volume(&label, &fs, FA_WRITE); + if (res != FR_OK) LEAVE_FF(fs, res); + dj.obj.fs = fs; - /* Create a volume label in directory form */ - vn[0] = 0; - for (sl = 0; label[sl]; sl++) ; /* Get name length */ - for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */ - if (sl) { /* Create volume label in directory form */ - i = j = 0; - do { -#if _USE_LFN && _LFN_UNICODE - w = ff_convert(ff_wtoupper(label[i++]), 0); + /* Get length of given volume label */ + for (slen = 0; (UINT)label[slen] >= ' '; slen++) ; /* Get name length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ + w = label[i++]; +#if !_LFN_UNICODE + if (IsDBCS1(w)) { + w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } + w = ff_convert(w, 1); +#endif + if (w == 0 || chk_chr(badchr, w) || j == 22) { /* Check validity check validity of the volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + st_word(dirvn + j, w); j += 2; + } + slen = j; + } else +#endif + { /* At the FAT12/16/32 */ + for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ + if (slen) { /* Is there a volume label to be set? */ + dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ + do { +#if _LFN_UNICODE + w = ff_convert(ff_wtoupper(label[i++]), 0); #else - w = (BYTE)label[i++]; - if (IsDBCS1(w)) - w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; -#if _USE_LFN - w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); + w = (BYTE)label[i++]; + if (IsDBCS1(w)) { + w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } +#if _USE_LFN != 0 + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); #else - if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ + if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ #ifdef _EXCVT - if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ + if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ #else - if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ + if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ #endif #endif #endif - if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ - LEAVE_FF(dj.fs, FR_INVALID_NAME); - if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); - vn[j++] = (BYTE)w; - } while (i < sl); - while (j < 11) vn[j++] = ' '; /* Fill remaining name field */ - if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8); + dirvn[j++] = (BYTE)w; + } while (i < slen); + while (j < 11) dirvn[j++] = ' '; /* Fill remaining name field */ + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + } } /* Set volume label */ - dj.sclust = 0; /* Open root directory */ + dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ - if (res == FR_OK) { /* A volume label is found */ - if (vn[0]) { - mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ - tm = GET_FATTIME(); - ST_DWORD(dj.dir + DIR_WrtTime, tm); + res = dir_read(&dj, 1); /* Get volume label entry */ + if (res == FR_OK) { + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = slen / 2; /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); } else { - dj.dir[0] = DDEM; /* Remove the volume label */ + if (slen) { + mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ + } else { + dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ + } } - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } else { /* No volume label is found or error */ + fs->wflag = 1; + res = sync_fs(fs); + } else { /* No volume label entry is found or error */ if (res == FR_NO_FILE) { res = FR_OK; - if (vn[0]) { /* Create volume label as new */ - res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ + if (slen) { /* Create a volume label entry */ + res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { - mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ - mem_cpy(dj.dir, vn, 11); - dj.dir[DIR_Attr] = AM_VOL; - tm = GET_FATTIME(); - ST_DWORD(dj.dir + DIR_WrtTime, tm); - dj.fs->wflag = 1; - res = sync_fs(dj.fs); + mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_NumLabel] = slen / 2; + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + } else { + dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ + mem_cpy(dj.dir, dirvn, 11); + } + fs->wflag = 1; + res = sync_fs(fs); } } } } } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } #endif /* !_FS_READONLY */ @@ -3992,10 +5043,94 @@ FRESULT f_setlabel ( +#if _USE_EXPAND && !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Forward data to the stream directly (available on only tiny cfg) */ +/* Allocate a Contiguous Blocks to the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_expand ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t fsz, /* File size to be expanded to */ + BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, stcl, scl, ncl, tcl, lclst; + + + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ +#endif + n = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; lclst = 0; + if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ + if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ + if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) { + if (opt) { + res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ + lclst = scl + tcl - 1; + } else { + lclst = scl - 1; + } + } + } else +#endif + { + scl = clst = stcl; ncl = 0; + for (;;) { /* Find a contiguous cluster block */ + n = get_fat(&fp->obj, clst); + if (++clst >= fs->n_fatent) clst = 2; + if (n == 1) { res = FR_INT_ERR; break; } + if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ + } else { + scl = clst; ncl = 0; /* Not a free cluster */ + } + if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + } + if (res == FR_OK) { + if (opt) { + for (clst = scl; tcl; clst++, tcl--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (tcl == 1) ? 0xFFFFFFFF : clst + 1); + if (res != FR_OK) break; + lclst = clst; + } + } else { + lclst = scl - 1; + } + } + } + + if (opt && res == FR_OK) { + fs->last_clst = lclst; /* Set suggested start cluster to start next */ + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + } + + LEAVE_FF(fs, res); +} + +#endif /* _USE_EXPAND && !_FS_READONLY */ + + + +#if _USE_FORWARD +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly */ /*-----------------------------------------------------------------------*/ -#if _USE_FORWARD && _FS_TINY FRESULT f_forward ( FIL* fp, /* Pointer to the file object */ @@ -4005,48 +5140,59 @@ FRESULT f_forward ( ) { FRESULT res; - DWORD remain, clst, sect; - UINT rcnt; - BYTE csect; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, csect; + BYTE *dbuf; *bf = 0; /* Clear transfer byte counter */ + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - res = validate(fp); /* Check validity of the object */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_READ)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - - remain = fp->fsize - fp->fptr; + remain = fp->obj.objsize - fp->fptr; if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ - for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - if (!csect) { /* On the cluster boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + if (csect == 0) { /* On the cluster boundary? */ clst = (fp->fptr == 0) ? /* On the top of the file? */ - fp->sclust : get_fat(fp->fs, fp->clust); - if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->obj.sclust : get_fat(&fp->obj, fp->clust); + if (clst <= 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } } - sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect = clust2sect(fs, fp->clust); /* Get current data sector */ + if (!sect) ABORT(fs, FR_INT_ERR); sect += csect; - if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - fp->dsect = sect; - rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ - if (rcnt > btf) rcnt = btf; - rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); - if (!rcnt) ABORT(fp->fs, FR_INT_ERR); +#if _FS_TINY + if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ + dbuf = fs->win; +#else + if (fp->sect != sect) { /* Fill sector cache with file data */ +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= ~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + dbuf = fp->buf; +#endif + fp->sect = sect; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ + rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ + if (!rcnt) ABORT(fs, FR_INT_ERR); } - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fs, FR_OK); } #endif /* _USE_FORWARD */ @@ -4054,249 +5200,452 @@ FRESULT f_forward ( #if _USE_MKFS && !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Create file system on the logical drive */ +/* Create FAT file system on the logical drive */ /*-----------------------------------------------------------------------*/ -#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ -#define N_FATS 1 /* Number of FATs (1 or 2) */ - FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ - BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ - UINT au /* Size of allocation unit in unit of byte or sector */ + BYTE opt, /* Format option */ + DWORD au, /* Size of allocation unit [byte] */ + void* work, /* Pointer to working buffer */ + UINT len /* Size of working buffer */ ) { - static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; - static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; + const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4KS unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128KS unit) */ + BYTE fmt, sys, *buf, *pte, pdrv, part; + WORD ss; + DWORD n, pau, n_clst, sz_blk, sect, szb_buf, sz_buf; + DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ + DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ + UINT i, ns; int vol; - BYTE fmt, md, sys, *tbl, pdrv, part; - DWORD n_clst, vs, n, wsect; - UINT i; - DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ - DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ - FATFS *fs; DSTATUS stat; -#if _USE_TRIM - DWORD eb[2]; +#if _USE_TRIM || _FS_EXFAT + DWORD tbl[3]; #endif /* Check mounted drive and clear work area */ - if (sfd > 1) return FR_INVALID_PARAMETER; - vol = get_ldnumber(&path); + vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; - fs = FatFs[vol]; - if (!fs) return FR_NOT_ENABLED; - fs->fs_type = 0; + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear mounted volume */ pdrv = LD2PD(vol); /* Physical drive */ - part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ + part = LD2PT(vol); /* Partition (0:create as new, 1-4:get by partition table) */ - /* Get disk statics */ + /* Check physical drive status */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; -#if _MAX_SS != _MIN_SS /* Get disk sector size */ - if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) - return FR_DISK_ERR; + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; +#if _MAX_SS != _MIN_SS /* Get sector size of the medium */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; + if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = _MAX_SS; #endif - if (_MULTI_PARTITION && part) { + if ((au != 0 && au < ss) || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ + au /= ss; /* Cluster size in byte to in sector */ + if (au > 32768) return FR_INVALID_PARAMETER; + + /* Set size and pointer of the working buffer */ + buf = (BYTE*)work; /* Use given working buffer */ + if (len < ss) return FR_MKFS_ABORTED; + szb_buf = len & ~(ss - 1); /* Round-down by sector size [byte] */ + sz_buf = szb_buf / ss; /* Size of sector buffer [sector] */ + + /* Determine where the volume to be located (b_vol, sz_vol) */ + if (_MULTI_PARTITION && part != 0) { /* Get partition information from partition table in the MBR */ - if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; - if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ - b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ - n_vol = LD_DWORD(tbl + 12); /* Volume size */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check MBR is valid */ + pte = buf + (MBR_Table + (part - 1) * SZ_PTE); + if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } else { - /* Create a partition in this function */ - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) - return FR_DISK_ERR; - b_vol = (sfd) ? 0 : 63; /* Volume start sector */ - n_vol -= b_vol; /* Volume size */ + /* Create a single-partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR; + b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + if (sz_vol < b_vol) return FR_MKFS_ABORTED; + sz_vol -= b_vol; /* Volume size */ } + if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check volume size (>=128s) */ - if (au & (au - 1)) au = 0; - if (!au) { /* AU auto selection */ - vs = n_vol / (2000 / (SS(fs) / 512)); - for (i = 0; vs < vst[i]; i++) ; - au = cst[i]; + /* Pre-determine the FAT type by argument */ + do { + if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au >= 256) { /* exFAT only, vol >= 64Ms or au >= 256s ? */ + fmt = FS_EXFAT; break; + } + } + if (au >= 256) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (opt & FM_FAT32) { /* FAT32 possible? */ + if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ + fmt = FS_FAT32; break; + } + } + if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */ + fmt = FS_FAT16; + } while (0); + +#if _FS_EXFAT + if (fmt == FS_EXFAT) { /* Create an exFAT volume */ + DWORD sum, szb_bit, szb_case; + WCHAR ch, si; + UINT j, st; + BYTE b; + + if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Determine FAT location, data location and number of clusters */ + if (!au) { /* au auto-selection */ + au = 8; + if (sz_vol >= 0x80000) au = 64; /* >= 512KS */ + if (sz_vol >= 0x4000000) au = 256; /* >= 64MS */ + } + b_fat = b_vol + 32; /* FAT start at offset 32 */ + sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Numbef of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ + if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ + n_clst = (sz_vol - (b_data - b_vol)) / au; /* Nunber of clusters */ + if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ + if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ + + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of bitmap clusters */ + tbl[2] = 1; /* Number of rootdir clusters */ + + /* Create a compressed up-case table */ + sect = b_data + au * tbl[0]; /* Table start sector */ + sum = 0; /* Table checksum to be stored in the 82 entry */ + st = si = i = j = szb_case = 0; + do { + switch (st) { + case 0: + ch = ff_wtoupper(si); /* Get an up-case char */ + if (ch != si) { + si++; break; /* Store the up-case char if exist */ + } + for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ + if (j >= 128) { + ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ + } + st = 1; /* Do not compress short run */ + /* continue */ + case 1: + ch = si++; /* Fill the short run */ + if (--j == 0) st = 0; + break; + default: + ch = (WCHAR)j; si += j; /* Number of chars to skip */ + st = 0; + } + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); + i += 2; szb_case += 2; + if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + ns = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; + sect += ns; i = 0; + } + } while (si); + tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case clusters */ + + /* Initialize the allocation bitmap */ + mem_set(buf, 0, szb_buf); /* Set in-use flags of bitmap, up-case and root dir */ + for (i = 0, n = tbl[0] + tbl[1] + tbl[2]; n >= 8; buf[i++] = 0xFF, n -= 8) ; + for (b = 1; n; buf[i] |= b, b <<= 1, n--) ; + sect = b_data; n = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of the sectors */ + do { /* Fill allocation bitmap sectors */ + ns = (n > sz_buf) ? sz_buf : n; + if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; + sect += ns; + mem_set(buf, 0, ss); + } while (n -= ns); + + /* Initialize the FAT */ + st_qword(buf, 0xFFFFFFFFFFFFFFF8); /* Entry 0 and 1 */ + for (j = 0, i = 2; j < 3; j++) { /* Set entries of bitmap, up-case and root dir */ + for (n = tbl[j]; n; n--) { + st_dword(buf + i * 4, (n >= 2) ? i + 1 : 0xFFFFFFFF); + i++; + } + } + sect = b_fat; n = sz_fat; /* Start of FAT and number of the sectors */ + do { /* Fill FAT sectors */ + ns = (n > sz_buf) ? sz_buf : n; + if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; + sect += ns; + mem_set(buf, 0, ss); + } while (n -= ns); + + /* Initialize the root directory */ + mem_set(buf, 0, ss); + buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ + buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ + st_dword(buf + SZDIRE * 1 + 20, 2); + st_dword(buf + SZDIRE * 1 + 24, szb_bit); + buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ + st_dword(buf + SZDIRE * 2 + 4, sum); + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); + st_dword(buf + SZDIRE * 2 + 24, szb_case); + sect = b_data + au * (tbl[0] + tbl[1]); n = au; /* Start of directory and number of the sectors */ + do { /* Fill root direcotry sectors */ + ns = (n > sz_buf) ? sz_buf : n; + if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; + sect += ns; + mem_set(buf, 0, ss); + } while (n -= ns); + + /* Create two set of the exFAT VBR blocks */ + sect = b_vol; + for (n = 0; n < 2; n++) { + /* Main record (+0) */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ + st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ + st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ + st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */ + for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ + for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + buf[BPB_NumFATsEx] = 1; /* Number of FATs */ + buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ + st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + for (i = sum = 0; i < ss; i++) { /* VBR checksum */ + if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); + } + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + /* Extended bootstrap record (+1..+8) */ + mem_set(buf, 0, ss); + st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + for (j = 1; j < 9; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* OEM/Reserved record (+9..+10) */ + mem_set(buf, 0, ss); + for ( ; j < 11; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* Sum record (+11) */ + for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + + } else +#endif + { /* Create an FAT12/16/32 volume */ + do { + pau = au; + /* Pre-determine number of clusters and FAT sub-type */ + if (fmt == FS_FAT32) { /* FAT32 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ + for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; /* Number of clusters */ + sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 32; /* Number of reserved sectors */ + sz_dir = 0; /* No static directory */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED; + } else { /* FAT12/16 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ + for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; + if (n_clst > MAX_FAT12) { + n = n_clst * 2 + 4; /* FAT size [byte] */ + } else { + fmt = FS_FAT12; + n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ + } + sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 1; /* Number of reserved sectors */ + sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ + } + b_fat = b_vol + sz_rsv; /* FAT base */ + b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ + + /* Align data base to erase block boundary (for flash memory media) */ + n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ + if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ + sz_rsv += n; b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + sz_fat += n / n_fats; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; + if (fmt == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ + if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT16) { + if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ + if (!au && (pau * 2) <= 64) { + au = pau * 2; continue; /* Adjust cluster size and retry */ + } + if ((opt & FM_FAT32)) { + fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + } + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */ + + /* Ok, it is the valid cluster configuration */ + break; + } while (1); + +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Create FAT VBR */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ + st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ + buf[BPB_NumFATs] = n_fats; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ + if (sz_vol < 0x10000) { + st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ + } else { + st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 12-bit LBA */ + } + buf[BPB_Media] = 0xF8; /* Media descriptor */ + st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ + if (fmt == FS_FAT32) { + st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */ + + /* Create FSINFO record if needed */ + if (fmt == FS_FAT32) { + disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ + mem_set(buf, 0, ss); + st_dword(buf + FSI_LeadSig, 0x41615252); + st_dword(buf + FSI_StrucSig, 0x61417272); + st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(buf + BS_55AA, 0xAA55); + disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ + disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ + } + + /* Initialize FAT area */ + mem_set(buf, 0, szb_buf); + sect = b_fat; /* Start sector */ + for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ + if (fmt == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ + st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ + st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ + } else { + st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ + } + n = sz_fat; /* Sector count of a FAT */ + do { /* Fill FAT sectors */ + ns = (n > sz_buf) ? sz_buf : n; + if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; + sect += ns; + mem_set(buf, 0, ss); + } while (n -= ns); + } + + /* Initialize root directory (fill with zero) */ + n = (fmt == FS_FAT32) ? pau : sz_dir; /* Sector count of root directory */ + do { + ns = (n > sz_buf) ? sz_buf : n; + if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; + sect += ns; + } while (n -= ns); } - if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */ - if (!au) au = 1; - if (au > 128) au = 128; - - /* Pre-compute number of clusters and FAT sub-type */ - n_clst = n_vol / au; - fmt = FS_FAT12; - if (n_clst >= MIN_FAT16) fmt = FS_FAT16; - if (n_clst >= MIN_FAT32) fmt = FS_FAT32; - - /* Determine offset and size of FAT structure */ - if (fmt == FS_FAT32) { - n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); - n_rsv = 32; - n_dir = 0; - } else { - n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; - n_fat = (n_fat + SS(fs) - 1) / SS(fs); - n_rsv = 1; - n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); - } - b_fat = b_vol + n_rsv; /* FAT area start sector */ - b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ - b_data = b_dir + n_dir; /* Data area start sector */ - if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ - - /* Align data start sector to erase block boundary (for flash memory media) */ - if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; - n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ - n = (n - b_data) / N_FATS; - if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ - n_rsv += n; - b_fat += n; - } else { /* FAT12/16: Expand FAT size */ - n_fat += n; - } - - /* Determine number of clusters and final check of validity of the FAT sub-type */ - n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; - if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) - || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) - return FR_MKFS_ABORTED; /* Determine system ID in the partition table */ - if (fmt == FS_FAT32) { - sys = 0x0C; /* FAT32X */ + if (_FS_EXFAT && fmt == FS_EXFAT) { + sys = 0x07; /* HPFS/NTFS/exFAT */ } else { - if (fmt == FS_FAT12 && n_vol < 0x10000) { - sys = 0x01; /* FAT12(<65536) */ + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ } else { - sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ + if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (>=64KS) */ + } else { + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */ + } } } - if (_MULTI_PARTITION && part) { + if (_MULTI_PARTITION && part != 0) { /* Update system ID in the partition table */ - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - tbl[4] = sys; - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ - return FR_DISK_ERR; - md = 0xF8; + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system type */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ } else { - if (sfd) { /* No partition table (SFD) */ - md = 0xF0; - } else { /* Create partition table (FDISK) */ - mem_set(fs->win, 0, SS(fs)); - tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */ - tbl[1] = 1; /* Partition start head */ - tbl[2] = 1; /* Partition start sector */ - tbl[3] = 0; /* Partition start cylinder */ - tbl[4] = sys; /* System type */ - tbl[5] = 254; /* Partition end head */ - n = (b_vol + n_vol) / 63 / 255; - tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ - tbl[7] = (BYTE)n; /* End cylinder */ - ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ - ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ - ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */ - return FR_DISK_ERR; - md = 0xF8; + if (!(opt & FM_SFD)) { + /* Create partition table in FDISK format */ + mem_set(buf, 0, ss); + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ + pte[PTE_Boot] = 0; /* Boot indicator */ + pte[PTE_StHead] = 1; /* Start head */ + pte[PTE_StSec] = 1; /* Start sector */ + pte[PTE_StCyl] = 0; /* Start cylinder */ + pte[PTE_System] = sys; /* System type */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS is incorrect) */ + pte[PTE_EdHead] = 254; /* End head */ + pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ + pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ + st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ + st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ } } - /* Create BPB in the VBR */ - tbl = fs->win; /* Clear sector */ - mem_set(tbl, 0, SS(fs)); - mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ - i = SS(fs); /* Sector size */ - ST_WORD(tbl + BPB_BytsPerSec, i); - tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ - ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ - tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ - i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ - ST_WORD(tbl + BPB_RootEntCnt, i); - if (n_vol < 0x10000) { /* Number of total sectors */ - ST_WORD(tbl + BPB_TotSec16, n_vol); - } else { - ST_DWORD(tbl + BPB_TotSec32, n_vol); - } - tbl[BPB_Media] = md; /* Media descriptor */ - ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ - ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ - ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ - n = GET_FATTIME(); /* Use current time as VSN */ - if (fmt == FS_FAT32) { - ST_DWORD(tbl + BS_VolID32, n); /* VSN */ - ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ - ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ - ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ - ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */ - tbl[BS_DrvNum32] = 0x80; /* Drive number */ - tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ - } else { - ST_DWORD(tbl + BS_VolID, n); /* VSN */ - ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ - tbl[BS_DrvNum] = 0x80; /* Drive number */ - tbl[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ - } - ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ - if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ - return FR_DISK_ERR; - if (fmt == FS_FAT32) /* Write it to the backup VBR if needed (VBR + 6) */ - disk_write(pdrv, tbl, b_vol + 6, 1); + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR; - /* Initialize FAT area */ - wsect = b_fat; - for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ - mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ - n = md; /* Media descriptor byte */ - if (fmt != FS_FAT32) { - n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; - ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ - } else { - n |= 0xFFFFFF00; - ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ - ST_DWORD(tbl + 4, 0xFFFFFFFF); - ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ - } - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ - for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - } - } - - /* Initialize root directory */ - i = (fmt == FS_FAT32) ? au : (UINT)n_dir; - do { - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - } while (--i); - -#if _USE_TRIM /* Erase data area if needed */ - { - eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; - disk_ioctl(pdrv, CTRL_TRIM, eb); - } -#endif - - /* Create FSINFO if needed */ - if (fmt == FS_FAT32) { - ST_DWORD(tbl + FSI_LeadSig, 0x41615252); - ST_DWORD(tbl + FSI_StrucSig, 0x61417272); - ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ - ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ - ST_WORD(tbl + BS_55AA, 0xAA55); - disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ - disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ - } - - return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; + return FR_OK; } @@ -4308,7 +5657,7 @@ FRESULT f_mkfs ( FRESULT f_fdisk ( BYTE pdrv, /* Physical drive number */ - const DWORD szt[], /* Pointer to the size table for each partitions */ + const DWORD* szt, /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer */ ) { @@ -4323,7 +5672,7 @@ FRESULT f_fdisk ( if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - /* Determine CHS in the table regardless of the drive geometry */ + /* Determine the CHS without any care of the drive geometry */ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; if (n == 256) n--; e_hd = n - 1; @@ -4355,19 +5704,18 @@ FRESULT f_fdisk ( p[5] = e_hd; /* End head */ p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ - ST_DWORD(p + 8, s_part); /* Start sector in LBA */ - ST_DWORD(p + 12, sz_part); /* Partition size */ + st_dword(p + 8, s_part); /* Start sector in LBA */ + st_dword(p + 12, sz_part); /* Partition size */ /* Next partition */ b_cyl += p_cyl; } - ST_WORD(p, 0xAA55); + st_word(p, 0xAA55); /* Write it to the MBR */ return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; } - #endif /* _MULTI_PARTITION */ #endif /* _USE_MKFS && !_FS_READONLY */ @@ -4392,7 +5740,7 @@ TCHAR* f_gets ( while (n < len - 1) { /* Read characters until buffer gets filled */ -#if _USE_LFN && _LFN_UNICODE +#if _LFN_UNICODE #if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ f_read(fp, s, 1, &rc); if (rc != 1) break; @@ -4459,14 +5807,14 @@ TCHAR* f_gets ( /*-----------------------------------------------------------------------*/ typedef struct { - FIL* fp; - int idx, nchr; - BYTE buf[64]; + FIL *fp; /* Ptr to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of chars written */ + BYTE buf[64]; /* Write buffer */ } putbuff; static -void putc_bfd ( +void putc_bfd ( /* Buffered write with code conversion */ putbuff* pb, TCHAR c ) @@ -4475,13 +5823,14 @@ void putc_bfd ( int i; - if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ + if (_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ putc_bfd(pb, '\r'); + } - i = pb->idx; /* Buffer write index (-1:error) */ + i = pb->idx; /* Write index of pb->buf[] */ if (i < 0) return; -#if _USE_LFN && _LFN_UNICODE +#if _LFN_UNICODE #if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ if (c < 0x80) { /* 7-bit */ pb->buf[i++] = (BYTE)c; @@ -4520,6 +5869,31 @@ void putc_bfd ( } +static +int putc_flush ( /* Flush left characters in the buffer */ + putbuff* pb +) +{ + UINT nw; + + if ( pb->idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK + && (UINT)pb->idx == nw) return pb->nchr; + return EOF; +} + + +static +void putc_init ( /* Initialize write buffer */ + putbuff* pb, + FIL* fp +) +{ + pb->fp = fp; + pb->nchr = pb->idx = 0; +} + + int f_putc ( TCHAR c, /* A character to be output */ @@ -4527,18 +5901,11 @@ int f_putc ( ) { putbuff pb; - UINT nw; - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; - - putc_bfd(&pb, c); /* Put a character */ - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + putc_init(&pb, fp); + putc_bfd(&pb, c); /* Put the character */ + return putc_flush(&pb); } @@ -4554,19 +5921,11 @@ int f_puts ( ) { putbuff pb; - UINT nw; - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; - - while (*str) /* Put the string */ - putc_bfd(&pb, *str++); - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + putc_init(&pb, fp); + while (*str) putc_bfd(&pb, *str++); /* Put the string */ + return putc_flush(&pb); } @@ -4583,15 +5942,14 @@ int f_printf ( ) { va_list arp; - BYTE f, r; - UINT nw, i, j, w; - DWORD v; - TCHAR c, d, s[16], *p; putbuff pb; + BYTE f, r; + UINT i, j, w; + DWORD v; + TCHAR c, d, str[32], *p; - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; + putc_init(&pb, fp); va_start(arp, fmt); @@ -4656,21 +6014,18 @@ int f_printf ( do { d = (TCHAR)(v % r); v /= r; if (d > 9) d += (c == 'x') ? 0x27 : 0x07; - s[i++] = d + '0'; - } while (v && i < sizeof s / sizeof s[0]); - if (f & 8) s[i++] = '-'; + str[i++] = d + '0'; + } while (v && i < sizeof str / sizeof str[0]); + if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; while (!(f & 2) && j++ < w) putc_bfd(&pb, d); - do putc_bfd(&pb, s[--i]); while (i); + do putc_bfd(&pb, str[--i]); while (i); while (j++ < w) putc_bfd(&pb, d); } va_end(arp); - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + return putc_flush(&pb); } #endif /* !_FS_READONLY */ diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.h b/firmware/chibios-portapack/ext/fatfs/src/ff.h index 917908d2..5984c8eb 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.h +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.h @@ -1,11 +1,13 @@ -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module include R0.11a (C)ChaN, 2015 -/----------------------------------------------------------------------------/ -/ FatFs module is a free software that opened under license policy of -/ following conditions. +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12a / +/-----------------------------------------------------------------------------/ / -/ Copyright (C) 2015, ChaN, all right reserved. +/ Copyright (C) 2016, ChaN, all right reserved. / +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / @@ -13,11 +15,11 @@ / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. -/---------------------------------------------------------------------------*/ +/----------------------------------------------------------------------------*/ #ifndef _FATFS -#define _FATFS 64180 /* Revision ID */ +#define _FATFS 80186 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -25,6 +27,7 @@ extern "C" { #include "integer.h" /* Basic integer types */ #include "ffconf.h" /* FatFs configuration options */ + #if _FATFS != _FFCONF #error Wrong configuration file (ffconf.h). #endif @@ -52,8 +55,8 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ /* Type of path name strings on FatFs API */ -#if _LFN_UNICODE /* Unicode string */ -#if !_USE_LFN +#if _LFN_UNICODE /* Unicode (UTF-16) string */ +#if _USE_LFN == 0 #error _LFN_UNICODE must be 0 at non-LFN cfg. #endif #ifndef _INC_TCHAR @@ -61,14 +64,25 @@ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x #endif - #else /* ANSI/OEM string */ #ifndef _INC_TCHAR typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif +#endif + + +/* Type of file size variables */ + +#if _FS_EXFAT +#if _USE_LFN == 0 +#error LFN must be enabled when enable exFAT +#endif +typedef QWORD FSIZE_t; +#else +typedef DWORD FSIZE_t; #endif @@ -76,60 +90,87 @@ typedef char TCHAR; /* File system object structure (FATFS) */ typedef struct { - BYTE fs_type; /* FAT sub-type (0:Not mounted) */ + BYTE fs_type; /* File system type (0:N/A) */ BYTE drv; /* Physical drive number */ - BYTE csize; /* Sectors per cluster (1,2,4...128) */ - BYTE n_fats; /* Number of FAT copies (1 or 2) */ + BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ #if _MAX_SS != _MIN_SS - WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ +#endif +#if _USE_LFN != 0 + WCHAR* lfnbuf; /* LFN working buffer */ +#endif +#if _FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer */ #endif #if _FS_REENTRANT _SYNC_t sobj; /* Identifier of sync object */ #endif #if !_FS_READONLY - DWORD last_clust; /* Last allocated cluster */ - DWORD free_clust; /* Number of free clusters */ + DWORD last_clst; /* Last allocated cluster */ + DWORD free_clst; /* Number of free clusters */ #endif -#if _FS_RPATH +#if _FS_RPATH != 0 DWORD cdir; /* Current directory start cluster (0:root) */ +#if _FS_EXFAT + DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ + DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ + DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ #endif - DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ - DWORD fsize; /* Sectors per FAT */ - DWORD volbase; /* Volume start sector */ - DWORD fatbase; /* FAT start sector */ - DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ - DWORD database; /* Data start sector */ +#endif + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Size of an FAT [sectors] */ + DWORD volbase; /* Volume base sector */ + DWORD fatbase; /* FAT base sector */ + DWORD dirbase; /* Root directory base sector/cluster */ + DWORD database; /* Data base sector */ DWORD winsect; /* Current sector appearing in the win[] */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; +/* Object ID and allocation information (_FDID) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object */ + WORD id; /* Owner file system mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ + DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if _FS_EXFAT + DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ +#endif +#if _FS_LOCK != 0 + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +} _FDID; + + + /* File object structure (FIL) */ typedef struct { - FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ - WORD id; /* Owner file system mount ID (**do not change order**) */ - BYTE flag; /* Status flags */ + _FDID obj; /* Object identifier */ + BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ - DWORD fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD fsize; /* File size */ - DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ - DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ - DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ + FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */ + DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ #if !_FS_READONLY DWORD dir_sect; /* Sector number containing the directory entry */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ #endif #if _USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ -#endif -#if _FS_LOCK - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif #if !_FS_TINY BYTE buf[_MAX_SS]; /* File private data read/write window */ @@ -141,23 +182,17 @@ typedef struct { /* Directory object structure (DIR) */ typedef struct { - FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ - WORD id; /* Owner file system mount ID (**do not change order**) */ - WORD index; /* Current read/write index number */ - DWORD sclust; /* Table start cluster (0:Root dir) */ + _FDID obj; /* Object identifier */ + DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ DWORD sect; /* Current sector */ - BYTE* dir; /* Pointer to the current SFN entry in the win[] */ - BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ -#if _FS_LOCK - UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ -#endif -#if _USE_LFN - WCHAR* lfn; /* Pointer to the LFN working buffer */ - WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ + BYTE* dir; /* Pointer to the directory item in the win[] */ + BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ +#if _USE_LFN != 0 + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif #if _USE_FIND - const TCHAR* pat; /* Pointer to the name matching pattern */ + const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } DIR; @@ -166,14 +201,15 @@ typedef struct { /* File information structure (FILINFO) */ typedef struct { - DWORD fsize; /* File size */ - WORD fdate; /* Last modified date */ - WORD ftime; /* Last modified time */ - BYTE fattrib; /* Attribute */ - TCHAR fname[13]; /* Short file name (8.3 format) */ -#if _USE_LFN - TCHAR* lfname; /* Pointer to the LFN buffer */ - UINT lfsize; /* Size of LFN buffer in TCHAR */ + FSIZE_t fsize; /* File size */ + WORD fdate; /* Modified date */ + WORD ftime; /* Modified time */ + BYTE fattrib; /* File attribute */ +#if _USE_LFN != 0 + TCHAR altname[13]; /* Altenative file name */ + TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ +#else + TCHAR fname[13]; /* File name */ #endif } FILINFO; @@ -196,7 +232,7 @@ typedef enum { FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ - FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ @@ -211,12 +247,11 @@ typedef enum { FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ -FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ -FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ -FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ -FRESULT f_truncate (FIL* fp); /* Truncate file */ -FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ +FRESULT f_truncate (FIL* fp); /* Truncate the file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ @@ -226,26 +261,28 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ -FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ -FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ +FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ -FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ +FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ -#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) +#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) -#define f_size(fp) ((fp)->fsize) +#define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) @@ -265,7 +302,7 @@ DWORD get_fattime (void); #endif /* Unicode support functions */ -#if _USE_LFN /* Unicode - OEM code conversion */ +#if _USE_LFN != 0 /* Unicode - OEM code conversion */ WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ #if _USE_LFN == 3 /* Memory functions */ @@ -289,60 +326,39 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ /* Flags and offset address */ -/* File access control and file status flags (FIL.flag) */ - +/* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 -#define FA_OPEN_EXISTING 0x00 - -#if !_FS_READONLY #define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 -#define FA__WRITTEN 0x20 -#define FA__DIRTY 0x40 -#endif +#define FA_OPEN_APPEND 0x30 +/* Fast seek controls (2nd argument of f_lseek) */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) -/* FAT sub type (FATFS.fs_type) */ +/* Format options (2nd argument of f_mkfs) */ +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 +/* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 #define FS_FAT32 3 +#define FS_EXFAT 4 - -/* File attribute bits for directory entry */ - +/* File attribute bits for directory entry (FILINFO.fattrib) */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ -#define AM_MASK 0x3F /* Mask of defined bits */ -/* Fast seek feature */ -#define CREATE_LINKMAP 0xFFFFFFFF - - - -/*--------------------------------*/ -/* Multi-byte word access macros */ - -#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) -#else /* Use byte-by-byte access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) -#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) -#endif - #ifdef __cplusplus } #endif diff --git a/firmware/chibios-portapack/ext/fatfs/src/ffconf_template.h b/firmware/chibios-portapack/ext/fatfs/src/ffconf_template.h index bbe74e43..8db3d7cb 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ffconf_template.h +++ b/firmware/chibios-portapack/ext/fatfs/src/ffconf_template.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015 +/ FatFs - FAT file system module configuration file /---------------------------------------------------------------------------*/ -#define _FFCONF 64180 /* Revision ID */ +#define _FFCONF 80186 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -19,8 +19,8 @@ /* This option defines minimization level to remove some basic API functions. / / 0: All basic functions are enabled. -/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), -/ f_truncate() and f_rename() function are removed. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ @@ -35,8 +35,8 @@ #define _USE_FIND 0 -/* This option switches filtered directory read feature and related functions, -/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define _USE_MKFS 0 @@ -44,7 +44,16 @@ #define _USE_FASTSEEK 0 -/* This option switches fast seek feature. (0:Disable or 1:Enable) */ +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define _USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define _USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ #define _USE_LABEL 0 @@ -53,8 +62,7 @@ #define _USE_FORWARD 0 -/* This option switches f_forward() function. (0:Disable or 1:Enable) -/ To enable it, also _FS_TINY need to be set to 1. */ +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ @@ -92,28 +100,30 @@ #define _USE_LFN 0 #define _MAX_LFN 255 -/* The _USE_LFN option switches the LFN feature. +/* The _USE_LFN switches the support of long file name (LFN). / -/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 0: Disable support of LFN. _MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must -/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. +/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added +/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and +/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. +/ It should be set 255 to support full featured LFN operations. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree(), must be added to the project. */ #define _LFN_UNICODE 0 -/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) -/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE -/ to 1. This option also affects behavior of string I/O functions. */ +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) +/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. +/ This option also affects behavior of string I/O functions. */ #define _STRF_ENCODE 3 -/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to +/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / / 0: ANSI/OEM @@ -121,17 +131,16 @@ / 2: UTF-16BE / 3: UTF-8 / -/ When _LFN_UNICODE is 0, this option has no effect. */ +/ This option has no effect when _LFN_UNICODE == 0. */ #define _FS_RPATH 0 -/* This option configures relative path feature. +/* This option configures support of relative path. / -/ 0: Disable relative path feature and remove related functions. -/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. -/ -/ Note that directory items read via f_readdir() are affected by this option. */ +*/ /*---------------------------------------------------------------------------/ @@ -143,8 +152,8 @@ #define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" -/* _STR_VOLUME_ID option switches string volume ID feature. +#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* _STR_VOLUME_ID switches string support of volume ID. / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each / logical drives. Number of items must be equal to _VOLUMES. Valid characters for @@ -152,11 +161,12 @@ #define _MULTI_PARTITION 0 -/* This option switches multi-partition feature. By default (0), each logical drive -/ number is bound to the same physical drive number and only an FAT volume found on -/ the physical drive will be mounted. When multi-partition feature is enabled (1), -/ each logical drive number is bound to arbitrary physical drive and partition -/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ +/* This option switches support of multi-partition on a physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When multi-partition is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ #define _MIN_SS 512 @@ -170,8 +180,8 @@ #define _USE_TRIM 0 -/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) -/ To enable Trim feature, also CTRL_TRIM command should be implemented to the +/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ @@ -194,46 +204,51 @@ #define _FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS -/ bytes. Instead of private sector buffer eliminated from the file object, -/ common sector buffer in the file system object (FATFS) is used for the file -/ data transfer. */ +/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the file system object (FATFS) is used for the file data transfer. */ + + +#define _FS_EXFAT 0 +/* This option switches support of exFAT file system in addition to the traditional +/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled. +/ Note that enabling exFAT discards C89 compatibility. */ #define _FS_NORTC 0 #define _NORTC_MON 1 #define _NORTC_MDAY 1 -#define _NORTC_YEAR 2015 -/* The _FS_NORTC option switches timestamp feature. If the system does not have -/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable -/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp -/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. -/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need -/ to be added to the project to read current time form RTC. _NORTC_MON, +#define _NORTC_YEAR 2016 +/* The option _FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. +/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to get current time form real-time clock. _NORTC_MON, / _NORTC_MDAY and _NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ +/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ #define _FS_LOCK 0 -/* The _FS_LOCK option switches file lock feature to control duplicated file open +/* The option _FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when _FS_READONLY / is 1. / -/ 0: Disable file lock feature. To avoid volume corruption, application program +/ 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. -/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file -/ lock feature is independent of re-entrancy. */ +/ lock control is independent of re-entrancy. */ #define _FS_REENTRANT 0 #define _FS_TIMEOUT 1000 #define _SYNC_t HANDLE -/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs +/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this feature. +/ to the same volume is under control of this function. / / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, @@ -247,30 +262,4 @@ / included somewhere in the scope of ff.c. */ -#define _WORD_ACCESS 0 -/* The _WORD_ACCESS option is an only platform dependent option. It defines -/ which access method is used to the word data on the FAT volume. -/ -/ 0: Byte-by-byte access. Always compatible with all platforms. -/ 1: Word access. Do not choose this unless under both the following conditions. -/ -/ * Address misaligned memory access is always allowed to ALL instructions. -/ * Byte order on the memory is little-endian. -/ -/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. -/ Following table shows allowable settings of some type of processors. -/ -/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 -/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 -/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 -/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 -/ AVR32 0 *1 RL78 0 *2 R32C 0 *2 -/ PIC18 0/1 SH-2 0 *1 M16C 0/1 -/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2 -/ PIC32 0 *1 H8/300H 0 *1 8051 0/1 -/ -/ *1:Big-endian. -/ *2:Unaligned memory access is not supported. -/ *3:Some compilers generate LDM/STM for mem_cpy function. -*/ - +/*--- End of configuration options ---*/ diff --git a/firmware/chibios-portapack/ext/fatfs/src/integer.h b/firmware/chibios-portapack/ext/fatfs/src/integer.h index 584bd1a9..4660ed62 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/integer.h +++ b/firmware/chibios-portapack/ext/fatfs/src/integer.h @@ -5,13 +5,19 @@ #ifndef _FF_INTEGER #define _FF_INTEGER -#ifdef _WIN32 /* Development platform */ +#ifdef _WIN32 /* FatFs development platform */ #include #include +typedef unsigned __int64 QWORD; + #else /* Embedded platform */ +/* These types MUST be 16-bit or 32-bit */ +typedef int INT; +typedef unsigned int UINT; + /* This type MUST be 8-bit */ typedef unsigned char BYTE; @@ -20,14 +26,13 @@ typedef short SHORT; typedef unsigned short WORD; typedef unsigned short WCHAR; -/* These types MUST be 16-bit or 32-bit */ -typedef int INT; -typedef unsigned int UINT; - /* These types MUST be 32-bit */ typedef long LONG; typedef unsigned long DWORD; +/* This type MUST be 64-bit (Remove this for C89 compatibility) */ +typedef unsigned long long QWORD; + #endif #endif diff --git a/firmware/chibios-portapack/ext/fatfs/src/option/cc932.c b/firmware/chibios-portapack/ext/fatfs/src/option/cc932.c index 19231a2b..1e244c37 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/option/cc932.c +++ b/firmware/chibios-portapack/ext/fatfs/src/option/cc932.c @@ -3782,46 +3782,87 @@ WCHAR ff_convert ( /* Converted code, 0 means conversion error */ -WCHAR ff_wtoupper ( - WCHAR chr /* Unicode character to be upper converted */ +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ ) { - static const WCHAR lower[] = { /* Lower case characters to be converted */ - /* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, - /* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E, - /* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217, - /* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB, - /* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9, - /* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586, - /* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9, - /* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F, - /* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 }; - static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178, - 0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D, - 0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216, - 0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA, - 0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8, - 0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556, - 0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8, - 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F, - 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 }; - UINT i, n, hi, li; + const WCHAR *p; + WCHAR bc, nc, cmd; - if (chr < 0x80) { /* ASCII characters (acceleration) */ - if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20; - - } else { /* Extended characters */ - n = 12; li = 0; hi = sizeof lower / sizeof lower[0]; - do { - i = li + (hi - li) / 2; - if (chr == lower[i]) break; - if (chr > lower[i]) li = i; else hi = i; - } while (--n); - if (n) chr = upper[i]; + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; } return chr; diff --git a/firmware/chibios-portapack/ext/fatfs/src/option/cc936.c b/firmware/chibios-portapack/ext/fatfs/src/option/cc936.c index 4c20783e..3a5960f4 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/option/cc936.c +++ b/firmware/chibios-portapack/ext/fatfs/src/option/cc936.c @@ -10957,46 +10957,87 @@ WCHAR ff_convert ( /* Converted code, 0 means conversion error */ -WCHAR ff_wtoupper ( - WCHAR chr /* Unicode character to be upper converted */ +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ ) { - static const WCHAR lower[] = { /* Lower case characters to be converted */ - /* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, - /* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E, - /* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217, - /* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB, - /* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9, - /* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586, - /* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9, - /* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F, - /* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 }; - static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178, - 0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D, - 0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216, - 0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA, - 0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8, - 0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556, - 0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8, - 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F, - 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 }; - UINT i, n, hi, li; + const WCHAR *p; + WCHAR bc, nc, cmd; - if (chr < 0x80) { /* ASCII characters (acceleration) */ - if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20; - - } else { /* Extended characters */ - n = 12; li = 0; hi = sizeof lower / sizeof lower[0]; - do { - i = li + (hi - li) / 2; - if (chr == lower[i]) break; - if (chr > lower[i]) li = i; else hi = i; - } while (--n); - if (n) chr = upper[i]; + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; } return chr; diff --git a/firmware/chibios-portapack/ext/fatfs/src/option/cc949.c b/firmware/chibios-portapack/ext/fatfs/src/option/cc949.c index f646e004..3bc617cc 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/option/cc949.c +++ b/firmware/chibios-portapack/ext/fatfs/src/option/cc949.c @@ -8586,47 +8586,87 @@ WCHAR ff_convert ( /* Converted code, 0 means conversion error */ - -WCHAR ff_wtoupper ( - WCHAR chr /* Unicode character to be upper converted */ +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ ) { - static const WCHAR lower[] = { /* Lower case characters to be converted */ - /* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, - /* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E, - /* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217, - /* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB, - /* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9, - /* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586, - /* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9, - /* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F, - /* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 }; - static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178, - 0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D, - 0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216, - 0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA, - 0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8, - 0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556, - 0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8, - 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F, - 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 }; - UINT i, n, hi, li; + const WCHAR *p; + WCHAR bc, nc, cmd; - if (chr < 0x80) { /* ASCII characters (acceleration) */ - if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20; - - } else { /* Extended characters */ - n = 12; li = 0; hi = sizeof lower / sizeof lower[0]; - do { - i = li + (hi - li) / 2; - if (chr == lower[i]) break; - if (chr > lower[i]) li = i; else hi = i; - } while (--n); - if (n) chr = upper[i]; + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; } return chr; diff --git a/firmware/chibios-portapack/ext/fatfs/src/option/cc950.c b/firmware/chibios-portapack/ext/fatfs/src/option/cc950.c index 064f5ca5..bbcaa244 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/option/cc950.c +++ b/firmware/chibios-portapack/ext/fatfs/src/option/cc950.c @@ -6812,47 +6812,87 @@ WCHAR ff_convert ( /* Converted code, 0 means conversion error */ - -WCHAR ff_wtoupper ( - WCHAR chr /* Unicode character to be upper converted */ +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ ) { - static const WCHAR lower[] = { /* Lower case characters to be converted */ - /* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, - /* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E, - /* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217, - /* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB, - /* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9, - /* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586, - /* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9, - /* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F, - /* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 }; - static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178, - 0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D, - 0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216, - 0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA, - 0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8, - 0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556, - 0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8, - 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F, - 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 }; - UINT i, n, hi, li; + const WCHAR *p; + WCHAR bc, nc, cmd; - if (chr < 0x80) { /* ASCII characters (acceleration) */ - if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20; - - } else { /* Extended characters */ - n = 12; li = 0; hi = sizeof lower / sizeof lower[0]; - do { - i = li + (hi - li) / 2; - if (chr == lower[i]) break; - if (chr > lower[i]) li = i; else hi = i; - } while (--n); - if (n) chr = upper[i]; + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; } return chr; diff --git a/firmware/chibios-portapack/ext/fatfs/src/option/ccsbcs.c b/firmware/chibios-portapack/ext/fatfs/src/option/ccsbcs.c index 37f763ef..164caa06 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/option/ccsbcs.c +++ b/firmware/chibios-portapack/ext/fatfs/src/option/ccsbcs.c @@ -300,47 +300,87 @@ WCHAR ff_convert ( /* Converted character, Returns zero on error */ - WCHAR ff_wtoupper ( /* Returns upper converted character */ - WCHAR chr /* Unicode character to be upper converted */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ ) { - static const WCHAR lower[] = { /* Lower case characters to be converted */ - /* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, - /* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E, - /* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217, - /* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB, - /* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9, - /* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586, - /* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9, - /* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F, - /* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 }; - static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178, - 0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D, - 0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216, - 0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA, - 0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8, - 0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556, - 0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8, - 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F, - 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 }; - UINT i, n, hi, li; + const WCHAR *p; + WCHAR bc, nc, cmd; - if (chr < 0x80) { /* ASCII characters (acceleration) */ - if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20; - - } else { /* Non ASCII characters (table search) */ - n = 12; li = 0; hi = sizeof lower / sizeof lower[0]; - do { - i = li + (hi - li) / 2; - if (chr == lower[i]) break; - if (chr > lower[i]) li = i; else hi = i; - } while (--n); - if (n) chr = upper[i]; + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; } return chr; diff --git a/firmware/chibios-portapack/ext/fatfs/src/option/syscall.c b/firmware/chibios-portapack/ext/fatfs/src/option/syscall.c index 2036cb77..c9d219b7 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/option/syscall.c +++ b/firmware/chibios-portapack/ext/fatfs/src/option/syscall.c @@ -16,8 +16,8 @@ / the f_mount() function fails with FR_INT_ERR. */ -int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */ - BYTE vol, /* Corresponding logical drive being processed */ +int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ + BYTE vol, /* Corresponding volume (logical drive number) */ _SYNC_t *sobj /* Pointer to return the created sync object */ ) { @@ -27,7 +27,7 @@ int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */ ret = (int)(*sobj != INVALID_HANDLE_VALUE); -// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */ +// *sobj = SyncObjects[vol]; /* uITRON (give a static sync object) */ // ret = 1; /* The initial value of the semaphore must be 1. */ // *sobj = OSMutexCreate(0, &err); /* uC/OS-II */ @@ -45,11 +45,11 @@ int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any /* Delete a Synchronization Object */ /*------------------------------------------------------------------------*/ /* This function is called in f_mount() function to delete a synchronization -/ object that created with ff_cre_syncobj function. When a 0 is returned, +/ object that created with ff_cre_syncobj() function. When a 0 is returned, / the f_mount() function fails with FR_INT_ERR. */ -int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */ +int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to any error */ _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ ) { From 3a519338821acb56583773f8570405e1fb733e23 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:11:23 -0700 Subject: [PATCH 002/100] FatFs: Apply patch ff12a_p1.diff. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index c6e91b37..98369088 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -298,7 +298,7 @@ typedef struct { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #elif _CODE_PAGE == 869 /* Greek 2 */ From 897110f715be65563e79d3151835e9ce5e84c83e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:12:04 -0700 Subject: [PATCH 003/100] FatFs: Apply patch ff12a_p2.diff. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index 98369088..7fe9668f 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -1194,6 +1194,7 @@ FRESULT change_bitmap ( } while (bm <<= 1); /* Next bit */ bm = 1; } while (++i < SS(fs)); /* Next byte */ + i = 0; } } @@ -1263,7 +1264,7 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } - if (fs->free_clst != 0xFFFFFFFF) { /* Update FSINFO */ + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst++; fs->fsi_flag |= 1; } @@ -3566,9 +3567,8 @@ FRESULT f_write ( if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - /* Check fptr wrap-around (file size cannot exceed the limit on each FAT specs) */ - if ((_FS_EXFAT && fs->fs_type == FS_EXFAT && fp->fptr + btw < fp->fptr) - || (DWORD)fp->fptr + btw < (DWORD)fp->fptr) { + /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ + if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } @@ -5101,8 +5101,8 @@ FRESULT f_expand ( } if (res == FR_OK) { if (opt) { - for (clst = scl; tcl; clst++, tcl--) { /* Create a cluster chain on the FAT */ - res = put_fat(fs, clst, (tcl == 1) ? 0xFFFFFFFF : clst + 1); + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } @@ -5112,12 +5112,18 @@ FRESULT f_expand ( } } - if (opt && res == FR_OK) { + if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ - fp->obj.sclust = scl; /* Update object allocation information */ - fp->obj.objsize = fsz; - if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ - fp->flag |= FA_MODIFIED; + if (opt) { + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } } LEAVE_FF(fs, res); From aa8c8b29378f6bea955a66e4e520dc8f9da6110a Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:13:07 -0700 Subject: [PATCH 004/100] FatFs: Apply patch ff12a_p3.diff. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index 7fe9668f..5bec9ccd 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -2266,7 +2266,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ - if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */ + if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ dp->obj.stat &= 3; dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ From 4f6254cc9314ab25a6356741ba7dce82106188da Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:14:08 -0700 Subject: [PATCH 005/100] FatFs: Apply patch ff12a_p4.diff. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index 5bec9ccd..dd8ef500 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -2430,7 +2430,7 @@ void get_fileinfo ( /* No return code */ } #endif if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ - fno->fname[i++] = (char)w; + fno->fname[i++] = (TCHAR)w; } fno->fname[i] = 0; /* Terminate the LFN */ } @@ -3680,8 +3680,9 @@ FRESULT f_sync ( FATFS *fs; DWORD tm; BYTE *dir; +#if _FS_EXFAT DEF_NAMBUF - +#endif res = validate(fp, &fs); /* Check validity of the object */ if (res == FR_OK) { @@ -4008,6 +4009,9 @@ FRESULT f_lseek ( /* Normal Seek */ { +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ +#endif if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } From e5810ab7c77b0a478b64287bc5eba502229c1e82 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:14:43 -0700 Subject: [PATCH 006/100] FatFs: Remove (deprecated?) _USE_WRITE, _USE_IOCTL guards. --- .../os/various/fatfs_bindings/fatfs_diskio.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c b/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c index d6cd3b1f..862f27e6 100755 --- a/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c +++ b/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs_diskio.c @@ -153,7 +153,6 @@ DRESULT disk_read ( /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ -#if _USE_WRITE DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ @@ -190,7 +189,6 @@ DRESULT disk_write ( } return RES_PARERR; } -#endif /* _READONLY */ @@ -198,7 +196,6 @@ DRESULT disk_write ( /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ -#if _USE_IOCTL DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ @@ -260,7 +257,6 @@ DRESULT disk_ioctl ( } return RES_PARERR; } -#endif /* _IOCTL */ DWORD get_fattime(void) { #if HAL_USE_RTC From e9d97dfd0f2c058d77100a9c9a32164770fc7c95 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:15:10 -0700 Subject: [PATCH 007/100] FatFs: Update application ffconf.h from template. --- firmware/application/ffconf.h | 143 ++++++++++++++++------------------ 1 file changed, 66 insertions(+), 77 deletions(-) diff --git a/firmware/application/ffconf.h b/firmware/application/ffconf.h index 2212ff1e..a02d51b0 100644 --- a/firmware/application/ffconf.h +++ b/firmware/application/ffconf.h @@ -2,10 +2,10 @@ #include "ch.h" /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015 +/ FatFs - FAT file system module configuration file /---------------------------------------------------------------------------*/ -#define _FFCONF 64180 /* Revision ID */ +#define _FFCONF 80186 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -22,8 +22,8 @@ /* This option defines minimization level to remove some basic API functions. / / 0: All basic functions are enabled. -/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), -/ f_truncate() and f_rename() function are removed. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ @@ -38,8 +38,8 @@ #define _USE_FIND 1 -/* This option switches filtered directory read feature and related functions, -/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define _USE_MKFS 0 @@ -47,7 +47,16 @@ #define _USE_FASTSEEK 1 -/* This option switches fast seek feature. (0:Disable or 1:Enable) */ +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define _USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define _USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ #define _USE_LABEL 0 @@ -56,8 +65,7 @@ #define _USE_FORWARD 0 -/* This option switches f_forward() function. (0:Disable or 1:Enable) -/ To enable it, also _FS_TINY need to be set to 1. */ +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ @@ -95,28 +103,30 @@ #define _USE_LFN 0 #define _MAX_LFN 255 -/* The _USE_LFN option switches the LFN feature. +/* The _USE_LFN switches the support of long file name (LFN). / -/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 0: Disable support of LFN. _MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must -/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. +/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added +/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and +/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. +/ It should be set 255 to support full featured LFN operations. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree(), must be added to the project. */ #define _LFN_UNICODE 0 -/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) -/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE -/ to 1. This option also affects behavior of string I/O functions. */ +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) +/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. +/ This option also affects behavior of string I/O functions. */ #define _STRF_ENCODE 3 -/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to +/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / / 0: ANSI/OEM @@ -124,17 +134,16 @@ / 2: UTF-16BE / 3: UTF-8 / -/ When _LFN_UNICODE is 0, this option has no effect. */ +/ This option has no effect when _LFN_UNICODE == 0. */ #define _FS_RPATH 0 -/* This option configures relative path feature. +/* This option configures support of relative path. / -/ 0: Disable relative path feature and remove related functions. -/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. -/ -/ Note that directory items read via f_readdir() are affected by this option. */ +*/ /*---------------------------------------------------------------------------/ @@ -146,8 +155,8 @@ #define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" -/* _STR_VOLUME_ID option switches string volume ID feature. +#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* _STR_VOLUME_ID switches string support of volume ID. / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each / logical drives. Number of items must be equal to _VOLUMES. Valid characters for @@ -155,11 +164,12 @@ #define _MULTI_PARTITION 0 -/* This option switches multi-partition feature. By default (0), each logical drive -/ number is bound to the same physical drive number and only an FAT volume found on -/ the physical drive will be mounted. When multi-partition feature is enabled (1), -/ each logical drive number is bound to arbitrary physical drive and partition -/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ +/* This option switches support of multi-partition on a physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When multi-partition is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ #define _MIN_SS 512 @@ -173,8 +183,8 @@ #define _USE_TRIM 0 -/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) -/ To enable Trim feature, also CTRL_TRIM command should be implemented to the +/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ @@ -197,46 +207,51 @@ #define _FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS -/ bytes. Instead of private sector buffer eliminated from the file object, -/ common sector buffer in the file system object (FATFS) is used for the file -/ data transfer. */ +/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the file system object (FATFS) is used for the file data transfer. */ + + +#define _FS_EXFAT 0 +/* This option switches support of exFAT file system in addition to the traditional +/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled. +/ Note that enabling exFAT discards C89 compatibility. */ #define _FS_NORTC 0 #define _NORTC_MON 1 #define _NORTC_MDAY 1 -#define _NORTC_YEAR 2015 -/* The _FS_NORTC option switches timestamp feature. If the system does not have -/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable -/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp -/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. -/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need -/ to be added to the project to read current time form RTC. _NORTC_MON, +#define _NORTC_YEAR 2016 +/* The option _FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. +/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to get current time form real-time clock. _NORTC_MON, / _NORTC_MDAY and _NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ +/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ #define _FS_LOCK 0 -/* The _FS_LOCK option switches file lock feature to control duplicated file open +/* The option _FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when _FS_READONLY / is 1. / -/ 0: Disable file lock feature. To avoid volume corruption, application program +/ 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. -/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file -/ lock feature is independent of re-entrancy. */ +/ lock control is independent of re-entrancy. */ #define _FS_REENTRANT 1 #define _FS_TIMEOUT 1000 #define _SYNC_t Semaphore * -/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs +/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this feature. +/ to the same volume is under control of this function. / / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, @@ -250,30 +265,4 @@ / included somewhere in the scope of ff.c. */ -#define _WORD_ACCESS 0 -/* The _WORD_ACCESS option is an only platform dependent option. It defines -/ which access method is used to the word data on the FAT volume. -/ -/ 0: Byte-by-byte access. Always compatible with all platforms. -/ 1: Word access. Do not choose this unless under both the following conditions. -/ -/ * Address misaligned memory access is always allowed to ALL instructions. -/ * Byte order on the memory is little-endian. -/ -/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. -/ Following table shows allowable settings of some type of processors. -/ -/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 -/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 -/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 -/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 -/ AVR32 0 *1 RL78 0 *2 R32C 0 *2 -/ PIC18 0/1 SH-2 0 *1 M16C 0/1 -/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2 -/ PIC32 0 *1 H8/300H 0 *1 8051 0/1 -/ -/ *1:Big-endian. -/ *2:Unaligned memory access is not supported. -/ *3:Some compilers generate LDM/STM for mem_cpy function. -*/ - +/*--- End of configuration options ---*/ From 69173f5292f07d55dada5cfd3fcae3629f32c214 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 28 Jul 2016 23:21:13 -0700 Subject: [PATCH 008/100] FatFs: My patch to fix wrong argument type warning. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index dd8ef500..ca71f697 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -3992,7 +3992,7 @@ FRESULT f_lseek ( #if !_FS_TINY #if !_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fp, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= ~FA_DIRTY; } #endif From 45a1ccbc53fa951331dd83acd19cca8b7d330b61 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 3 Aug 2016 16:12:01 -0700 Subject: [PATCH 009/100] Correctly map TX gain from dB to register value. --- firmware/application/max2837.cpp | 16 ++++++++++++++-- firmware/application/max2837.hpp | 10 +++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/firmware/application/max2837.cpp b/firmware/application/max2837.cpp index 33e4a8b6..4db7bf92 100644 --- a/firmware/application/max2837.cpp +++ b/firmware/application/max2837.cpp @@ -55,6 +55,18 @@ static uint_fast8_t gain_ordinal(const int8_t db) { } /* namespace vga */ +namespace tx { + +static uint_fast8_t gain_ordinal(const int8_t db) { + const auto db_sat = gain_db_range.clip(db); + uint8_t value = db_sat & 0x0f; + value = (db_sat >= 16) ? (value | 0x20) : value; + value = (db_sat >= 32) ? (value | 0x10) : value; + return (value & 0b111111) ^ 0b111111; +} + +} /* namespace tx */ + namespace filter { static uint_fast8_t bandwidth_ordinal(const uint32_t bandwidth) { @@ -170,8 +182,8 @@ reg_t MAX2837::read(const Register reg) { return read(toUType(reg)); } -void MAX2837::set_tx_vga_gain(const int_fast8_t value) { - _map.r.tx_gain.TXVGA_GAIN_SPI = value; +void MAX2837::set_tx_vga_gain(const int_fast8_t db) { + _map.r.tx_gain.TXVGA_GAIN_SPI = tx::gain_ordinal(db); _dirty[Register::TX_GAIN] = 1; flush(); } diff --git a/firmware/application/max2837.hpp b/firmware/application/max2837.hpp index 6c91ae58..857bb4e9 100644 --- a/firmware/application/max2837.hpp +++ b/firmware/application/max2837.hpp @@ -83,6 +83,14 @@ constexpr int8_t gain_db_step = 2; /*************************************************************************/ +namespace tx { + +constexpr range_t gain_db_range { 0, 47 }; +constexpr int8_t gain_db_step = 1; +} + +/*************************************************************************/ + namespace filter { constexpr std::array bandwidths { @@ -829,7 +837,7 @@ public: void init(); void set_mode(const Mode mode); - void set_tx_vga_gain(const int_fast8_t value); + void set_tx_vga_gain(const int_fast8_t db); void set_lna_gain(const int_fast8_t db); void set_vga_gain(const int_fast8_t db); void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum); From 1e39b7ea45cee7c28b23883f5c1afcef6e7e46df Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 3 Aug 2016 16:12:22 -0700 Subject: [PATCH 010/100] Expose TX gain in radio API. --- firmware/application/radio.cpp | 4 ++++ firmware/application/radio.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 88ef4a21..b61ce022 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -146,6 +146,10 @@ void set_vga_gain(const int_fast8_t db) { second_if.set_vga_gain(db); } +void set_tx_gain(const int_fast8_t db) { + second_if.set_tx_vga_gain(db); +} + void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum) { second_if.set_lpf_rf_bandwidth(bandwidth_minimum); } diff --git a/firmware/application/radio.hpp b/firmware/application/radio.hpp index 4c1faa78..6d22acf3 100644 --- a/firmware/application/radio.hpp +++ b/firmware/application/radio.hpp @@ -47,6 +47,7 @@ bool set_tuning_frequency(const rf::Frequency frequency); void set_rf_amp(const bool rf_amp); void set_lna_gain(const int_fast8_t db); void set_vga_gain(const int_fast8_t db); +void set_tx_gain(const int_fast8_t db); void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum); void set_baseband_rate(const uint32_t rate); void set_baseband_decimation_by(const size_t n); From ef9b4051b78bbac5e28551132f0a24da188b2fa3 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 3 Aug 2016 16:13:54 -0700 Subject: [PATCH 011/100] Expose TX gain on ReceiverModel. Obviously, ReceiverModel is an even worse name/concept than it was before. --- firmware/application/receiver_model.cpp | 14 ++++++++++++++ firmware/application/receiver_model.hpp | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 35059f5c..b5796c38 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -115,6 +115,15 @@ void ReceiverModel::set_vga(int32_t v_db) { update_vga(); } +int32_t ReceiverModel::tx_gain() const { + return tx_gain_db_; +} + +void ReceiverModel::set_tx_gain(int32_t v_db) { + tx_gain_db_ = v_db; + update_tx_gain(); +} + uint32_t ReceiverModel::sampling_rate() const { return sampling_rate_; } @@ -155,6 +164,7 @@ void ReceiverModel::enable() { update_rf_amp(); update_lna(); update_vga(); + update_tx_gain(); update_baseband_bandwidth(); update_sampling_rate(); update_modulation(); @@ -202,6 +212,10 @@ void ReceiverModel::update_vga() { radio::set_vga_gain(vga_gain_db_); } +void ReceiverModel::update_tx_gain() { + radio::set_tx_gain(tx_gain_db_); +} + void ReceiverModel::set_am_configuration(const size_t n) { if( n < am_configs.size() ) { am_config_index = n; diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index d103c4c8..4499e9fe 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -60,6 +60,9 @@ public: int32_t vga() const; void set_vga(int32_t v_db); + int32_t tx_gain() const; + void set_tx_gain(int32_t v_db); + uint32_t sampling_rate() const; void set_sampling_rate(uint32_t v); @@ -91,6 +94,7 @@ private: int32_t lna_gain_db_ { 32 }; uint32_t baseband_bandwidth_ { max2837::filter::bandwidth_minimum }; int32_t vga_gain_db_ { 32 }; + int32_t tx_gain_db_ { 47 }; Mode mode_ { Mode::NarrowbandFMAudio }; uint32_t sampling_rate_ { 3072000 }; size_t decimation_factor_ { 1 }; @@ -107,6 +111,7 @@ private: void update_lna(); void update_baseband_bandwidth(); void update_vga(); + void update_tx_gain(); void update_sampling_rate(); void update_headphone_volume(); From 447a7a5661fc04870a329ea73a414b3dfb002f70 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 3 Aug 2016 16:14:34 -0700 Subject: [PATCH 012/100] Add TXGainField user interface element. --- firmware/application/ui_receiver.cpp | 25 +++++++++++++++++++++++++ firmware/application/ui_receiver.hpp | 9 +++++++++ 2 files changed, 34 insertions(+) diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index 18a5c613..d48917a4 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -353,4 +353,29 @@ void VGAGainField::on_focus() { } } +/* TXGainField **********************************************************/ + +TXGainField::TXGainField( + Point parent_pos +) : NumberField { + parent_pos, 2, + { max2837::tx::gain_db_range.minimum, max2837::tx::gain_db_range.maximum }, + max2837::tx::gain_db_step, + ' ', + } +{ + set_value(receiver_model.tx_gain()); + + on_change = [](int32_t v) { + receiver_model.set_tx_gain(v); + }; +} + +void TXGainField::on_focus() { + //Widget::on_focus(); + if( on_show_options ) { + on_show_options(); + } +} + } /* namespace ui */ diff --git a/firmware/application/ui_receiver.hpp b/firmware/application/ui_receiver.hpp index 1d4cb6d3..eb012f4d 100644 --- a/firmware/application/ui_receiver.hpp +++ b/firmware/application/ui_receiver.hpp @@ -330,6 +330,15 @@ public: void on_focus() override; }; +class TXGainField : public NumberField { +public: + std::function on_show_options; + + TXGainField(Point parent_pos); + + void on_focus() override; +}; + } /* namespace ui */ #endif/*__UI_RECEIVER_H__*/ From c8af6dcd70535e60ba8957a6b4b1a12812c6ee95 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 10 Aug 2016 09:53:35 -0700 Subject: [PATCH 013/100] Add SMULL instruction inline function. --- .../os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h b/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h index 25f56907..d56457ae 100644 --- a/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h +++ b/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h @@ -196,6 +196,20 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMULTT(uint32_t op1 return result; } +#undef __SMULL + +__attribute__( ( always_inline ) ) static inline int64_t __SMULL (int32_t op1, int32_t op2) +{ + union llreg_u{ + uint32_t w32[2]; + int64_t w64; + } llr; + + __asm volatile ("smull %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2)); + + return(llr.w64); +} + #undef __SMLALD __attribute__( ( always_inline ) ) static inline int64_t __SMLALD (uint32_t op1, uint32_t op2, int64_t acc) From 96da55d83aeadd92ac9e57dec9a38057b1b35f67 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 10 Aug 2016 10:34:14 -0700 Subject: [PATCH 014/100] wait_for_buffer() now handles TX buffers. Feels a bit awkward to read LLI src/dest to determine if RX or TX. But it works. --- firmware/baseband/baseband_dma.cpp | 7 +++++-- firmware/baseband/baseband_dma.hpp | 2 +- firmware/baseband/baseband_thread.cpp | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/firmware/baseband/baseband_dma.cpp b/firmware/baseband/baseband_dma.cpp index d86bef72..4fc1fdd8 100644 --- a/firmware/baseband/baseband_dma.cpp +++ b/firmware/baseband/baseband_dma.cpp @@ -156,12 +156,15 @@ void disable() { gpdma_channel_sgpio.disable(); } -baseband::buffer_t wait_for_rx_buffer() { +baseband::buffer_t wait_for_buffer() { const auto next_index = thread_wait.sleep(); if( next_index >= 0 ) { const size_t free_index = (next_index + transfers_per_buffer - 2) & transfers_mask; - return { reinterpret_cast(lli_loop[free_index].destaddr), transfer_samples }; + const auto src = lli_loop[free_index].srcaddr; + const auto dst = lli_loop[free_index].destaddr; + const auto p = (src == reinterpret_cast(&LPC_SGPIO->REG_SS[0])) ? dst : src; + return { reinterpret_cast(p), transfer_samples }; } else { return { }; } diff --git a/firmware/baseband/baseband_dma.hpp b/firmware/baseband/baseband_dma.hpp index 94827d4b..56752ddc 100644 --- a/firmware/baseband/baseband_dma.hpp +++ b/firmware/baseband/baseband_dma.hpp @@ -42,7 +42,7 @@ bool is_enabled(); void disable(); -baseband::buffer_t wait_for_rx_buffer(); +baseband::buffer_t wait_for_buffer(); } /* namespace dma */ } /* namespace baseband */ diff --git a/firmware/baseband/baseband_thread.cpp b/firmware/baseband/baseband_thread.cpp index 0784d9bd..926e4fb0 100644 --- a/firmware/baseband/baseband_thread.cpp +++ b/firmware/baseband/baseband_thread.cpp @@ -77,7 +77,7 @@ void BasebandThread::run() { while( !chThdShouldTerminate() ) { // TODO: Place correct sampling rate into buffer returned here: - const auto buffer_tmp = baseband::dma::wait_for_rx_buffer(); + const auto buffer_tmp = baseband::dma::wait_for_buffer(); if( buffer_tmp ) { buffer_c8_t buffer { buffer_tmp.p, buffer_tmp.count, sampling_rate From 2ec1bab5d5f153172163ac6a2e585eb9a4a66f36 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 10 Aug 2016 10:36:03 -0700 Subject: [PATCH 015/100] Plumb BasebandThread to accept direction argument. Default is to receive, for compatibility with existing users. --- firmware/baseband/baseband_thread.cpp | 6 ++++-- firmware/baseband/baseband_thread.hpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/firmware/baseband/baseband_thread.cpp b/firmware/baseband/baseband_thread.cpp index 926e4fb0..3f683a59 100644 --- a/firmware/baseband/baseband_thread.cpp +++ b/firmware/baseband/baseband_thread.cpp @@ -44,9 +44,11 @@ Thread* BasebandThread::thread = nullptr; BasebandThread::BasebandThread( uint32_t sampling_rate, BasebandProcessor* const baseband_processor, - const tprio_t priority + const tprio_t priority, + baseband::Direction direction ) : baseband_processor { baseband_processor }, - sampling_rate { sampling_rate } + sampling_rate { sampling_rate }, + _direction { direction } { thread = chThdCreateStatic(baseband_thread_wa, sizeof(baseband_thread_wa), priority, ThreadBase::fn, diff --git a/firmware/baseband/baseband_thread.hpp b/firmware/baseband/baseband_thread.hpp index 3263b4f1..4d06e326 100644 --- a/firmware/baseband/baseband_thread.hpp +++ b/firmware/baseband/baseband_thread.hpp @@ -33,20 +33,22 @@ public: BasebandThread( uint32_t sampling_rate, BasebandProcessor* const baseband_processor, - const tprio_t priority + const tprio_t priority, + const baseband::Direction direction = baseband::Direction::Receive ); ~BasebandThread(); // This getter should die, it's just here to leak information to code that // isn't in the right place to begin with. baseband::Direction direction() const { - return baseband::Direction::Receive; + return _direction; } private: static Thread* thread; BasebandProcessor* baseband_processor { nullptr }; + baseband::Direction _direction; uint32_t sampling_rate; void run() override; From 62d2ae2336bd847412dd80562e900adb81af951f Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Aug 2016 16:42:39 -0700 Subject: [PATCH 016/100] SGPIO: Change bus direction more deliberately. There may have been an instant where the CPLD and SGPIO were driving the bus simultaneously, when switching from TX to RX. --- firmware/common/baseband_sgpio.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/common/baseband_sgpio.cpp b/firmware/common/baseband_sgpio.cpp index e4554e96..a718c6fc 100644 --- a/firmware/common/baseband_sgpio.cpp +++ b/firmware/common/baseband_sgpio.cpp @@ -299,7 +299,9 @@ void SGPIO::configure(const Direction direction) { disable_all_slice_counters(); LPC_SGPIO->GPIO_OUTREG = gpio_outreg(direction); - LPC_SGPIO->GPIO_OENREG = gpio_oenreg(direction); + + // Set data pins as input, temporarily. + LPC_SGPIO->GPIO_OENREG = gpio_oenreg(Direction::Receive); LPC_SGPIO->OUT_MUX_CFG[ 8] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE); LPC_SGPIO->OUT_MUX_CFG[ 9] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE); LPC_SGPIO->OUT_MUX_CFG[10] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE); @@ -314,6 +316,9 @@ void SGPIO::configure(const Direction direction) { LPC_SGPIO->OUT_MUX_CFG[i] = data_out_mux_cfg; } + // Now that output enable sources are set, enable data bus in correct direction. + LPC_SGPIO->GPIO_OENREG = gpio_oenreg(direction); + const auto slice_gpdma = Slice::H; const size_t slice_count = slice_mode_multislice ? 8 : 1; From 52c089c4dfb4298f2f0d06eea26e85a4d69251cb Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Aug 2016 16:46:02 -0700 Subject: [PATCH 017/100] SGPIO: Hi-Z data bus before setting direction pin. Another tactic to avoid bus contention, however brief. --- firmware/common/baseband_sgpio.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/common/baseband_sgpio.cpp b/firmware/common/baseband_sgpio.cpp index a718c6fc..a574e81d 100644 --- a/firmware/common/baseband_sgpio.cpp +++ b/firmware/common/baseband_sgpio.cpp @@ -298,10 +298,12 @@ constexpr P_OUT_CFG data_p_out_cfg( void SGPIO::configure(const Direction direction) { disable_all_slice_counters(); - LPC_SGPIO->GPIO_OUTREG = gpio_outreg(direction); - // Set data pins as input, temporarily. LPC_SGPIO->GPIO_OENREG = gpio_oenreg(Direction::Receive); + + // Now that data pins are inputs, safe to change CPLD direction. + LPC_SGPIO->GPIO_OUTREG = gpio_outreg(direction); + LPC_SGPIO->OUT_MUX_CFG[ 8] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE); LPC_SGPIO->OUT_MUX_CFG[ 9] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE); LPC_SGPIO->OUT_MUX_CFG[10] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE); From b0a3f680e52944c6b24928827eccfc723cd42459 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 11:31:37 -0700 Subject: [PATCH 018/100] CPLD: Remove decimation feature. --- firmware/application/ais_app.cpp | 1 - firmware/application/baseband_cpld.cpp | 13 ------------- firmware/application/baseband_cpld.hpp | 1 - firmware/application/capture_app.cpp | 1 - firmware/application/ert_app.cpp | 1 - firmware/application/radio.cpp | 5 ----- firmware/application/radio.hpp | 2 -- firmware/application/receiver_model.cpp | 8 +------- firmware/application/receiver_model.hpp | 3 --- firmware/application/tpms_app.cpp | 1 - firmware/common/hackrf_gpio.hpp | 5 ----- 11 files changed, 1 insertion(+), 40 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 814262e6..189ecacc 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -315,7 +315,6 @@ AISAppView::AISAppView(NavigationView&) { receiver_model.rf_amp(), static_cast(receiver_model.lna()), static_cast(receiver_model.vga()), - 1, }); options_channel.on_change = [this](size_t, OptionsField::value_t v) { diff --git a/firmware/application/baseband_cpld.cpp b/firmware/application/baseband_cpld.cpp index 50949cc7..1c42daa0 100644 --- a/firmware/application/baseband_cpld.cpp +++ b/firmware/application/baseband_cpld.cpp @@ -27,23 +27,10 @@ using namespace hackrf::one; namespace baseband { void CPLD::init() { - set_decimation_by(1); - gpios_baseband_decimation[0].output(); - gpios_baseband_decimation[1].output(); - gpios_baseband_decimation[2].output(); - set_q_invert(false); gpio_baseband_q_invert.output(); } -void CPLD::set_decimation_by(const uint8_t n) { - const uint8_t skip_n = n - 1; - const uint8_t value = skip_n ^ 7; - gpios_baseband_decimation[0].write(value & 1); - gpios_baseband_decimation[1].write(value & 2); - gpios_baseband_decimation[2].write(value & 4); -} - void CPLD::set_q_invert(const bool invert) { gpio_baseband_q_invert.write(invert); } diff --git a/firmware/application/baseband_cpld.hpp b/firmware/application/baseband_cpld.hpp index 2482306a..5124ba7f 100644 --- a/firmware/application/baseband_cpld.hpp +++ b/firmware/application/baseband_cpld.hpp @@ -30,7 +30,6 @@ class CPLD { public: void init(); - void set_decimation_by(const uint8_t n); void set_q_invert(const bool invert); private: diff --git a/firmware/application/capture_app.cpp b/firmware/application/capture_app.cpp index 87d40114..6ebcd02f 100644 --- a/firmware/application/capture_app.cpp +++ b/firmware/application/capture_app.cpp @@ -74,7 +74,6 @@ CaptureAppView::CaptureAppView(NavigationView& nav) { receiver_model.rf_amp(), static_cast(receiver_model.lna()), static_cast(receiver_model.vga()), - 1, }); record_view.set_sampling_rate(sampling_rate / 8); diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index e5597cd8..4ec70f93 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -142,7 +142,6 @@ ERTAppView::ERTAppView(NavigationView&) { receiver_model.rf_amp(), static_cast(receiver_model.lna()), static_cast(receiver_model.vga()), - 1, }); logger = std::make_unique(); diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index b61ce022..27cd253c 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -158,10 +158,6 @@ void set_baseband_rate(const uint32_t rate) { portapack::clock_manager.set_sampling_frequency(rate); } -void set_baseband_decimation_by(const size_t n) { - baseband_cpld.set_decimation_by(n); -} - void set_antenna_bias(const bool on) { /* Pull MOSFET gate low to turn on antenna bias. */ first_if.set_gpo1(on ? 0 : 1); @@ -185,7 +181,6 @@ void configure(Configuration configuration) { set_lna_gain(configuration.lna_gain); set_vga_gain(configuration.vga_gain); set_baseband_rate(configuration.baseband_rate); - set_baseband_decimation_by(configuration.baseband_decimation); set_baseband_filter_bandwidth(configuration.baseband_filter_bandwidth); set_direction(configuration.direction); } diff --git a/firmware/application/radio.hpp b/firmware/application/radio.hpp index 6d22acf3..cb1929c8 100644 --- a/firmware/application/radio.hpp +++ b/firmware/application/radio.hpp @@ -37,7 +37,6 @@ struct Configuration { bool rf_amp; int8_t lna_gain; int8_t vga_gain; - uint8_t baseband_decimation; }; void init(); @@ -50,7 +49,6 @@ void set_vga_gain(const int_fast8_t db); void set_tx_gain(const int_fast8_t db); void set_baseband_filter_bandwidth(const uint32_t bandwidth_minimum); void set_baseband_rate(const uint32_t rate); -void set_baseband_decimation_by(const size_t n); void set_antenna_bias(const bool on); void enable(Configuration configuration); diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index b5796c38..48d8447b 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -151,11 +151,6 @@ void ReceiverModel::set_headphone_volume(volume_t v) { update_headphone_volume(); } -uint32_t ReceiverModel::baseband_oversampling() const { - // TODO: Rename decimation_factor. - return decimation_factor_; -} - void ReceiverModel::enable() { enabled_ = true; radio::set_direction(rf::Direction::Receive); @@ -243,9 +238,8 @@ void ReceiverModel::update_sampling_rate() { // protocols that need quick RX/TX turn-around. // Disabling baseband while changing sampling rates seems like a good idea... - radio::set_baseband_rate(sampling_rate() * baseband_oversampling()); + radio::set_baseband_rate(sampling_rate()); update_tuning_frequency(); - radio::set_baseband_decimation_by(baseband_oversampling()); } void ReceiverModel::update_headphone_volume() { diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index 4499e9fe..1d6d4783 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -72,8 +72,6 @@ public: volume_t headphone_volume() const; void set_headphone_volume(volume_t v); - uint32_t baseband_oversampling() const; - void enable(); void disable(); @@ -97,7 +95,6 @@ private: int32_t tx_gain_db_ { 47 }; Mode mode_ { Mode::NarrowbandFMAudio }; uint32_t sampling_rate_ { 3072000 }; - size_t decimation_factor_ { 1 }; size_t am_config_index = 0; size_t nbfm_config_index = 0; size_t wfm_config_index = 0; diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 008a920a..cc55f276 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -184,7 +184,6 @@ TPMSAppView::TPMSAppView(NavigationView&) { receiver_model.rf_amp(), static_cast(receiver_model.lna()), static_cast(receiver_model.vga()), - 1, }); options_band.on_change = [this](size_t, OptionsField::value_t v) { diff --git a/firmware/common/hackrf_gpio.hpp b/firmware/common/hackrf_gpio.hpp index 57257f06..62d32446 100644 --- a/firmware/common/hackrf_gpio.hpp +++ b/firmware/common/hackrf_gpio.hpp @@ -71,11 +71,6 @@ constexpr GPIO gpio_max2837_txenable = gpio[GPIO2_4]; constexpr GPIO gpio_max5864_select = gpio[GPIO2_7]; -constexpr std::array gpios_baseband_decimation { - gpio[GPIO5_12], - gpio[GPIO5_13], - gpio[GPIO5_14] -}; constexpr GPIO gpio_baseband_q_invert = gpio[GPIO0_13]; constexpr GPIO gpio_cpld_tdo = gpio[GPIO5_18]; From 77016b9a40178ab99df3ada3a137311d0dce5550 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 11:34:46 -0700 Subject: [PATCH 019/100] Rename CPLD "Q_INVERT" to signal to "INVERT". Don't expose detail in name about how the task is accomplished. --- firmware/application/baseband_cpld.cpp | 8 ++++---- firmware/application/baseband_cpld.hpp | 2 +- firmware/application/radio.cpp | 2 +- firmware/application/tuning.cpp | 8 ++++---- firmware/application/tuning.hpp | 8 ++++---- firmware/common/hackrf_gpio.hpp | 2 +- firmware/common/pins.hpp | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/application/baseband_cpld.cpp b/firmware/application/baseband_cpld.cpp index 1c42daa0..ded20b48 100644 --- a/firmware/application/baseband_cpld.cpp +++ b/firmware/application/baseband_cpld.cpp @@ -27,12 +27,12 @@ using namespace hackrf::one; namespace baseband { void CPLD::init() { - set_q_invert(false); - gpio_baseband_q_invert.output(); + set_invert(false); + gpio_baseband_invert.output(); } -void CPLD::set_q_invert(const bool invert) { - gpio_baseband_q_invert.write(invert); +void CPLD::set_invert(const bool invert) { + gpio_baseband_invert.write(invert); } } diff --git a/firmware/application/baseband_cpld.hpp b/firmware/application/baseband_cpld.hpp index 5124ba7f..6bcb63aa 100644 --- a/firmware/application/baseband_cpld.hpp +++ b/firmware/application/baseband_cpld.hpp @@ -30,7 +30,7 @@ class CPLD { public: void init(); - void set_q_invert(const bool invert); + void set_invert(const bool invert); private: }; diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index 27cd253c..681f5560 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -126,7 +126,7 @@ bool set_tuning_frequency(const rf::Frequency frequency) { const auto result_second_if = second_if.set_frequency(tuning_config.second_lo_frequency); rf_path.set_band(tuning_config.rf_path_band); - baseband_cpld.set_q_invert(tuning_config.baseband_q_invert); + baseband_cpld.set_invert(tuning_config.baseband_invert); return result_second_if; } else { diff --git a/firmware/application/tuning.cpp b/firmware/application/tuning.cpp index 0ca8711b..310b3213 100644 --- a/firmware/application/tuning.cpp +++ b/firmware/application/tuning.cpp @@ -49,8 +49,8 @@ constexpr rf::Frequency high_band_second_lo_frequency(const rf::Frequency target Config low_band(const rf::Frequency target_frequency) { const rf::Frequency first_lo_frequency = target_frequency + low_band_second_lo_frequency(target_frequency); const rf::Frequency second_lo_frequency = first_lo_frequency - target_frequency; - const bool baseband_q_invert = true; - return { first_lo_frequency, second_lo_frequency, rf::path::Band::Low, baseband_q_invert }; + const bool baseband_invert = true; + return { first_lo_frequency, second_lo_frequency, rf::path::Band::Low, baseband_invert }; } Config mid_band(const rf::Frequency target_frequency) { @@ -60,8 +60,8 @@ Config mid_band(const rf::Frequency target_frequency) { Config high_band(const rf::Frequency target_frequency) { const rf::Frequency first_lo_frequency = target_frequency - high_band_second_lo_frequency(target_frequency); const rf::Frequency second_lo_frequency = target_frequency - first_lo_frequency; - const bool baseband_q_invert = false; - return { first_lo_frequency, second_lo_frequency, rf::path::Band::High, baseband_q_invert }; + const bool baseband_invert = false; + return { first_lo_frequency, second_lo_frequency, rf::path::Band::High, baseband_invert }; } } /* namespace */ diff --git a/firmware/application/tuning.hpp b/firmware/application/tuning.hpp index 16b19fd9..16b4509a 100644 --- a/firmware/application/tuning.hpp +++ b/firmware/application/tuning.hpp @@ -33,7 +33,7 @@ struct Config { ) : first_lo_frequency(0), second_lo_frequency(0), rf_path_band(rf::path::Band::Mid), - baseband_q_invert(false) + baseband_invert(false) { } @@ -41,11 +41,11 @@ struct Config { rf::Frequency first_lo_frequency, rf::Frequency second_lo_frequency, rf::path::Band rf_path_band, - bool baseband_q_invert + bool baseband_invert ) : first_lo_frequency(first_lo_frequency), second_lo_frequency(second_lo_frequency), rf_path_band(rf_path_band), - baseband_q_invert(baseband_q_invert) + baseband_invert(baseband_invert) { } @@ -56,7 +56,7 @@ struct Config { const rf::Frequency first_lo_frequency; const rf::Frequency second_lo_frequency; const rf::path::Band rf_path_band; - const bool baseband_q_invert; + const bool baseband_invert; }; Config create(const rf::Frequency target_frequency); diff --git a/firmware/common/hackrf_gpio.hpp b/firmware/common/hackrf_gpio.hpp index 62d32446..41f58fc9 100644 --- a/firmware/common/hackrf_gpio.hpp +++ b/firmware/common/hackrf_gpio.hpp @@ -71,7 +71,7 @@ constexpr GPIO gpio_max2837_txenable = gpio[GPIO2_4]; constexpr GPIO gpio_max5864_select = gpio[GPIO2_7]; -constexpr GPIO gpio_baseband_q_invert = gpio[GPIO0_13]; +constexpr GPIO gpio_baseband_invert = gpio[GPIO0_13]; constexpr GPIO gpio_cpld_tdo = gpio[GPIO5_18]; constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0]; diff --git a/firmware/common/pins.hpp b/firmware/common/pins.hpp index 527e4485..76f1761d 100644 --- a/firmware/common/pins.hpp +++ b/firmware/common/pins.hpp @@ -61,7 +61,7 @@ constexpr Pin pins[] = { [P1_15] = { 1, 15, PinConfig::sgpio_inout_fast(2) }, /* SGPIO2/BANK2F3M9: CPLD.74/HOST_DATA2(IO) */ [P1_16] = { 1, 16, PinConfig::sgpio_inout_fast(2) }, /* SGPIO3/BANK2F3M10: CPLD.72/HOST_DATA3(IO) */ [P1_17] = { 1, 17, PinConfig::sgpio_out_fast_with_pullup(6) }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */ - [P1_18] = { 1, 18, PinConfig::gpio_out_with_pulldown(0) }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_Q_INVERT(I) */ + [P1_18] = { 1, 18, PinConfig::gpio_out_with_pulldown(0) }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */ [P1_19] = { 1, 19, { .mode=1, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */ [P1_20] = { 1, 20, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* CS_XCVR/P53: MAX2837.CS(I) */ [P2_0] = { 2, 0, { .mode=4, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */ From f20647feb4e74529452199b174255143333c17b8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 11:42:05 -0700 Subject: [PATCH 020/100] MAX2837: Expose trim/bias/calibration adjustments. --- firmware/application/max2837.cpp | 28 ++++++++++++++++++++++++++++ firmware/application/max2837.hpp | 5 +++++ 2 files changed, 33 insertions(+) diff --git a/firmware/application/max2837.cpp b/firmware/application/max2837.cpp index 4db7bf92..4825da10 100644 --- a/firmware/application/max2837.cpp +++ b/firmware/application/max2837.cpp @@ -242,6 +242,34 @@ bool MAX2837::set_frequency(const rf::Frequency lo_frequency) { return true; } +void MAX2837::set_rx_lo_iq_calibration(const size_t v) { + _map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1; + _dirty[Register::RX_TOP_RX_BIAS] = 1; + _map.r.rxrf_2.iqerr_trim = v; + _dirty[Register::RXRF_2] = 1; + flush(); +} + +void MAX2837::set_rx_bias_trim(const size_t v) { + _map.r.rx_top_rx_bias.EN_Bias_Trim = 1; + _map.r.rx_top_rx_bias.BIAS_TRIM_SPI = v; + _dirty[Register::RX_TOP_RX_BIAS] = 1; + flush(); +} + +void MAX2837::set_vco_bias(const size_t v) { + _map.r.vco_cfg.VCO_BIAS_SPI_EN = 1; + _map.r.vco_cfg.VCO_BIAS_SPI = v; + _dirty[Register::VCO_CFG] = 1; + flush(); +} + +void MAX2837::set_rx_buff_vcm(const size_t v) { + _map.r.lpf_3_vga_1.BUFF_VCM = v; + _dirty[Register::LPF_3_VGA_1] = 1; + flush(); +} + reg_t MAX2837::temp_sense() { if( !_map.r.rx_top.ts_en ) { _map.r.rx_top.ts_en = 1; diff --git a/firmware/application/max2837.hpp b/firmware/application/max2837.hpp index 857bb4e9..3f1beb70 100644 --- a/firmware/application/max2837.hpp +++ b/firmware/application/max2837.hpp @@ -884,6 +884,11 @@ public: bool set_frequency(const rf::Frequency lo_frequency); + void set_rx_lo_iq_calibration(const size_t v); + void set_rx_bias_trim(const size_t v); + void set_vco_bias(const size_t v); + void set_rx_buff_vcm(const size_t v); + reg_t temp_sense(); reg_t read(const address_t reg_num); From 43a11ba04801dc34f7ea65aaec64b087ab1f8330 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 17:49:06 -0700 Subject: [PATCH 021/100] Rename time files/namespace to not conflict with existing defs. --- firmware/application/CMakeLists.txt | 2 +- firmware/application/event_m0.cpp | 4 ++-- firmware/application/{time.cpp => rtc_time.cpp} | 6 +++--- firmware/application/{time.hpp => rtc_time.hpp} | 10 +++++----- firmware/application/ui_record_view.cpp | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) rename firmware/application/{time.cpp => rtc_time.cpp} (92%) rename firmware/application/{time.hpp => rtc_time.hpp} (88%) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 50dc53bb..23d61736 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -170,7 +170,7 @@ set(CPPSRC ${COMMON}/ert_packet.cpp capture_app.cpp sd_card.cpp - time.cpp + rtc_time.cpp file.cpp log_file.cpp ${COMMON}/png_writer.cpp diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index d40d60a9..a7fae4a3 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -24,7 +24,7 @@ #include "portapack.hpp" #include "sd_card.hpp" -#include "time.hpp" +#include "rtc_time.hpp" #include "message.hpp" #include "message_queue.hpp" @@ -219,7 +219,7 @@ void EventDispatcher::handle_rtc_tick() { portapack::temperature_logger.second_tick(); - time::on_tick_second(); + rtc_time::on_tick_second(); } ui::Widget* EventDispatcher::touch_widget(ui::Widget* const w, ui::TouchEvent event) { diff --git a/firmware/application/time.cpp b/firmware/application/rtc_time.cpp similarity index 92% rename from firmware/application/time.cpp rename to firmware/application/rtc_time.cpp index 10ba7f3b..d4a9f506 100644 --- a/firmware/application/time.cpp +++ b/firmware/application/rtc_time.cpp @@ -19,9 +19,9 @@ * Boston, MA 02110-1301, USA. */ -#include "time.hpp" +#include "rtc_time.hpp" -namespace time { +namespace rtc_time { Signal<> signal_tick_second; @@ -29,4 +29,4 @@ void on_tick_second() { signal_tick_second.emit(); } -} /* namespace time */ +} /* namespace rtc_time */ diff --git a/firmware/application/time.hpp b/firmware/application/rtc_time.hpp similarity index 88% rename from firmware/application/time.hpp rename to firmware/application/rtc_time.hpp index 470c894d..e43793be 100644 --- a/firmware/application/time.hpp +++ b/firmware/application/rtc_time.hpp @@ -19,17 +19,17 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __TIME_H__ -#define __TIME_H__ +#ifndef __RTC_TIME_H__ +#define __RTC_TIME_H__ #include "signal.hpp" -namespace time { +namespace rtc_time { extern Signal<> signal_tick_second; void on_tick_second(); -} /* namespace time */ +} /* namespace rtc_time */ -#endif/*__TIME_H__*/ +#endif/*__RTC_TIME_H__*/ diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 695a454d..bf7ec391 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -25,7 +25,7 @@ using namespace portapack; #include "file.hpp" -#include "time.hpp" +#include "rtc_time.hpp" #include "string_format.hpp" #include "utility.hpp" @@ -188,13 +188,13 @@ RecordView::RecordView( this->toggle(); }; - signal_token_tick_second = time::signal_tick_second += [this]() { + signal_token_tick_second = rtc_time::signal_tick_second += [this]() { this->on_tick_second(); }; } RecordView::~RecordView() { - time::signal_tick_second -= signal_token_tick_second; + rtc_time::signal_tick_second -= signal_token_tick_second; } void RecordView::focus() { From f7bfde73b63c0bb17d7f64e0468bf279bbfd0776 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 18:06:39 -0700 Subject: [PATCH 022/100] FatFs: Enable long file name support. Lots of re-plumbing to make this work, including a bunch of Unicode stuff now in the binary. Bloat City, I'm sure. TODO: FatFs using unsigned (uint16_t) for UTF16 representation is kinda inconvenient. Lots of reinterpret_cast<>(). --- firmware/application/ais_app.cpp | 2 +- firmware/application/ais_app.hpp | 2 +- firmware/application/analog_audio_app.hpp | 2 +- firmware/application/capture_app.hpp | 2 +- firmware/application/ert_app.cpp | 2 +- firmware/application/ert_app.hpp | 2 +- firmware/application/ffconf.h | 4 +-- firmware/application/file.cpp | 34 +++++++++---------- firmware/application/file.hpp | 21 +++++++----- firmware/application/log_file.hpp | 2 +- firmware/application/sd_card.cpp | 2 +- firmware/application/tpms_app.cpp | 2 +- firmware/application/tpms_app.hpp | 2 +- firmware/application/ui_navigation.cpp | 4 +-- firmware/application/ui_record_view.cpp | 24 ++++++++----- firmware/application/ui_record_view.hpp | 6 ++-- firmware/application/ui_sd_card_debug.cpp | 8 ++--- .../os/various/fatfs_bindings/fatfs.cmake | 1 + firmware/common/png_writer.cpp | 2 +- firmware/common/png_writer.hpp | 2 +- 20 files changed, 68 insertions(+), 58 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 189ecacc..1b04bc18 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -331,7 +331,7 @@ AISAppView::AISAppView(NavigationView&) { logger = std::make_unique(); if( logger ) { - logger->append("ais.txt"); + logger->append(u"ais.txt"); } } diff --git a/firmware/application/ais_app.hpp b/firmware/application/ais_app.hpp index b38a2146..10da06a2 100644 --- a/firmware/application/ais_app.hpp +++ b/firmware/application/ais_app.hpp @@ -95,7 +95,7 @@ using AISRecentEntries = RecentEntries; class AISLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/analog_audio_app.hpp b/firmware/application/analog_audio_app.hpp index a91e8059..697a199a 100644 --- a/firmware/application/analog_audio_app.hpp +++ b/firmware/application/analog_audio_app.hpp @@ -143,7 +143,7 @@ private: RecordView record_view { { 0 * 8, 2 * 16, 30 * 8, 1 * 16 }, - "AUD_????", RecordView::FileType::WAV, 4096, 4 + u"AUD_????", RecordView::FileType::WAV, 4096, 4 }; spectrum::WaterfallWidget waterfall; diff --git a/firmware/application/capture_app.hpp b/firmware/application/capture_app.hpp index a7d04859..76d287f0 100644 --- a/firmware/application/capture_app.hpp +++ b/firmware/application/capture_app.hpp @@ -89,7 +89,7 @@ private: RecordView record_view { { 0 * 8, 1 * 16, 30 * 8, 1 * 16 }, - "BBD_????", RecordView::FileType::RawS16, 16384, 3 + u"BBD_????", RecordView::FileType::RawS16, 16384, 3 }; spectrum::WaterfallWidget waterfall; diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 4ec70f93..5bed3782 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -146,7 +146,7 @@ ERTAppView::ERTAppView(NavigationView&) { logger = std::make_unique(); if( logger ) { - logger->append("ert.txt"); + logger->append(u"ert.txt"); } } diff --git a/firmware/application/ert_app.hpp b/firmware/application/ert_app.hpp index 1d901f45..cba9e74a 100644 --- a/firmware/application/ert_app.hpp +++ b/firmware/application/ert_app.hpp @@ -90,7 +90,7 @@ struct ERTRecentEntry { class ERTLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/ffconf.h b/firmware/application/ffconf.h index a02d51b0..cfe0e890 100644 --- a/firmware/application/ffconf.h +++ b/firmware/application/ffconf.h @@ -101,7 +101,7 @@ */ -#define _USE_LFN 0 +#define _USE_LFN 2 #define _MAX_LFN 255 /* The _USE_LFN switches the support of long file name (LFN). / @@ -119,7 +119,7 @@ / ff_memfree(), must be added to the project. */ -#define _LFN_UNICODE 0 +#define _LFN_UNICODE 1 /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. / This option also affects behavior of string I/O functions. */ diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index f4415452..4ceb51aa 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -30,8 +30,8 @@ static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected."); #define FR_BAD_SEEK (0x102) #define FR_UNEXPECTED (0x103) -Optional File::open_fatfs(const std::string& filename, BYTE mode) { - auto result = f_open(&f, filename.c_str(), mode); +Optional File::open_fatfs(const std::filesystem::path& filename, BYTE mode) { + auto result = f_open(&f, reinterpret_cast(filename.c_str()), mode); if( result == FR_OK ) { if( mode & FA_OPEN_ALWAYS ) { const auto result = f_lseek(&f, f_size(&f)); @@ -48,15 +48,15 @@ Optional File::open_fatfs(const std::string& filename, BYTE mode) { } } -Optional File::open(const std::string& filename) { +Optional File::open(const std::filesystem::path& filename) { return open_fatfs(filename, FA_READ); } -Optional File::append(const std::string& filename) { +Optional File::append(const std::filesystem::path& filename) { return open_fatfs(filename, FA_WRITE | FA_OPEN_ALWAYS); } -Optional File::create(const std::string& filename) { +Optional File::create(const std::filesystem::path& filename) { return open_fatfs(filename, FA_WRITE | FA_CREATE_ALWAYS); } @@ -124,9 +124,9 @@ Optional File::sync() { } } -static std::string find_last_file_matching_pattern(const std::string& pattern) { - std::string last_match; - for(const auto& entry : std::filesystem::directory_iterator("", pattern.c_str())) { +static std::filesystem::path find_last_file_matching_pattern(const std::filesystem::path& pattern) { + std::filesystem::path last_match; + for(const auto& entry : std::filesystem::directory_iterator(u"", pattern.c_str())) { if( std::filesystem::is_regular_file(entry.status()) ) { const auto match = entry.path(); if( match > last_match ) { @@ -137,13 +137,13 @@ static std::string find_last_file_matching_pattern(const std::string& pattern) { return last_match; } -static std::string remove_filename_extension(const std::string& filename) { +static std::filesystem::path remove_filename_extension(const std::filesystem::path& filename) { const auto extension_index = filename.find_last_of('.'); return filename.substr(0, extension_index); } -static std::string increment_filename_stem_ordinal(const std::string& filename_stem) { - std::string result { filename_stem }; +static std::filesystem::path increment_filename_stem_ordinal(const std::filesystem::path& filename_stem) { + std::filesystem::path result { filename_stem }; auto it = result.rbegin(); @@ -165,8 +165,8 @@ static std::string increment_filename_stem_ordinal(const std::string& filename_s return result; } -std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern) { - const auto filename = find_last_file_matching_pattern(filename_stem_pattern + ".*"); +std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem::path& filename_stem_pattern) { + const auto filename = find_last_file_matching_pattern(filename_stem_pattern + u".*"); auto filename_stem = remove_filename_extension(filename); if( filename_stem.empty() ) { filename_stem = filename_stem_pattern; @@ -211,11 +211,11 @@ std::string filesystem_error::what() const { } directory_iterator::directory_iterator( - const char* path, - const char* wild + const std::filesystem::path::value_type* path, + const std::filesystem::path::value_type* wild ) { impl = std::make_shared(); - const auto result = f_findfirst(&impl->dir, &impl->filinfo, path, wild); + const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast(path), reinterpret_cast(wild)); if( result != FR_OK ) { impl.reset(); // TODO: Throw exception if/when I enable exceptions... @@ -237,7 +237,7 @@ bool is_regular_file(const file_status s) { space_info space(const path& p) { DWORD free_clusters { 0 }; FATFS* fs; - if( f_getfree(p.c_str(), &free_clusters, &fs) == FR_OK ) { + if( f_getfree(reinterpret_cast(p.c_str()), &free_clusters, &fs) == FR_OK ) { #if _MAX_SS != _MIN_SS static_assert(false, "FatFs not configured for fixed sector size"); #else diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index f3739317..62813e21 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -33,8 +33,6 @@ #include #include -std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern); - namespace std { namespace filesystem { @@ -66,9 +64,12 @@ private: uint32_t err; }; -using path = std::string; +using path = std::u16string; using file_status = BYTE; +static_assert(sizeof(path::value_type) == 2, "sizeof(std::filesystem::path::value_type) != 2"); +static_assert(sizeof(path::value_type) == sizeof(TCHAR), "FatFs TCHAR size != std::filesystem::path::value_type"); + struct space_info { static_assert(sizeof(std::uintmax_t) >= 8, "std::uintmax_t too small ((fname); }; }; class directory_iterator { @@ -107,7 +108,7 @@ public: using iterator_category = std::input_iterator_tag; directory_iterator() noexcept { }; - directory_iterator(const char* path, const char* wild); + directory_iterator(const std::filesystem::path::value_type* path, const std::filesystem::path::value_type* wild); ~directory_iterator() { } @@ -131,6 +132,8 @@ space_info space(const path& p); } /* namespace filesystem */ } /* namespace std */ +std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem::path& filename_stem_pattern); + class File { public: using Error = std::filesystem::filesystem_error; @@ -193,9 +196,9 @@ public: File& operator=(const File&) = delete; // TODO: Return Result<>. - Optional open(const std::string& filename); - Optional append(const std::string& filename); - Optional create(const std::string& filename); + Optional open(const std::filesystem::path& filename); + Optional append(const std::filesystem::path& filename); + Optional create(const std::filesystem::path& filename); Result read(void* const data, const size_t bytes_to_read); Result write(const void* const data, const size_t bytes_to_write); @@ -215,7 +218,7 @@ public: private: FIL f; - Optional open_fatfs(const std::string& filename, BYTE mode); + Optional open_fatfs(const std::filesystem::path& filename, BYTE mode); }; #endif/*__FILE_H__*/ diff --git a/firmware/application/log_file.hpp b/firmware/application/log_file.hpp index 1e1f667a..5f222a79 100644 --- a/firmware/application/log_file.hpp +++ b/firmware/application/log_file.hpp @@ -31,7 +31,7 @@ using namespace lpc43xx; class LogFile { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return file.append(filename); } diff --git a/firmware/application/sd_card.cpp b/firmware/application/sd_card.cpp index ed2a90b2..b7846152 100644 --- a/firmware/application/sd_card.cpp +++ b/firmware/application/sd_card.cpp @@ -36,7 +36,7 @@ Status status_ { Status::NotPresent }; FATFS fs; FRESULT mount() { - return f_mount(&fs, "", 0); + return f_mount(&fs, reinterpret_cast(_T("")), 0); } } /* namespace */ diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index cc55f276..2a13e2f2 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -193,7 +193,7 @@ TPMSAppView::TPMSAppView(NavigationView&) { logger = std::make_unique(); if( logger ) { - logger->append("tpms.txt"); + logger->append(u"tpms.txt"); } } diff --git a/firmware/application/tpms_app.hpp b/firmware/application/tpms_app.hpp index fc9e0c35..98715219 100644 --- a/firmware/application/tpms_app.hpp +++ b/firmware/application/tpms_app.hpp @@ -76,7 +76,7 @@ using TPMSRecentEntries = RecentEntries; class TPMSLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 4238af12..ba8e783c 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -81,13 +81,13 @@ void SystemStatusView::set_title(const std::string new_value) { } void SystemStatusView::on_camera() { - const auto filename_stem = next_filename_stem_matching_pattern("SCR_????"); + const auto filename_stem = next_filename_stem_matching_pattern(u"SCR_????"); if( filename_stem.empty() ) { return; } PNGWriter png; - auto create_error = png.create(filename_stem + ".PNG"); + auto create_error = png.create(filename_stem + u".PNG"); if( create_error.is_valid() ) { return; } diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index bf7ec391..42e0d374 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -32,6 +32,9 @@ using namespace portapack; #include +#include +#include + class FileWriter : public Writer { public: FileWriter() = default; @@ -41,7 +44,7 @@ public: FileWriter(FileWriter&& file) = delete; FileWriter& operator=(FileWriter&&) = delete; - Optional create(const std::string& filename) { + Optional create(const std::filesystem::path& filename) { return file.create(filename); } @@ -79,7 +82,7 @@ public: } Optional create( - const std::string& filename + const std::filesystem::path& filename ) { const auto create_error = FileWriter::create(filename); if( create_error.is_valid() ) { @@ -164,7 +167,7 @@ namespace ui { RecordView::RecordView( const Rect parent_rect, - std::string filename_stem_pattern, + std::filesystem::path filename_stem_pattern, const FileType file_type, const size_t write_size, const size_t buffer_count @@ -251,7 +254,7 @@ void RecordView::start() { sampling_rate ); auto create_error = p->create( - filename_stem + ".WAV" + filename_stem + u".WAV" ); if( create_error.is_valid() ) { handle_error(create_error.value()); @@ -263,7 +266,7 @@ void RecordView::start() { case FileType::RawS16: { - const auto metadata_file_error = write_metadata_file(filename_stem + ".TXT"); + const auto metadata_file_error = write_metadata_file(filename_stem + u".TXT"); if( metadata_file_error.is_valid() ) { handle_error(metadata_file_error.value()); return; @@ -271,7 +274,7 @@ void RecordView::start() { auto p = std::make_unique(); auto create_error = p->create( - filename_stem + ".C16" + filename_stem + u".C16" ); if( create_error.is_valid() ) { handle_error(create_error.value()); @@ -286,7 +289,10 @@ void RecordView::start() { }; if( writer ) { - text_record_filename.set(filename_stem); + std::wstring_convert, std::filesystem::path::value_type> conv; + const auto filename_stem_s = conv.to_bytes(filename_stem); + + text_record_filename.set(filename_stem_s); button_record.set_bitmap(&bitmap_stop); capture_thread = std::make_unique( std::move(writer), @@ -314,7 +320,7 @@ void RecordView::stop() { update_status_display(); } -Optional RecordView::write_metadata_file(const std::string& filename) { +Optional RecordView::write_metadata_file(const std::filesystem::path& filename) { File file; const auto create_error = file.create(filename); if( create_error.is_valid() ) { @@ -344,7 +350,7 @@ void RecordView::update_status_display() { } if( sampling_rate ) { - const auto space_info = std::filesystem::space(""); + const auto space_info = std::filesystem::space(u""); const uint32_t bytes_per_second = file_type == FileType::WAV ? (sampling_rate * 2) : (sampling_rate * 4); const uint32_t available_seconds = space_info.free / bytes_per_second; const uint32_t seconds = available_seconds % 60; diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index 023fb0d5..203d334c 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -46,7 +46,7 @@ public: RecordView( const Rect parent_rect, - std::string filename_stem_pattern, + std::filesystem::path filename_stem_pattern, FileType file_type, const size_t write_size, const size_t buffer_count @@ -64,7 +64,7 @@ public: private: void toggle(); - Optional write_metadata_file(const std::string& filename); + Optional write_metadata_file(const std::filesystem::path& filename); void on_tick_second(); void update_status_display(); @@ -72,7 +72,7 @@ private: void handle_capture_thread_done(const File::Error error); void handle_error(const File::Error error); - const std::string filename_stem_pattern; + const std::filesystem::path filename_stem_pattern; const FileType file_type; const size_t write_size; const size_t buffer_count; diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index eac201ea..dd92f5c6 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -95,7 +95,7 @@ private: } Result run() { - const std::string filename { "_PPTEST_.DAT" }; + const std::filesystem::path filename { u"_PPTEST_.DAT" }; const auto write_result = write(filename); if( write_result != Result::OK ) { @@ -115,7 +115,7 @@ private: return read_result; } - f_unlink(filename.c_str()); + f_unlink(reinterpret_cast(filename.c_str())); if( _stats.read_bytes < bytes_to_read ) { return Result::FailReadIncomplete; @@ -128,7 +128,7 @@ private: return Result::OK; } - Result write(const std::string& filename) { + Result write(const std::filesystem::path& filename) { const auto buffer = std::make_unique>(); if( !buffer ) { return Result::FailHeap; @@ -175,7 +175,7 @@ private: return Result::OK; } - Result read(const std::string& filename) { + Result read(const std::filesystem::path& filename) { const auto buffer = std::make_unique>(); if( !buffer ) { return Result::FailHeap; diff --git a/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake b/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake index 389f5d14..1eff8f31 100644 --- a/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake +++ b/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake @@ -3,6 +3,7 @@ set(FATFSSRC ${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_diskio.c ${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_syscall.c ${CHIBIOS_PORTAPACK}/ext/fatfs/src/ff.c + ${CHIBIOS_PORTAPACK}/ext/fatfs/src/option/unicode.c ) set(FATFSINC diff --git a/firmware/common/png_writer.cpp b/firmware/common/png_writer.cpp index e1667f14..b714e322 100644 --- a/firmware/common/png_writer.cpp +++ b/firmware/common/png_writer.cpp @@ -50,7 +50,7 @@ static constexpr std::array png_iend { { } }; Optional PNGWriter::create( - const std::string& filename + const std::filesystem::path& filename ) { const auto create_error = file.create(filename); if( create_error.is_valid() ) { diff --git a/firmware/common/png_writer.hpp b/firmware/common/png_writer.hpp index 37bede47..020a118a 100644 --- a/firmware/common/png_writer.hpp +++ b/firmware/common/png_writer.hpp @@ -35,7 +35,7 @@ class PNGWriter { public: ~PNGWriter(); - Optional create(const std::string& filename); + Optional create(const std::filesystem::path& filename); void write_scanline(const std::array& scanline); From ed791ac5bdc9ae54676cf8197ef56e8dcc1692d8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 22:15:19 -0700 Subject: [PATCH 023/100] File: Widen size/offset types for 64-bit filesystems. --- firmware/application/capture_thread.hpp | 2 +- firmware/application/file.cpp | 10 +++++----- firmware/application/file.hpp | 10 ++++++---- firmware/application/ui_record_view.cpp | 2 +- firmware/application/ui_sd_card_debug.cpp | 12 ++++++------ 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index 849a3131..6e2bbaa8 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -35,7 +35,7 @@ class Writer { public: - virtual File::Result write(const void* const buffer, const size_t bytes) = 0; + virtual File::Result write(const void* const buffer, const File::Size bytes) = 0; virtual ~Writer() = default; }; diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 4ceb51aa..8c45c8b3 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -64,7 +64,7 @@ File::~File() { f_close(&f); } -File::Result File::read(void* const data, const size_t bytes_to_read) { +File::Result File::read(void* const data, const Size bytes_to_read) { UINT bytes_read = 0; const auto result = f_read(&f, data, bytes_to_read, &bytes_read); if( result == FR_OK ) { @@ -74,12 +74,12 @@ File::Result File::read(void* const data, const size_t bytes_to_read) { } } -File::Result File::write(const void* const data, const size_t bytes_to_write) { +File::Result File::write(const void* const data, const Size bytes_to_write) { UINT bytes_written = 0; const auto result = f_write(&f, data, bytes_to_write, &bytes_written); if( result == FR_OK ) { if( bytes_to_write == bytes_written ) { - return { static_cast(bytes_written) }; + return { static_cast(bytes_written) }; } else { return Error { FR_DISK_FULL }; } @@ -88,7 +88,7 @@ File::Result File::write(const void* const data, const size_t bytes_to_w } } -File::Result File::seek(const uint64_t new_position) { +File::Result File::seek(const Offset new_position) { /* NOTE: Returns *old* position, not new position */ const auto old_position = f_tell(&f); const auto result = f_lseek(&f, new_position); @@ -98,7 +98,7 @@ File::Result File::seek(const uint64_t new_position) { if( f_tell(&f) != new_position ) { return { static_cast(FR_BAD_SEEK) }; } - return { static_cast(old_position) }; + return { static_cast(old_position) }; } Optional File::write_line(const std::string& s) { diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 62813e21..64691703 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -136,6 +136,8 @@ std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem: class File { public: + using Size = uint64_t; + using Offset = uint64_t; using Error = std::filesystem::filesystem_error; template @@ -200,13 +202,13 @@ public: Optional append(const std::filesystem::path& filename); Optional create(const std::filesystem::path& filename); - Result read(void* const data, const size_t bytes_to_read); - Result write(const void* const data, const size_t bytes_to_write); + Result read(void* const data, const Size bytes_to_read); + Result write(const void* const data, const Size bytes_to_write); - Result seek(const uint64_t new_position); + Result seek(const uint64_t Offset); template - Result write(const std::array& data) { + Result write(const std::array& data) { return write(data.data(), N); } diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 42e0d374..71211dfc 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -48,7 +48,7 @@ public: return file.create(filename); } - File::Result write(const void* const buffer, const size_t bytes) override { + File::Result write(const void* const buffer, const File::Size bytes) override { auto write_result = file.write(buffer, bytes) ; if( write_result.is_ok() ) { bytes_written += write_result.value(); diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index dd92f5c6..856f3e63 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -51,13 +51,13 @@ public: halrtcnt_t write_duration_min { 0 }; halrtcnt_t write_duration_max { 0 }; halrtcnt_t write_test_duration { 0 }; - size_t write_bytes { 0 }; + File::Size write_bytes { 0 }; size_t write_count { 0 }; halrtcnt_t read_duration_min { 0 }; halrtcnt_t read_duration_max { 0 }; halrtcnt_t read_test_duration { 0 }; - size_t read_bytes { 0 }; + File::Size read_bytes { 0 }; size_t read_count { 0 }; }; @@ -80,9 +80,9 @@ public: } private: - static constexpr size_t write_size = 16384; - static constexpr size_t bytes_to_write = 16 * 1024 * 1024; - static constexpr size_t bytes_to_read = bytes_to_write; + static constexpr File::Size write_size = 16384; + static constexpr File::Size bytes_to_write = 16 * 1024 * 1024; + static constexpr File::Size bytes_to_read = bytes_to_write; static Thread* thread; volatile Result _result { Result::Incomplete }; @@ -365,7 +365,7 @@ static std::string format_ticks_as_ms(const halrtcnt_t value) { return format_3dot3_string(us); } -static std::string format_bytes_per_ticks_as_mib(const size_t bytes, const halrtcnt_t ticks) { +static std::string format_bytes_per_ticks_as_mib(const File::Size bytes, const halrtcnt_t ticks) { const uint32_t bps = uint64_t(bytes) * halGetCounterFrequency() / ticks; const uint32_t kbps = bps / 1000U; return format_3dot3_string(kbps); From 81517b3f4d095516e564debc85ab8935d348af8e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 22:16:08 -0700 Subject: [PATCH 024/100] SD debug: Enlarge stack for long filenames, etc. --- firmware/application/ui_sd_card_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index 856f3e63..22db218c 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -63,7 +63,7 @@ public: SDCardTestThread( ) { - thread = chThdCreateFromHeap(NULL, 2048, NORMALPRIO + 10, SDCardTestThread::static_fn, this); + thread = chThdCreateFromHeap(NULL, 3072, NORMALPRIO + 10, SDCardTestThread::static_fn, this); } Result result() const { From 60cc9b7faa4b435c78b2dc6f4abddc7c81c034e8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 23:02:00 -0700 Subject: [PATCH 025/100] FatFs: Apply patch ff12a_p5.diff. Fixed one chunk of this patch in an earlier commit. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index ca71f697..f0b927d5 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -5303,7 +5303,7 @@ FRESULT f_mkfs ( #if _FS_EXFAT if (fmt == FS_EXFAT) { /* Create an exFAT volume */ - DWORD sum, szb_bit, szb_case; + DWORD szb_bit, szb_case, sum, nb, cl; WCHAR ch, si; UINT j, st; BYTE b; @@ -5368,32 +5368,37 @@ FRESULT f_mkfs ( tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case clusters */ /* Initialize the allocation bitmap */ - mem_set(buf, 0, szb_buf); /* Set in-use flags of bitmap, up-case and root dir */ - for (i = 0, n = tbl[0] + tbl[1] + tbl[2]; n >= 8; buf[i++] = 0xFF, n -= 8) ; - for (b = 1; n; buf[i] |= b, b <<= 1, n--) ; sect = b_data; n = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of the sectors */ - do { /* Fill allocation bitmap sectors */ - ns = (n > sz_buf) ? sz_buf : n; + nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ + do { + mem_set(buf, 0, szb_buf); + for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + ns = (n > sz_buf) ? sz_buf : n; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; - mem_set(buf, 0, ss); - } while (n -= ns); + sect += ns; n -= ns; + } while (n); /* Initialize the FAT */ - st_qword(buf, 0xFFFFFFFFFFFFFFF8); /* Entry 0 and 1 */ - for (j = 0, i = 2; j < 3; j++) { /* Set entries of bitmap, up-case and root dir */ - for (n = tbl[j]; n; n--) { - st_dword(buf + i * 4, (n >= 2) ? i + 1 : 0xFFFFFFFF); - i++; - } - } sect = b_fat; n = sz_fat; /* Start of FAT and number of the sectors */ - do { /* Fill FAT sectors */ - ns = (n > sz_buf) ? sz_buf : n; + j = nb = cl = 0; + do { + mem_set(buf, 0, szb_buf); i = 0; + if (cl == 0) { /* Set entry 0 and 1 */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; + } + do { /* Create chains of bitmap, up-case and root dir */ + while (nb && i < szb_buf) { /* Create a chain */ + st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); + i += 4; cl++; nb--; + } + if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb && i < szb_buf); + ns = (n > sz_buf) ? sz_buf : n; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR; - sect += ns; - mem_set(buf, 0, ss); - } while (n -= ns); + sect += ns; n -= ns; + } while (n); /* Initialize the root directory */ mem_set(buf, 0, ss); From 11a5aa9766f2b6c592eefa7a09475bd598fbb0b1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 23:03:08 -0700 Subject: [PATCH 026/100] FatFs: Apply patch ff12a_p6.diff. --- firmware/chibios-portapack/ext/fatfs/src/ff.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/firmware/chibios-portapack/ext/fatfs/src/ff.c b/firmware/chibios-portapack/ext/fatfs/src/ff.c index f0b927d5..04e197cf 100644 --- a/firmware/chibios-portapack/ext/fatfs/src/ff.c +++ b/firmware/chibios-portapack/ext/fatfs/src/ff.c @@ -4038,11 +4038,16 @@ FRESULT f_lseek ( } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; #if !_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */ if (clst == 0) { /* When disk gets full, clip file size */ - ofs = bcs; break; + ofs = 0; break; } } else #endif @@ -4050,8 +4055,6 @@ FRESULT f_lseek ( if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; - fp->fptr += bcs; - ofs -= bcs; } fp->fptr += ofs; if (ofs % SS(fs)) { From e2fe4b65d9c74c5daa5de807f781b31c331a5af9 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 23 Aug 2016 10:30:05 -0700 Subject: [PATCH 027/100] CPLD: Set DECIM1 as input to CPLD. How did DECIM work before?! Now, decimate is no longer a feature, so this doesn't really matter. But tidying it up anyway. --- firmware/common/baseband_sgpio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/baseband_sgpio.cpp b/firmware/common/baseband_sgpio.cpp index a574e81d..1cc0d143 100644 --- a/firmware/common/baseband_sgpio.cpp +++ b/firmware/common/baseband_sgpio.cpp @@ -190,7 +190,7 @@ constexpr uint32_t gpio_outreg(const Direction direction) { constexpr uint32_t gpio_oenreg(const Direction direction) { return (0U << PIN_DECIM2) - | (1U << PIN_DECIM1) + | (0U << PIN_DECIM1) | (0U << PIN_DECIM0) | (0U << PIN_INVERT) | (1U << PIN_DIRECTION) From f0c4b0fc9879c893c2ef2ed3a641b24b5d81e687 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 29 Aug 2016 20:26:39 -0700 Subject: [PATCH 028/100] AIS: Doesn't use RRC filter -- use rect instead. --- firmware/baseband/proc_ais.hpp | 2 +- firmware/common/ais_baseband.hpp | 22 +++++++--------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/firmware/baseband/proc_ais.hpp b/firmware/baseband/proc_ais.hpp index eff71b4a..97e813ff 100644 --- a/firmware/baseband/proc_ais.hpp +++ b/firmware/baseband/proc_ais.hpp @@ -62,7 +62,7 @@ private: dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0; dsp::decimate::FIRC16xR16x32Decim8 decim_1; - dsp::matched_filter::MatchedFilter mf { baseband::ais::rrc_taps_38k4_4t_p, 2 }; + dsp::matched_filter::MatchedFilter mf { baseband::ais::square_taps_38k4_1t_p, 2 }; clock_recovery::ClockRecovery clock_recovery { 19200, 9600, { 0.0555f }, diff --git a/firmware/common/ais_baseband.hpp b/firmware/common/ais_baseband.hpp index 1d7a2aa6..f8bbc0d8 100644 --- a/firmware/common/ais_baseband.hpp +++ b/firmware/common/ais_baseband.hpp @@ -32,21 +32,13 @@ namespace baseband { namespace ais { -// RRC length should be about 4 x the symbol length (4T) to do a good job of -// cleaning up ISI. - -// Translate+RRC filter -// sample=38.4k, deviation=2400, b=0.5, symbol=9600 -// Length: 16 taps, 4 symbols, 1 cycles of sinusoid -constexpr std::array, 16> rrc_taps_38k4_4t_p { { - { 1.0619794019e-02f, 0.0000000000e+00f }, { 3.5758705854e-03f, 1.4811740938e-03f }, - { -1.3274742629e-02f, -1.3274742629e-02f }, { -1.5018657262e-02f, -3.6258246051e-02f }, - { 0.0000000000e+00f, -2.6549484581e-02f }, { -1.5018657262e-02f, 3.6258246051e-02f }, - { -1.0237997393e-01f, 1.0237997393e-01f }, { -2.2527985355e-01f, 9.3313970669e-02f }, - { -2.8440842032e-01f, 0.0000000000e+00f }, { -2.2527985355e-01f, -9.3313970669e-02f }, - { -1.0237997393e-01f, -1.0237997393e-01f }, { -1.5018657262e-02f, -3.6258246051e-02f }, - { 0.0000000000e+00f, 2.6549484581e-02f }, { -1.5018657262e-02f, 3.6258246051e-02f }, - { -1.3274742629e-02f, 1.3274742629e-02f }, { 3.5758705854e-03f, -1.4811740938e-03f }, +// Translate+Rectangular window filter +// sample=38.4k, deviation=2400, symbol=9600 +// Length: 4 taps, 1 symbol, 1/4 cycle of sinusoid +// Gain: 1.0 (sinusoid / len(taps)) +constexpr std::array, 4> square_taps_38k4_1t_p { { + { 0.25000000f, 0.00000000f }, { 0.23096988f, 0.09567086f }, + { 0.17677670f, 0.17677670f }, { 0.09567086f, 0.23096988f }, } }; } /* namespace ais */ From 42a07bb10ce360b57ff3737fb6602fef77abaf94 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 30 Aug 2016 21:26:55 -0700 Subject: [PATCH 029/100] Remove repeated code in RF path Config. --- firmware/application/rf_path.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/application/rf_path.cpp b/firmware/application/rf_path.cpp index 4680ae4c..3f646954 100644 --- a/firmware/application/rf_path.cpp +++ b/firmware/application/rf_path.cpp @@ -92,9 +92,9 @@ struct Config { lp(band == Band::Low), amp_bypass(!amplify), tx_amp((direction == Direction::Transmit) && amplify), - not_tx_amp(!((direction == Direction::Transmit) && amplify)), + not_tx_amp(!tx_amp), rx_amp((direction == Direction::Receive) && amplify), - not_rx_amp(!((direction == Direction::Receive) && amplify)) + not_rx_amp(!rx_amp) { } From 337d5ebaea653579e7b7ea3f09f78ab295c08b99 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 30 Aug 2016 21:29:23 -0700 Subject: [PATCH 030/100] Add PortaPack-customized HackRF CPLD bitstream. --- firmware/CMakeLists.txt | 2 +- firmware/hackrf_cpld_portapack.svf | 1122 ++++++++++++++++++++++++++++ 2 files changed, 1123 insertions(+), 1 deletion(-) create mode 100755 firmware/hackrf_cpld_portapack.svf diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 9a7bb2d1..124c420e 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -27,7 +27,7 @@ set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack) set(HACKRF_FIRMWARE_FILENAME hackrf_one_usb_ram.dfu) set(HACKRF_FIRMWARE_IMAGE ${PROJECT_SOURCE_DIR}/${HACKRF_FIRMWARE_FILENAME}) -set(HACKRF_CPLD_SVF_FILENAME hackrf_cpld_default.svf) +set(HACKRF_CPLD_SVF_FILENAME hackrf_cpld_portapack.svf) set(HACKRF_CPLD_SVF_PATH ${PROJECT_SOURCE_DIR}/${HACKRF_CPLD_SVF_FILENAME}) set(EXTRACT_CPLD_DATA ${PROJECT_SOURCE_DIR}/tools/extract_cpld_data.py) diff --git a/firmware/hackrf_cpld_portapack.svf b/firmware/hackrf_cpld_portapack.svf new file mode 100755 index 00000000..424fb659 --- /dev/null +++ b/firmware/hackrf_cpld_portapack.svf @@ -0,0 +1,1122 @@ +// Created using Xilinx Cse Software [ISE - 14.7] +// Date: Tue Aug 23 23:01:43 2016 + +TRST OFF; +ENDIR IDLE; +ENDDR IDLE; +STATE RESET; +STATE IDLE; +FREQUENCY 1E6 HZ; +TIR 0 ; +HIR 0 ; +TDR 0 ; +HDR 0 ; +TIR 0 ; +HIR 0 ; +HDR 0 ; +TDR 0 ; +//Loading device with 'idcode' instruction. +SIR 8 TDI (01) SMASK (ff) ; +SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f6e5f093) MASK (0fff8fff) ; +//Check for Read/Write Protect. +SIR 8 TDI (ff) TDO (01) MASK (03) ; +//Boundary Scan Chain Contents +//Position 1: xc2c64a +TIR 0 ; +HIR 0 ; +TDR 0 ; +HDR 0 ; +TIR 0 ; +HIR 0 ; +TDR 0 ; +HDR 0 ; +TIR 0 ; +HIR 0 ; +HDR 0 ; +TDR 0 ; +//Loading device with 'idcode' instruction. +SIR 8 TDI (01) ; +SDR 32 TDI (00000000) TDO (f6e5f093) ; +//Check for Read/Write Protect. +SIR 8 TDI (ff) TDO (01) MASK (03) ; +//Loading device with 'bypass' instruction. +SIR 8 TDI (ff) ; +//Loading device with 'enable' instruction. +SIR 8 TDI (e8) ; +//Loading device with 'enable' instruction. +SIR 8 TDI (e8) ; +// Loading device with a 'erase' instruction. +ENDIR IRPAUSE; +SIR 8 TDI (ed) SMASK (ff) ; +ENDIR IDLE; +STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRPAUSE; +RUNTEST DRPAUSE 20 TCK; +STATE IDLE; +RUNTEST IDLE 100000 TCK; +STATE DRPAUSE; +RUNTEST DRPAUSE 5000 TCK; +ENDIR IRPAUSE; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IDLE; +RUNTEST IDLE 20 TCK; +ENDIR IRPAUSE; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRUPDATE IDLE; +RUNTEST 800 TCK; +ENDIR IDLE; +//Loading device with 'conld' instruction. +SIR 8 TDI (c0) ; +RUNTEST IDLE 100 TCK; +//Loading device with 'enable' instruction. +SIR 8 TDI (e8) ; +// Programming. +// Loading device with a 'program' instruction. +ENDIR IRPAUSE; +SIR 8 TDI (ea) ; +SDR 281 TDI (0003c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) SMASK (01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +ENDIR IDLE; +RUNTEST 10000 TCK; +SDR 281 TDI (0103f9ffffffffffffffffffffffffffffffff777fffffffffffffffffffffffffdffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0180f97fffffffffffffffffffffffbfffe9de7fffffffffffffffffeffffffffffbfe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0083c1fffffffffffffffffffffffffffbf99e7ffffffffffbffffffffffffffffffde0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00c3f9fffffffffffffffffffffffffffbf99e7fffffffffffffbfffffffffffffff7e7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01c0f93ffffffffffffffffffffffffffff99e7fffffefbefbffffffefbeffffeaab2a7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0143c1bffffffffffffffffffffdfffffffffeeefffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0043f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0060f9fffffffffffffffffffffbfffffff99e7fffffffffffffffffffffffffeaabfc7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0163c1fffffffffffffffffffffffffffbf99e7ffffffffeffffffffffffffffefffde4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01e3f9fffffffffffffffffffffffffffbf87e7fffffffbffffffffffffffffffeffde7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00e0f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00a3c1fffffffffffffffffffffffffefffbbefffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01a3f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0120f9fffffffffffffffffffffffffffffd7f7ffffffffffffffffffffefffffffffe83) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0023c1fffffffffffffffffffffffffffff5ff7fffffffffffffffffffffffffeaabf64f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0033f9fffffffffffffffffffffffffffbf87e7fffffeffffffffffffffffffffbffde7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0130f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01b3c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00b3f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00f0f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01f3c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffabfe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0173f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dfe1d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0070f9ffffffffffffffffffffffffffffffe607fffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0053c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff544f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0153f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff07ffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01d0f8bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffff03) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00d3c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0093f9fffffffffffffffffffffffffffffddf7fffffffffffffffffffbfffffffeffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0190f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0113c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0013f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0018f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) ; +RUNTEST 10000 TCK; +SDR 281 TDI (011bc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (019b99fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (009afdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00dbc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01db99fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (015af9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) ; +RUNTEST 10000 TCK; +SDR 281 TDI (005bc9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (007bd9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (017afdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01fbc9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00fbd9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00bafdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01bbc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (013b99fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (003afdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03) ; +RUNTEST 10000 TCK; +SDR 281 TDI (002bc8eabfffffffffffffeffffffffffffffefefbfffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0128feeabf7fffffeffffffffffffffffffffefefbfffffffffffffffffffffffffffe1d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01aa00eab7ffff7ffffffffffffffffffffffefefbfffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00abc1bff77ffffffffffffffffffffffffffeeefffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00ebf8ebffffffffffffffffffffffbffffffefeeffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01e8f9fffbfffffffffffffffffffffffffbbefffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (016bc9ffffbffffffffffffffffffffffffafefffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0068e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (004ac5fffffffffffffefffffffffffffffffeeefffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (014bc0fffffffffffffffffffffffffffbfffefeeffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01cbf9fffff7fffffffffffffffffffffffffeeefffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00c8f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (008bc8eaffffffffffffffffbffffffffffffefeeffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0188e0effffffffffffffffffffffffefffffefeeffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (010ac3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (000bc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (000ff9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (010cf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (018fc9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (008ce1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00cec5ffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01cfc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (014ee1ffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) ; +RUNTEST 10000 TCK; +SDR 281 TDI (004cf8bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) ; +RUNTEST 10000 TCK; +SDR 281 TDI (006fc9dfcefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (016ce1fffffffffffffffffffffffffffffff9fffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01eec3df7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00efc993fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00ace1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01aec5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (012fc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (002ee1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (003cf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (013fc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01bee1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00bcf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00ffc1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01fff9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (017cf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (007fc9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (005ce1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (015ec5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (01dfc9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (00dce1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (009ec5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (019fc9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (011ce1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) ; +RUNTEST 10000 TCK; +SDR 281 TDI (001ec5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 10000 TCK; +SDR 281 TDI (0117ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 10000 TCK; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IDLE; +RUNTEST IDLE 20 TCK; +ENDIR IRPAUSE; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRUPDATE IDLE; +RUNTEST 800 TCK; +ENDIR IDLE; +//Loading device with 'enable' instruction. +SIR 8 TDI (e8) ; +//Loading device with 'enable' instruction. +SIR 8 TDI (e8) ; +// Verification. +// Loading device with a 'verify' instruction. +ENDIR IRPAUSE; +SIR 8 TDI (ee) ; +ENDDR DRPAUSE; +SDR 7 TDI (00) SMASK (7f) ; +ENDIR IDLE; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (40) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9ffffffffffffffffffffffffffffffff777fffffffffffffffffffffffffdffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (60) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f97fffffffffffffffffffffffbfffe9de7fffffffffffffffffeffffffffffbfe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (20) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffbf99e7ffffffffffbffffffffffffffffffde0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (30) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffbf99e7fffffffffffffbfffffffffffffff7e7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (70) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f93ffffffffffffffffffffffffffff99e7fffffefbefbffffffefbeffffeaab2a7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (50) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1bffffffffffffffffffffdfffffffffeeefffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (10) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (18) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffbfffffff99e7fffffffffffffffffffffffffeaabfc7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (58) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffbf99e7ffffffffeffffffffffffffffefffde4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (78) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffbf87e7fffffffbffffffffffffffffffeffde7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (38) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (28) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffefffbbefffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (68) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (48) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffd7f7ffffffffffffffffffffefffffffffe83) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (08) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffff5ff7fffffffffffffffffffffffffeaabf64f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (0c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffbf87e7fffffeffffffffffffffffffffbffde7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (4c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (6c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (2c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (3c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (7c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffabfe0f) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (5c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dfe1d) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (1c) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9ffffffffffffffffffffffffffffffe607fffffffffffffffffffffffffffffe7c) MASK ( +03fffffffffffffffffffffffffffffe001ff801ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (14) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff544f) MASK ( +03fffffffffffffffffffffffffffffe001f8001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (54) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff07ffe7c) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (74) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f8bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffff03) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (34) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (24) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffddf7fffffffffffffffffffbfffffffeffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (64) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (44) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (04) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (06) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (46) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (66) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (0399fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (26) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02fdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (36) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (76) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (0399fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (56) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (16) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (1e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03d9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (5e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02fdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe83) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (7e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (3e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03d9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (2e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02fdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (6e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (4e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (0399fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (0e) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02fdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (0a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c8eabfffffffffffffeffffffffffffffefefbfffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (4a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00feeabf7fffffeffffffffffffffffffffefefbfffffffffffffffffffffffffffe1d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (6a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (0200eab7ffff7ffffffffffffffffffffffefefbfffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (2a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1bff77ffffffffffffffffffffffffffeeefffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (3a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f8ebffffffffffffffffffffffbffffffefeeffffffffffffffffffffffffffffe69) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (7a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffbfffffffffffffffffffffffffbbefffffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (5a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9ffffbffffffffffffffffffffffffafefffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (1a) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (12) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c5fffffffffffffefffffffffffffffffeeefffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (52) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c0fffffffffffffffffffffffffffbfffefeeffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (72) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffff7fffffffffffffffffffffffffeeefffffffffffffffffffffffffffffe69) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (32) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (22) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c8eaffffffffffffffffbffffffffffffefeeffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (62) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e0effffffffffffffffffffffffefffffefeeffffffffffffffffffffffffffffe69) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (42) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (02) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (03) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (43) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (63) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (23) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (33) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c5ffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (73) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4f) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (53) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02e1ffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe69) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (13) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f8bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7d) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (1b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9dfcefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (5b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffff9fffffffffffffffffffffffffffffffe7f) MASK ( +03fffffffffffffffffffffffffffffe00078001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (7b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c3df7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (3b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c993fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03fffffffffffffffffffffffffffffe00000001ffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (2b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (6b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (4b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (0b) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (0f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (4f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (6f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (2f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (3f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (7f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (5f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (1f) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (17) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (57) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (77) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (37) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (27) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (67) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03c9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (47) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (00e1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7f) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (07) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02c5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7c) MASK ( +03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (05) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) MASK ( +0000000000000000000000000000000000000000000000000000000000000000000000) ; +RUNTEST 100 TCK; +ENDDR DRPAUSE; +SDR 7 TDI (45) SMASK (7f) ; +RUNTEST DRPAUSE 20 TCK; +ENDDR IDLE; +RUNTEST IDLE 100 TCK; +// masking lower UES bits. +SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) MASK ( +0000000000000000000000000000000000000000000000000000000000000000000000) ; +RUNTEST 100 TCK; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IDLE; +RUNTEST IDLE 20 TCK; +ENDIR IRPAUSE; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRUPDATE IDLE; +RUNTEST 800 TCK; +ENDIR IDLE; +//Loading device with 'conld' instruction. +SIR 8 TDI (c0) ; +RUNTEST IDLE 100 TCK; +//Loading device with 'enable' instruction. +SIR 8 TDI (e8) ; +// Setting Done bit ... +// Loading device with a 'program' instruction. +ENDIR IRPAUSE; +SIR 8 TDI (ea) ; +SDR 281 TDI (0017fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; +ENDIR IDLE; +RUNTEST 10000 TCK; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IDLE; +RUNTEST IDLE 20 TCK; +ENDIR IRPAUSE; +SIR 8 TDI (f0) SMASK (ff) ; +STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRUPDATE IDLE; +RUNTEST 800 TCK; +ENDIR IDLE; +//Loading device with 'conld' instruction. +SIR 8 TDI (c0) ; +RUNTEST IDLE 100 TCK; +//Loading device with 'idcode' instruction. +SIR 8 TDI (01) ; +SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f6e5f093) MASK (0fff8fff) ; +//Check for Done bit. +SIR 8 TDI (ff) TDO (05) MASK (07) ; +//Loading device with 'bypass' instruction. +SIR 8 TDI (ff) ; +TIR 0 ; +HIR 0 ; +HDR 0 ; +TDR 0 ; +TIR 0 ; +HIR 0 ; +TDR 0 ; +HDR 0 ; +SIR 8 TDI (ff) ; +SDR 1 TDI (00) SMASK (01) ; From 00c7cdf027a0ec034a989bfe566102826f6bd428 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 30 Aug 2016 21:30:03 -0700 Subject: [PATCH 031/100] CPLD: Always clock SGPIO data on external clock rising edge. --- firmware/common/baseband_sgpio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/baseband_sgpio.cpp b/firmware/common/baseband_sgpio.cpp index 1cc0d143..8e9e972d 100644 --- a/firmware/common/baseband_sgpio.cpp +++ b/firmware/common/baseband_sgpio.cpp @@ -282,7 +282,7 @@ constexpr CLK_CAPTURE_MODE data_clk_capture_mode( ) { return (direction == Direction::Transmit) ? CLK_CAPTURE_MODE::RISING_CLOCK_EDGE - : CLK_CAPTURE_MODE::FALLING_CLOCK_EDGE + : CLK_CAPTURE_MODE::RISING_CLOCK_EDGE ; } From 5d2ad9c1aaf00019b8db3d64aaece7bbc0d354b1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 30 Aug 2016 21:33:44 -0700 Subject: [PATCH 032/100] SGPIO: Use pin constants when changing output enables. --- firmware/common/baseband_sgpio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/baseband_sgpio.cpp b/firmware/common/baseband_sgpio.cpp index 8e9e972d..2dc34cbe 100644 --- a/firmware/common/baseband_sgpio.cpp +++ b/firmware/common/baseband_sgpio.cpp @@ -184,7 +184,7 @@ constexpr Slice slice_order[] { }; constexpr uint32_t gpio_outreg(const Direction direction) { - return ((direction == Direction::Transmit) ? (1U << 11) : 0U) | (1U << 10); + return ((direction == Direction::Transmit) ? (1U << PIN_DIRECTION) : 0U) | (1U << PIN_DISABLE); } constexpr uint32_t gpio_oenreg(const Direction direction) { From 2396d2d97aa8a1c30c5408e0fe8178218588fa6e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 31 Aug 2016 11:23:42 -0700 Subject: [PATCH 033/100] CMake: Remove DFU --reset, which fails build if reset fails. dfu-util will often complain of reset not succeeding (which is apparently fine), then halting the programming phase (which is not fine). --- firmware/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 124c420e..2c338ce3 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -59,7 +59,7 @@ add_custom_target( add_custom_target( program - COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_IMAGE} --reset + COMMAND dfu-util --device 1fc9:000c --download ${HACKRF_FIRMWARE_IMAGE} COMMAND sleep 1s COMMAND hackrf_spiflash -w ${FIRMWARE_FILENAME} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${FIRMWARE_FILENAME} From 1e0d452f57c3761983665d1af292e09bb0109f81 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 2 Sep 2016 22:22:30 -0700 Subject: [PATCH 034/100] RecentEntriesView: Generalize draw_header() implementations. --- firmware/application/ais_app.cpp | 30 ++++--------------- firmware/application/ert_app.cpp | 34 ++++++---------------- firmware/application/recent_entries.hpp | 27 +++++++++++++++++- firmware/application/tpms_app.cpp | 38 +++++++------------------ 4 files changed, 50 insertions(+), 79 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 1b04bc18..3d7ad098 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -185,30 +185,6 @@ void AISRecentEntry::update(const ais::Packet& packet) { namespace ui { -static const std::array, 2> ais_columns { { - { "MMSI", 9 }, - { "Name/Call", 20 }, -} }; - -template<> -void RecentEntriesView::draw_header( - const Rect& target_rect, - Painter& painter, - const Style& style -) { - auto x = 0; - for(const auto& column : ais_columns) { - const auto width = column.second; - auto text = column.first; - if( width > text.length() ) { - text.append(width - text.length(), ' '); - } - - painter.draw_string({ x, target_rect.pos.y }, style, text); - x += (width * 8) + 8; - } -} - template<> void RecentEntriesView::draw( const Entry& entry, @@ -303,6 +279,12 @@ AISAppView::AISAppView(NavigationView&) { &recent_entry_detail_view, } }); + const std::array columns { { + { "MMSI", 9 }, + { "Name/Call", 20 }, + } }; + recent_entries_view.set_columns(columns); + recent_entry_detail_view.hidden(true); target_frequency_ = initial_target_frequency; diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 5bed3782..fac65320 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -75,32 +75,6 @@ void ERTRecentEntry::update(const ert::Packet& packet) { namespace ui { -static const std::array, 4> ert_columns { { - { "ID", 10 }, - { "Tp", 2 }, - { "Consumpt", 10 }, - { "Cnt", 3 }, -} }; - -template<> -void RecentEntriesView::draw_header( - const Rect& target_rect, - Painter& painter, - const Style& style -) { - auto x = 0; - for(const auto& column : ert_columns) { - const auto width = column.second; - auto text = column.first; - if( width > text.length() ) { - text.append(width - text.length(), ' '); - } - - painter.draw_string({ x, target_rect.pos.y }, style, text); - x += (width * 8) + 8; - } -} - template<> void RecentEntriesView::draw( const Entry& entry, @@ -134,6 +108,14 @@ ERTAppView::ERTAppView(NavigationView&) { &recent_entries_view, } }); + const std::array columns { { + { "ID", 10 }, + { "Tp", 2 }, + { "Consumpt", 10 }, + { "Cnt", 3 }, + } }; + recent_entries_view.set_columns(columns); + radio::enable({ initial_target_frequency, sampling_rate, diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 84afb868..30bf4a8d 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -118,6 +118,8 @@ private: namespace ui { +using RecentEntriesColumn = std::pair; + template class RecentEntriesView : public View { public: @@ -132,6 +134,16 @@ public: set_focusable(true); } + template + void set_columns( + const std::array& columns + ) { + _columns.clear(); + for(const auto& column : columns) { + _columns.emplace_back(column); + } + } + void paint(Painter& painter) override { const auto r = screen_rect(); const auto& s = style(); @@ -192,6 +204,7 @@ public: private: Entries& recent; + std::vector> _columns; using EntryKey = typename Entry::Key; EntryKey selected_key = Entry::invalid_key; @@ -226,7 +239,19 @@ private: const Rect& target_rect, Painter& painter, const Style& style - ); + ) { + auto x = 0; + for(const auto& column : _columns) { + const auto width = column.second; + auto text = column.first; + if( width > text.length() ) { + text.append(width - text.length(), ' '); + } + + painter.draw_string({ x, target_rect.pos.y }, style, text); + x += (width * 8) + 8; + } + } void draw( const Entry& entry, diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 2a13e2f2..25ad2420 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -95,34 +95,6 @@ void TPMSRecentEntry::update(const tpms::Reading& reading) { namespace ui { -static const std::array, 6> tpms_columns { { - { "Tp", 2 }, - { "ID", 8 }, - { "kPa", 3 }, - { "C", 3 }, - { "Cnt", 3 }, - { "Fl", 2 }, -} }; - -template<> -void RecentEntriesView::draw_header( - const Rect& target_rect, - Painter& painter, - const Style& style -) { - auto x = 0; - for(const auto& column : tpms_columns) { - const auto width = column.second; - auto text = column.first; - if( width > text.length() ) { - text.append(width - text.length(), ' '); - } - - painter.draw_string({ x, target_rect.pos.y }, style, text); - x += (width * 8) + 8; - } -} - template<> void RecentEntriesView::draw( const Entry& entry, @@ -176,6 +148,16 @@ TPMSAppView::TPMSAppView(NavigationView&) { &recent_entries_view, } }); + const std::array columns { { + { "Tp", 2 }, + { "ID", 8 }, + { "kPa", 3 }, + { "C", 3 }, + { "Cnt", 3 }, + { "Fl", 2 }, + } }; + recent_entries_view.set_columns(columns); + radio::enable({ tuning_frequency(), sampling_rate, From c6f7d7f844f63fce33bd419d292d45ab8d803c86 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 2 Sep 2016 22:44:40 -0700 Subject: [PATCH 035/100] RecentEntriesView: Extract duplicate focus+selection style code. --- firmware/application/ais_app.cpp | 7 ++----- firmware/application/ert_app.cpp | 7 ++----- firmware/application/recent_entries.hpp | 6 +++--- firmware/application/tpms_app.cpp | 7 ++----- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 3d7ad098..cb9e1ef8 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -190,11 +190,8 @@ void RecentEntriesView::draw( const Entry& entry, const Rect& target_rect, Painter& painter, - const Style& style, - const bool is_selected + const Style& style ) { - const auto& draw_style = is_selected ? style.invert() : style; - std::string line = ais::format::mmsi(entry.mmsi) + " "; if( !entry.name.empty() ) { line += entry.name; @@ -203,7 +200,7 @@ void RecentEntriesView::draw( } line.resize(target_rect.width() / 8, ' '); - painter.draw_string(target_rect.pos, draw_style, line); + painter.draw_string(target_rect.pos, style, line); } AISRecentEntryDetailView::AISRecentEntryDetailView() { diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index fac65320..d02133c8 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -80,11 +80,8 @@ void RecentEntriesView::draw( const Entry& entry, const Rect& target_rect, Painter& painter, - const Style& style, - const bool is_selected + const Style& style ) { - const auto& draw_style = is_selected ? style.invert() : style; - std::string line = ert::format::id(entry.id) + " " + ert::format::commodity_type(entry.commodity_type) + " " + ert::format::consumption(entry.last_consumption); if( entry.received_count > 999 ) { @@ -94,7 +91,7 @@ void RecentEntriesView::draw( } line.resize(target_rect.width() / 8, ' '); - painter.draw_string(target_rect.pos, draw_style, line); + painter.draw_string(target_rect.pos, style, line); } ERTAppView::ERTAppView(NavigationView&) { diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 30bf4a8d..c0118f77 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -170,7 +170,8 @@ public: for(auto p = range.first; p != range.second; p++) { const auto& entry = *p; const auto is_selected_key = (selected_key == entry.key()); - draw(entry, target_rect, painter, s, (has_focus() && is_selected_key)); + const auto item_style = (has_focus() && is_selected_key) ? s.invert() : s; + draw(entry, target_rect, painter, item_style); target_rect.pos.y += target_rect.height(); } @@ -257,8 +258,7 @@ private: const Entry& entry, const Rect& target_rect, Painter& painter, - const Style& style, - const bool is_selected + const Style& style ); }; diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 25ad2420..9da4fce6 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -100,11 +100,8 @@ void RecentEntriesView::draw( const Entry& entry, const Rect& target_rect, Painter& painter, - const Style& style, - const bool is_selected + const Style& style ) { - const auto& draw_style = is_selected ? style.invert() : style; - std::string line = tpms::format::type(entry.type) + " " + tpms::format::id(entry.id); if( entry.last_pressure.is_valid() ) { @@ -132,7 +129,7 @@ void RecentEntriesView::draw( } line.resize(target_rect.width() / 8, ' '); - painter.draw_string(target_rect.pos, draw_style, line); + painter.draw_string(target_rect.pos, style, line); } TPMSAppView::TPMSAppView(NavigationView&) { From 4d781df76c2c3f95de093d405b658ff2cbcda667 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 3 Sep 2016 12:58:11 -0700 Subject: [PATCH 036/100] RecentEntries: Don't reference Entry template arg directly. --- firmware/application/recent_entries.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index c0118f77..0f899ed0 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -37,13 +37,13 @@ template class RecentEntries { public: using EntryType = Entry; - using Key = typename Entry::Key; - using ContainerType = std::list; + using Key = typename EntryType::Key; + using ContainerType = std::list; using const_reference = typename ContainerType::const_reference; using const_iterator = typename ContainerType::const_iterator; using RangeType = std::pair; - const Entry& on_packet(const Key key, const Packet& packet) { + const EntryType& on_packet(const Key key, const Packet& packet) { auto matching_recent = find(key); if( matching_recent != std::end(entries) ) { // Found within. Move to front of list, increment counter. @@ -67,7 +67,7 @@ public: const_iterator find(const Key key) const { return std::find_if( std::begin(entries), std::end(entries), - [key](const Entry& e) { return e.key() == key; } + [key](const EntryType& e) { return e.key() == key; } ); } From 42d98c3b4595e17032c9a19656a639a60e6fa8ac Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 3 Sep 2016 16:38:44 -0700 Subject: [PATCH 037/100] RecentEntries: Remove Packet template arg. --- firmware/application/ais_app.cpp | 7 ++++--- firmware/application/ais_app.hpp | 2 +- firmware/application/ert_app.cpp | 3 ++- firmware/application/ert_app.hpp | 2 +- firmware/application/recent_entries.hpp | 9 +++------ firmware/application/tpms_app.cpp | 3 ++- firmware/application/tpms_app.hpp | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index cb9e1ef8..049acf71 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -336,12 +336,13 @@ void AISAppView::on_packet(const ais::Packet& packet) { logger->on_packet(packet); } - const auto updated_entry = recent.on_packet(packet.source_id(), packet); + auto& entry = recent.on_packet(packet.source_id()); + entry.update(packet); recent_entries_view.set_dirty(); // TODO: Crude hack, should be a more formal listener arrangement... - if( updated_entry.key() == recent_entry_detail_view.entry().key() ) { - recent_entry_detail_view.set_entry(updated_entry); + if( entry.key() == recent_entry_detail_view.entry().key() ) { + recent_entry_detail_view.set_entry(entry); } } diff --git a/firmware/application/ais_app.hpp b/firmware/application/ais_app.hpp index 10da06a2..556002e1 100644 --- a/firmware/application/ais_app.hpp +++ b/firmware/application/ais_app.hpp @@ -91,7 +91,7 @@ struct AISRecentEntry { void update(const ais::Packet& packet); }; -using AISRecentEntries = RecentEntries; +using AISRecentEntries = RecentEntries; class AISLogger { public: diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index d02133c8..fcfc9b1e 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -150,7 +150,8 @@ void ERTAppView::on_packet(const ert::Packet& packet) { } if( packet.crc_ok() ) { - recent.on_packet({ packet.id(), packet.commodity_type() }, packet); + auto& entry = recent.on_packet({ packet.id(), packet.commodity_type() }); + entry.update(packet); recent_entries_view.set_dirty(); } } diff --git a/firmware/application/ert_app.hpp b/firmware/application/ert_app.hpp index cba9e74a..49c7701e 100644 --- a/firmware/application/ert_app.hpp +++ b/firmware/application/ert_app.hpp @@ -100,7 +100,7 @@ private: LogFile log_file; }; -using ERTRecentEntries = RecentEntries; +using ERTRecentEntries = RecentEntries; namespace ui { diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 0f899ed0..9c23bde6 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -33,7 +33,7 @@ #include #include -template +template class RecentEntries { public: using EntryType = Entry; @@ -43,7 +43,7 @@ public: using const_iterator = typename ContainerType::const_iterator; using RangeType = std::pair; - const EntryType& on_packet(const Key key, const Packet& packet) { + EntryType& on_packet(const Key key) { auto matching_recent = find(key); if( matching_recent != std::end(entries) ) { // Found within. Move to front of list, increment counter. @@ -54,10 +54,7 @@ public: truncate_entries(); } - auto& entry = entries.front(); - entry.update(packet); - - return entry; + return entries.front(); } const_reference front() const { diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 9da4fce6..a00ff16f 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -199,7 +199,8 @@ void TPMSAppView::on_packet(const tpms::Packet& packet) { const auto reading_opt = packet.reading(); if( reading_opt.is_valid() ) { const auto reading = reading_opt.value(); - recent.on_packet({ reading.type(), reading.id() }, reading); + auto& entry = recent.on_packet({ reading.type(), reading.id() }); + entry.update(reading); recent_entries_view.set_dirty(); } } diff --git a/firmware/application/tpms_app.hpp b/firmware/application/tpms_app.hpp index 98715219..c294862e 100644 --- a/firmware/application/tpms_app.hpp +++ b/firmware/application/tpms_app.hpp @@ -72,7 +72,7 @@ struct TPMSRecentEntry { void update(const tpms::Reading& reading); }; -using TPMSRecentEntries = RecentEntries; +using TPMSRecentEntries = RecentEntries; class TPMSLogger { public: From b596d0697c1bc188f50162ad5206427cc302c5f7 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 3 Sep 2016 17:09:03 -0700 Subject: [PATCH 038/100] RecentEntries: Extract range_around(). --- firmware/application/recent_entries.hpp | 50 +++++++++++++------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 9c23bde6..d276dc84 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -41,7 +41,6 @@ public: using ContainerType = std::list; using const_reference = typename ContainerType::const_reference; using const_iterator = typename ContainerType::const_iterator; - using RangeType = std::pair; EntryType& on_packet(const Key key) { auto matching_recent = find(key); @@ -80,28 +79,6 @@ public: return entries.empty(); } - RangeType range_around( - const_iterator item, const size_t count - ) const { - auto start = item; - auto end = item; - size_t i = 0; - - // Move start iterator toward first entry. - while( (start != std::begin(entries)) && (i < count / 2) ) { - std::advance(start, -1); - i++; - } - - // Move end iterator toward last entry. - while( (end != std::end(entries)) && (i < count) ) { - std::advance(end, 1); - i++; - } - - return { start, end }; - } - private: ContainerType entries; const size_t entries_max = 64; @@ -113,6 +90,31 @@ private: } }; +template +static std::pair range_around( + const ContainerType& entries, + typename ContainerType::const_iterator item, + const size_t count +) { + auto start = item; + auto end = item; + size_t i = 0; + + // Move start iterator toward first entry. + while( (start != std::begin(entries)) && (i < count / 2) ) { + std::advance(start, -1); + i++; + } + + // Move end iterator toward last entry. + while( (end != std::end(entries)) && (i < count) ) { + std::advance(end, 1); + i++; + } + + return { start, end }; +} + namespace ui { using RecentEntriesColumn = std::pair; @@ -162,7 +164,7 @@ public: selected = std::begin(recent); } - auto range = recent.range_around(selected, visible_item_count); + auto range = range_around(recent, selected, visible_item_count); for(auto p = range.first; p != range.second; p++) { const auto& entry = *p; From c8f7863c8394c39c9322cc9b25370aaf007d4cf1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 3 Sep 2016 18:12:07 -0700 Subject: [PATCH 039/100] RecentEntries: Expose container as base class. Trying to refactor until there's nothing but the base class left. --- firmware/application/recent_entries.hpp | 35 +++++++------------------ 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index d276dc84..a06038e0 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -34,7 +34,7 @@ #include template -class RecentEntries { +class RecentEntries : public std::list { public: using EntryType = Entry; using Key = typename EntryType::Key; @@ -44,48 +44,31 @@ public: EntryType& on_packet(const Key key) { auto matching_recent = find(key); - if( matching_recent != std::end(entries) ) { + if( matching_recent != std::end(*this) ) { // Found within. Move to front of list, increment counter. - entries.push_front(*matching_recent); - entries.erase(matching_recent); + this->push_front(*matching_recent); + this->erase(matching_recent); } else { - entries.emplace_front(key); + this->emplace_front(key); truncate_entries(); } - return entries.front(); - } - - const_reference front() const { - return entries.front(); + return this->front(); } const_iterator find(const Key key) const { return std::find_if( - std::begin(entries), std::end(entries), + std::begin(*this), std::end(*this), [key](const EntryType& e) { return e.key() == key; } ); } - const_iterator begin() const { - return entries.begin(); - } - - const_iterator end() const { - return entries.end(); - } - - bool empty() const { - return entries.empty(); - } - private: - ContainerType entries; const size_t entries_max = 64; void truncate_entries() { - while(entries.size() > entries_max) { - entries.pop_back(); + while(this->size() > entries_max) { + this->pop_back(); } } }; From bd785d8bf4dbf2099029fa72cbaa04aa6e19b67b Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 3 Sep 2016 18:26:48 -0700 Subject: [PATCH 040/100] RecentEntries: Extract more algorithms. --- firmware/application/ais_app.cpp | 2 +- firmware/application/ert_app.cpp | 2 +- firmware/application/recent_entries.hpp | 66 ++++++++++++------------- firmware/application/tpms_app.cpp | 2 +- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 049acf71..5c50dbac 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -336,7 +336,7 @@ void AISAppView::on_packet(const ais::Packet& packet) { logger->on_packet(packet); } - auto& entry = recent.on_packet(packet.source_id()); + auto& entry = ::on_packet(recent, packet.source_id()); entry.update(packet); recent_entries_view.set_dirty(); diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index fcfc9b1e..8c1b305f 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -150,7 +150,7 @@ void ERTAppView::on_packet(const ert::Packet& packet) { } if( packet.crc_ok() ) { - auto& entry = recent.on_packet({ packet.id(), packet.commodity_type() }); + auto& entry = ::on_packet(recent, ERTRecentEntry::Key { packet.id(), packet.commodity_type() }); entry.update(packet); recent_entries_view.set_dirty(); } diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index a06038e0..22576588 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -41,38 +41,38 @@ public: using ContainerType = std::list; using const_reference = typename ContainerType::const_reference; using const_iterator = typename ContainerType::const_iterator; - - EntryType& on_packet(const Key key) { - auto matching_recent = find(key); - if( matching_recent != std::end(*this) ) { - // Found within. Move to front of list, increment counter. - this->push_front(*matching_recent); - this->erase(matching_recent); - } else { - this->emplace_front(key); - truncate_entries(); - } - - return this->front(); - } - - const_iterator find(const Key key) const { - return std::find_if( - std::begin(*this), std::end(*this), - [key](const EntryType& e) { return e.key() == key; } - ); - } - -private: - const size_t entries_max = 64; - - void truncate_entries() { - while(this->size() > entries_max) { - this->pop_back(); - } - } }; +template +typename ContainerType::const_iterator find(const ContainerType& entries, const Key key) { + return std::find_if( + std::begin(entries), std::end(entries), + [key](typename ContainerType::const_reference e) { return e.key() == key; } + ); +} + +template +static void truncate_entries(ContainerType& entries, const size_t entries_max = 64) { + while(entries.size() > entries_max) { + entries.pop_back(); + } +} + +template +typename ContainerType::reference on_packet(ContainerType& entries, const Key key) { + auto matching_recent = find(entries, key); + if( matching_recent != std::end(entries) ) { + // Found within. Move to front of list, increment counter. + entries.push_front(*matching_recent); + entries.erase(matching_recent); + } else { + entries.emplace_front(key); + truncate_entries(entries); + } + + return entries.front(); +} + template static std::pair range_around( const ContainerType& entries, @@ -142,7 +142,7 @@ public: draw_header(target_rect, painter, style_header); target_rect.pos.y += target_rect.height(); - auto selected = recent.find(selected_key); + auto selected = find(recent, selected_key); if( selected == std::end(recent) ) { selected = std::begin(recent); } @@ -171,7 +171,7 @@ public: bool on_key(const ui::KeyEvent event) override { if( event == ui::KeyEvent::Select ) { if( on_select ) { - const auto selected = recent.find(selected_key); + const auto selected = find(recent, selected_key); if( selected != std::end(recent) ) { on_select(*selected); return true; @@ -193,7 +193,7 @@ private: EntryKey selected_key = Entry::invalid_key; void advance(const int32_t amount) { - auto selected = recent.find(selected_key); + auto selected = find(recent, selected_key); if( selected == std::end(recent) ) { if( recent.empty() ) { selected_key = Entry::invalid_key; diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index a00ff16f..c435bce1 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -199,7 +199,7 @@ void TPMSAppView::on_packet(const tpms::Packet& packet) { const auto reading_opt = packet.reading(); if( reading_opt.is_valid() ) { const auto reading = reading_opt.value(); - auto& entry = recent.on_packet({ reading.type(), reading.id() }); + auto& entry = ::on_packet(recent, TPMSRecentEntry::Key { reading.type(), reading.id() }); entry.update(reading); recent_entries_view.set_dirty(); } From 50e2dfa0b9c87fb70c9036f8a5cbd84a83021172 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 3 Sep 2016 22:53:44 -0700 Subject: [PATCH 041/100] RecentEntries: Make templated type of std::list. --- firmware/application/recent_entries.hpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 22576588..795bf602 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -34,14 +34,7 @@ #include template -class RecentEntries : public std::list { -public: - using EntryType = Entry; - using Key = typename EntryType::Key; - using ContainerType = std::list; - using const_reference = typename ContainerType::const_reference; - using const_iterator = typename ContainerType::const_iterator; -}; +using RecentEntries = std::list; template typename ContainerType::const_iterator find(const ContainerType& entries, const Key key) { @@ -105,7 +98,7 @@ using RecentEntriesColumn = std::pair; template class RecentEntriesView : public View { public: - using Entry = typename Entries::EntryType; + using Entry = typename Entries::value_type; std::function on_select; From 61f0d97c39f22a5ac2f73f0efec8009320945bbd Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 12:09:29 -0700 Subject: [PATCH 042/100] RecentEntriesView: Extract header and table widget, package in to top-level View. --- firmware/application/ais_app.cpp | 2 +- firmware/application/ert_app.cpp | 2 +- firmware/application/recent_entries.hpp | 134 +++++++++++++++++------- firmware/application/tpms_app.cpp | 2 +- 4 files changed, 97 insertions(+), 43 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 5c50dbac..2db3f7df 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -186,7 +186,7 @@ void AISRecentEntry::update(const ais::Packet& packet) { namespace ui { template<> -void RecentEntriesView::draw( +void RecentEntriesTable::draw( const Entry& entry, const Rect& target_rect, Painter& painter, diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 8c1b305f..108c7937 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -76,7 +76,7 @@ void ERTRecentEntry::update(const ert::Packet& packet) { namespace ui { template<> -void RecentEntriesView::draw( +void RecentEntriesTable::draw( const Entry& entry, const Rect& target_rect, Painter& painter, diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 795bf602..fc2c08ca 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -95,19 +95,8 @@ namespace ui { using RecentEntriesColumn = std::pair; -template -class RecentEntriesView : public View { +class RecentEntriesHeader : public Widget { public: - using Entry = typename Entries::value_type; - - std::function on_select; - - RecentEntriesView( - Entries& recent - ) : recent { recent } - { - set_focusable(true); - } template void set_columns( @@ -119,6 +108,47 @@ public: } } + void paint(Painter& painter) override { + const auto r = screen_rect(); + const auto& parent_style = style(); + + const Style style { + .font = parent_style.font, + .background = Color::blue(), + .foreground = parent_style.foreground, + }; + + auto p = r.pos; + for(const auto& column : _columns) { + const auto width = column.second; + auto text = column.first; + if( width > text.length() ) { + text.append(width - text.length(), ' '); + } + + painter.draw_string(p, style, text); + p += { static_cast((width * 8) + 8), 0 }; + } + } + +private: + std::vector _columns; +}; + +template +class RecentEntriesTable : public Widget { +public: + using Entry = typename Entries::value_type; + + std::function on_select; + + RecentEntriesTable( + Entries& recent + ) : recent { recent } + { + set_focusable(true); + } + void paint(Painter& painter) override { const auto r = screen_rect(); const auto& s = style(); @@ -126,15 +156,6 @@ public: Rect target_rect { r.pos, { r.width(), s.font.line_height() }}; const size_t visible_item_count = r.height() / s.font.line_height(); - const Style style_header { - .font = font::fixed_8x16, - .background = Color::blue(), - .foreground = Color::white(), - }; - - draw_header(target_rect, painter, style_header); - target_rect.pos.y += target_rect.height(); - auto selected = find(recent, selected_key); if( selected == std::end(recent) ) { selected = std::begin(recent); @@ -180,7 +201,6 @@ public: private: Entries& recent; - std::vector> _columns; using EntryKey = typename Entry::Key; EntryKey selected_key = Entry::invalid_key; @@ -211,24 +231,6 @@ private: set_dirty(); } - void draw_header( - const Rect& target_rect, - Painter& painter, - const Style& style - ) { - auto x = 0; - for(const auto& column : _columns) { - const auto width = column.second; - auto text = column.first; - if( width > text.length() ) { - text.append(width - text.length(), ' '); - } - - painter.draw_string({ x, target_rect.pos.y }, style, text); - x += (width * 8) + 8; - } - } - void draw( const Entry& entry, const Rect& target_rect, @@ -237,6 +239,58 @@ private: ); }; +template +class RecentEntriesView : public View { +public: + using Entry = typename Entries::value_type; + + std::function on_select; + + RecentEntriesView( + Entries& recent + ) : _table { recent } + { + add_children({ { + &_header, + &_table, + } }); + + _table.on_select = [this](const Entry& entry) { if( this->on_select ) { this->on_select(entry); } }; + } + + template + void set_columns( + const std::array& columns + ) { + _header.set_columns(columns); + } + + void set_parent_rect(const Rect new_parent_rect) override { + constexpr Dim scale_height = 16; + + View::set_parent_rect(new_parent_rect); + _header.set_parent_rect({ 0, 0, new_parent_rect.width(), scale_height }); + _table.set_parent_rect({ + 0, scale_height, + new_parent_rect.width(), + new_parent_rect.height() - scale_height + }); + } + + void paint(Painter&) override { + // Children completely cover this View, do not paint. + // TODO: What happens here shouldn't matter if I do proper damage detection! + } + + void on_focus() override { + _table.focus(); + } + +private: + RecentEntriesHeader _header; + RecentEntriesTable _table; +}; + } /* namespace ui */ #endif/*__RECENT_ENTRIES_H__*/ diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index c435bce1..e7f38e37 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -96,7 +96,7 @@ void TPMSRecentEntry::update(const tpms::Reading& reading) { namespace ui { template<> -void RecentEntriesView::draw( +void RecentEntriesTable::draw( const Entry& entry, const Rect& target_rect, Painter& painter, From 298324d6e47c31fd01b5d5fc9193064ab891867b Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 12:34:41 -0700 Subject: [PATCH 043/100] RecentEntries: Extract Columns model. --- firmware/application/ais_app.cpp | 6 ---- firmware/application/ais_app.hpp | 6 +++- firmware/application/ert_app.cpp | 8 ----- firmware/application/ert_app.hpp | 8 ++++- firmware/application/recent_entries.hpp | 43 ++++++++++++++----------- firmware/application/tpms_app.cpp | 10 ------ firmware/application/tpms_app.hpp | 10 +++++- 7 files changed, 46 insertions(+), 45 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 2db3f7df..c79f3050 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -276,12 +276,6 @@ AISAppView::AISAppView(NavigationView&) { &recent_entry_detail_view, } }); - const std::array columns { { - { "MMSI", 9 }, - { "Name/Call", 20 }, - } }; - recent_entries_view.set_columns(columns); - recent_entry_detail_view.hidden(true); target_frequency_ = initial_target_frequency; diff --git a/firmware/application/ais_app.hpp b/firmware/application/ais_app.hpp index 556002e1..2e26d2ab 100644 --- a/firmware/application/ais_app.hpp +++ b/firmware/application/ais_app.hpp @@ -161,7 +161,11 @@ private: AISRecentEntries recent; std::unique_ptr logger; - AISRecentEntriesView recent_entries_view { recent }; + const RecentEntriesColumns columns { { + { "MMSI", 9 }, + { "Name/Call", 20 }, + } }; + AISRecentEntriesView recent_entries_view { columns, recent }; AISRecentEntryDetailView recent_entry_detail_view; static constexpr auto header_height = 1 * 16; diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 108c7937..d8d20fa4 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -105,14 +105,6 @@ ERTAppView::ERTAppView(NavigationView&) { &recent_entries_view, } }); - const std::array columns { { - { "ID", 10 }, - { "Tp", 2 }, - { "Consumpt", 10 }, - { "Cnt", 3 }, - } }; - recent_entries_view.set_columns(columns); - radio::enable({ initial_target_frequency, sampling_rate, diff --git a/firmware/application/ert_app.hpp b/firmware/application/ert_app.hpp index 49c7701e..6a774ede 100644 --- a/firmware/application/ert_app.hpp +++ b/firmware/application/ert_app.hpp @@ -129,7 +129,13 @@ private: ERTRecentEntries recent; std::unique_ptr logger; - ERTRecentEntriesView recent_entries_view { recent }; + const RecentEntriesColumns columns { { + { "ID", 10 }, + { "Tp", 2 }, + { "Consumpt", 10 }, + { "Cnt", 3 }, + } }; + ERTRecentEntriesView recent_entries_view { columns, recent }; static constexpr auto header_height = 1 * 16; diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index fc2c08ca..5bfa3e12 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -95,17 +95,29 @@ namespace ui { using RecentEntriesColumn = std::pair; +class RecentEntriesColumns { +public: + using ContainerType = std::vector; + + RecentEntriesColumns( + const std::initializer_list columns + ) : _columns { columns } + { + } + + ContainerType::const_iterator begin() const { return std::begin(_columns); } + ContainerType::const_iterator end() const { return std::end(_columns); } + +private: + const ContainerType _columns; +}; + class RecentEntriesHeader : public Widget { public: - - template - void set_columns( - const std::array& columns - ) { - _columns.clear(); - for(const auto& column : columns) { - _columns.emplace_back(column); - } + RecentEntriesHeader( + const RecentEntriesColumns& columns + ) : _columns { columns } + { } void paint(Painter& painter) override { @@ -132,7 +144,7 @@ public: } private: - std::vector _columns; + const RecentEntriesColumns& _columns; }; template @@ -247,8 +259,10 @@ public: std::function on_select; RecentEntriesView( + const RecentEntriesColumns& columns, Entries& recent - ) : _table { recent } + ) : _header { columns }, + _table { recent } { add_children({ { &_header, @@ -258,13 +272,6 @@ public: _table.on_select = [this](const Entry& entry) { if( this->on_select ) { this->on_select(entry); } }; } - template - void set_columns( - const std::array& columns - ) { - _header.set_columns(columns); - } - void set_parent_rect(const Rect new_parent_rect) override { constexpr Dim scale_height = 16; diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index e7f38e37..989e98d9 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -145,16 +145,6 @@ TPMSAppView::TPMSAppView(NavigationView&) { &recent_entries_view, } }); - const std::array columns { { - { "Tp", 2 }, - { "ID", 8 }, - { "kPa", 3 }, - { "C", 3 }, - { "Cnt", 3 }, - { "Fl", 2 }, - } }; - recent_entries_view.set_columns(columns); - radio::enable({ tuning_frequency(), sampling_rate, diff --git a/firmware/application/tpms_app.hpp b/firmware/application/tpms_app.hpp index c294862e..771efd7f 100644 --- a/firmware/application/tpms_app.hpp +++ b/firmware/application/tpms_app.hpp @@ -153,7 +153,15 @@ private: TPMSRecentEntries recent; std::unique_ptr logger; - TPMSRecentEntriesView recent_entries_view { recent }; + const RecentEntriesColumns columns { { + { "Tp", 2 }, + { "ID", 8 }, + { "kPa", 3 }, + { "C", 3 }, + { "Cnt", 3 }, + { "Fl", 2 }, + } }; + TPMSRecentEntriesView recent_entries_view { columns, recent }; uint32_t target_frequency_ = initial_target_frequency; From 8a69b0523e2123491cfa5fd40de125e34bf1a78d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 14:53:04 -0700 Subject: [PATCH 044/100] View::add_children: Use std::list_initializer as argument. Improvement in code size -- 944 bytes. Some day I will understand C++11 well enough to do the right thing the first time. --- firmware/application/ais_app.cpp | 8 ++++---- firmware/application/analog_audio_app.cpp | 12 ++++++------ firmware/application/capture_app.cpp | 4 ++-- firmware/application/ert_app.cpp | 4 ++-- firmware/application/recent_entries.hpp | 4 ++-- firmware/application/tpms_app.cpp | 4 ++-- firmware/application/ui_baseband_stats_view.cpp | 4 ++-- firmware/application/ui_debug.cpp | 12 ++++++------ firmware/application/ui_navigation.cpp | 16 ++++++++-------- firmware/application/ui_receiver.cpp | 8 ++++---- firmware/application/ui_record_view.cpp | 4 ++-- firmware/application/ui_sd_card_debug.cpp | 4 ++-- firmware/application/ui_setup.cpp | 16 ++++++++-------- firmware/application/ui_touch_calibration.cpp | 4 ++-- firmware/common/ui_widget.cpp | 6 ++++-- firmware/common/ui_widget.hpp | 2 +- 16 files changed, 57 insertions(+), 55 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index c79f3050..8a53da71 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -204,9 +204,9 @@ void RecentEntriesTable::draw( } AISRecentEntryDetailView::AISRecentEntryDetailView() { - add_children({ { + add_children({ &button_done, - } }); + }); button_done.on_select = [this](const ui::Button&) { if( this->on_close ) { @@ -264,7 +264,7 @@ void AISRecentEntryDetailView::set_entry(const AISRecentEntry& entry) { AISAppView::AISAppView(NavigationView&) { baseband::run_image(portapack::spi_flash::image_tag_ais); - add_children({ { + add_children({ &label_channel, &options_channel, &field_rf_amp, @@ -274,7 +274,7 @@ AISAppView::AISAppView(NavigationView&) { &channel, &recent_entries_view, &recent_entry_detail_view, - } }); + }); recent_entry_detail_view.hidden(true); diff --git a/firmware/application/analog_audio_app.cpp b/firmware/application/analog_audio_app.cpp index 417d1ea1..0a6009ca 100644 --- a/firmware/application/analog_audio_app.cpp +++ b/firmware/application/analog_audio_app.cpp @@ -44,10 +44,10 @@ AMOptionsView::AMOptionsView( { set_style(style); - add_children({ { + add_children({ &label_config, &options_config, - } }); + }); options_config.set_selected_index(receiver_model.am_configuration()); options_config.on_change = [this](size_t n, OptionsField::value_t) { @@ -63,10 +63,10 @@ NBFMOptionsView::NBFMOptionsView( { set_style(style); - add_children({ { + add_children({ &label_config, &options_config, - } }); + }); options_config.set_selected_index(receiver_model.nbfm_configuration()); options_config.on_change = [this](size_t n, OptionsField::value_t) { @@ -79,7 +79,7 @@ NBFMOptionsView::NBFMOptionsView( AnalogAudioView::AnalogAudioView( NavigationView& nav ) { - add_children({ { + add_children({ &rssi, &channel, &audio, @@ -90,7 +90,7 @@ AnalogAudioView::AnalogAudioView( &field_volume, &record_view, &waterfall, - } }); + }); field_frequency.set_value(receiver_model.tuning_frequency()); field_frequency.set_step(receiver_model.frequency_step()); diff --git a/firmware/application/capture_app.cpp b/firmware/application/capture_app.cpp index 6ebcd02f..cd2a3824 100644 --- a/firmware/application/capture_app.cpp +++ b/firmware/application/capture_app.cpp @@ -34,7 +34,7 @@ namespace ui { CaptureAppView::CaptureAppView(NavigationView& nav) { baseband::run_image(portapack::spi_flash::image_tag_capture); - add_children({ { + add_children({ &rssi, &channel, &field_frequency, @@ -44,7 +44,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav) { &field_vga, &record_view, &waterfall, - } }); + }); field_frequency.set_value(target_frequency()); field_frequency.set_step(receiver_model.frequency_step()); diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index d8d20fa4..5df0f336 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -97,13 +97,13 @@ void RecentEntriesTable::draw( ERTAppView::ERTAppView(NavigationView&) { baseband::run_image(portapack::spi_flash::image_tag_ert); - add_children({ { + add_children({ &field_rf_amp, &field_lna, &field_vga, &rssi, &recent_entries_view, - } }); + }); radio::enable({ initial_target_frequency, diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 5bfa3e12..e4068270 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -264,10 +264,10 @@ public: ) : _header { columns }, _table { recent } { - add_children({ { + add_children({ &_header, &_table, - } }); + }); _table.on_select = [this](const Entry& entry) { if( this->on_select ) { this->on_select(entry); } }; } diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 989e98d9..7fe5ab6f 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -135,7 +135,7 @@ void RecentEntriesTable::draw( TPMSAppView::TPMSAppView(NavigationView&) { baseband::run_image(portapack::spi_flash::image_tag_tpms); - add_children({ { + add_children({ &rssi, &channel, &options_band, @@ -143,7 +143,7 @@ TPMSAppView::TPMSAppView(NavigationView&) { &field_lna, &field_vga, &recent_entries_view, - } }); + }); radio::enable({ tuning_frequency(), diff --git a/firmware/application/ui_baseband_stats_view.cpp b/firmware/application/ui_baseband_stats_view.cpp index 44774465..b6a9525f 100644 --- a/firmware/application/ui_baseband_stats_view.cpp +++ b/firmware/application/ui_baseband_stats_view.cpp @@ -34,9 +34,9 @@ namespace ui { /* BasebandStatsView *****************************************************/ BasebandStatsView::BasebandStatsView() { - add_children({ { + add_children({ &text_stats, - } }); + }); } static std::string ticks_to_percent_string(const uint32_t ticks) { diff --git a/firmware/application/ui_debug.cpp b/firmware/application/ui_debug.cpp index e3d673a0..a5cc61e6 100644 --- a/firmware/application/ui_debug.cpp +++ b/firmware/application/ui_debug.cpp @@ -35,7 +35,7 @@ namespace ui { /* DebugMemoryView *******************************************************/ DebugMemoryView::DebugMemoryView(NavigationView& nav) { - add_children({ { + add_children({ &text_title, &text_label_m0_core_free, &text_label_m0_core_free_value, @@ -44,7 +44,7 @@ DebugMemoryView::DebugMemoryView(NavigationView& nav) { &text_label_m0_heap_fragments, &text_label_m0_heap_fragments_value, &button_done - } }); + }); const auto m0_core_free = chCoreStatus(); text_label_m0_core_free_value.set(to_string_dec_uint(m0_core_free, 5)); @@ -135,11 +135,11 @@ Coord TemperatureWidget::screen_y( /* TemperatureView *******************************************************/ TemperatureView::TemperatureView(NavigationView& nav) { - add_children({ { + add_children({ &text_title, &temperature_widget, &button_done, - } }); + }); button_done.on_select = [&nav](Button&){ nav.pop(); }; } @@ -219,12 +219,12 @@ RegistersView::RegistersView( std::function&& reader ) : registers_widget { std::move(config), std::move(reader) } { - add_children({ { + add_children({ &text_title, ®isters_widget, &button_update, &button_done, - } }); + }); button_update.on_select = [this](Button&){ this->registers_widget.update(); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index ba8e783c..b8882620 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -43,13 +43,13 @@ namespace ui { /* SystemStatusView ******************************************************/ SystemStatusView::SystemStatusView() { - add_children({ { + add_children({ &button_back, &title, &button_camera, &button_sleep, &sd_card_status_view, - } }); + }); button_back.on_select = [this](Button&){ if( this->on_back ) { @@ -259,7 +259,7 @@ HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) { nav.pop(); }; - add_children({ { + add_children({ &text_title, &text_description_1, &text_description_2, @@ -267,7 +267,7 @@ HackRFFirmwareView::HackRFFirmwareView(NavigationView& nav) { &text_description_4, &button_yes, &button_no, - } }); + }); } void HackRFFirmwareView::focus() { @@ -281,10 +281,10 @@ NotImplementedView::NotImplementedView(NavigationView& nav) { nav.pop(); }; - add_children({ { + add_children({ &text_title, &button_done, - } }); + }); } void NotImplementedView::focus() { @@ -303,10 +303,10 @@ ModalMessageView::ModalMessageView( nav.pop(); }; - add_children({ { + add_children({ &text_message, &button_done, - } }); + }); text_message.set(message); diff --git a/firmware/application/ui_receiver.cpp b/firmware/application/ui_receiver.cpp index d48917a4..1e7c648d 100644 --- a/firmware/application/ui_receiver.cpp +++ b/firmware/application/ui_receiver.cpp @@ -241,12 +241,12 @@ FrequencyOptionsView::FrequencyOptionsView( this->on_reference_ppm_correction_changed(v); }; - add_children({ { + add_children({ &text_step, &field_step, &field_ppm, &text_ppm, - } }); + }); } void FrequencyOptionsView::set_step(rf::Frequency f) { @@ -297,10 +297,10 @@ RadioGainOptionsView::RadioGainOptionsView( { set_style(style); - add_children({ { + add_children({ &label_rf_amp, &field_rf_amp, - } }); + }); } /* LNAGainField **********************************************************/ diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 71211dfc..01155490 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -177,13 +177,13 @@ RecordView::RecordView( write_size { write_size }, buffer_count { buffer_count } { - add_children({ { + add_children({ &rect_background, &button_record, &text_record_filename, &text_record_dropped, &text_time_available, - } }); + }); rect_background.set_parent_rect({ { 0, 0 }, size() }); diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index 22db218c..12dc5293 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -230,7 +230,7 @@ Thread* SDCardTestThread::thread { nullptr }; namespace ui { SDCardDebugView::SDCardDebugView(NavigationView& nav) { - add_children({ { + add_children({ &text_title, &text_csd_title, &text_csd_value_3, @@ -257,7 +257,7 @@ SDCardDebugView::SDCardDebugView(NavigationView& nav) { &text_test_read_rate_value, &button_test, &button_ok, - } }); + }); button_test.on_select = [this](Button&){ this->on_test(); }; button_ok.on_select = [&nav](Button&){ nav.pop(); }; diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index 9bc75389..2beddf7a 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -51,7 +51,7 @@ SetDateTimeView::SetDateTimeView( nav.pop(); }, - add_children({ { + add_children({ &text_title, &field_year, &text_slash1, @@ -66,7 +66,7 @@ SetDateTimeView::SetDateTimeView( &text_format, &button_ok, &button_cancel, - } }); + }); rtc::RTC datetime; rtcGetTime(&RTCD1, &datetime); @@ -119,13 +119,13 @@ SetFrequencyCorrectionView::SetFrequencyCorrectionView( nav.pop(); }, - add_children({ { + add_children({ &text_title, &field_ppm, &text_ppm, &button_ok, &button_cancel, - } }); + }); SetFrequencyCorrectionModel model { static_cast(portapack::persistent_memory::correction_ppb() / 1000) @@ -149,7 +149,7 @@ SetFrequencyCorrectionModel SetFrequencyCorrectionView::form_collect() { } AntennaBiasSetupView::AntennaBiasSetupView(NavigationView& nav) { - add_children({ { + add_children({ &text_title, &text_description_1, &text_description_2, @@ -157,7 +157,7 @@ AntennaBiasSetupView::AntennaBiasSetupView(NavigationView& nav) { &text_description_4, &options_bias, &button_done, - } }); + }); options_bias.set_by_value(receiver_model.antenna_bias() ? 1 : 0); options_bias.on_change = [this](size_t, OptionsField::value_t v) { @@ -172,13 +172,13 @@ void AntennaBiasSetupView::focus() { } AboutView::AboutView(NavigationView& nav) { - add_children({ { + add_children({ &text_title, &text_firmware, &text_cpld_hackrf, &text_cpld_hackrf_status, &button_ok, - } }); + }); button_ok.on_select = [&nav](Button&){ nav.pop(); }; diff --git a/firmware/application/ui_touch_calibration.cpp b/firmware/application/ui_touch_calibration.cpp index 6fe20027..37cd0df8 100644 --- a/firmware/application/ui_touch_calibration.cpp +++ b/firmware/application/ui_touch_calibration.cpp @@ -33,7 +33,7 @@ TouchCalibrationView::TouchCalibrationView( ) : nav { nav }, calibration { touch::default_calibration() } { - add_children({ { + add_children({ &image_calibrate_0, &image_calibrate_1, &image_calibrate_2, @@ -46,7 +46,7 @@ TouchCalibrationView::TouchCalibrationView( &label_failure, &button_cancel, &button_ok, - } }); + }); button_cancel.on_select = [this](Button&){ this->on_cancel(); }; button_ok.on_select = [this](Button&){ this->on_ok(); }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 31a71d51..d760faaa 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -232,9 +232,11 @@ void View::add_child(Widget* const widget) { } } -void View::add_children(const std::vector& children) { +void View::add_children(const std::initializer_list children) { + children_.insert(std::end(children_), children); for(auto child : children) { - add_child(child); + child->set_parent(this); + child->set_dirty(); } } diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 2c427249..18a03158 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -154,7 +154,7 @@ public: void paint(Painter& painter) override; void add_child(Widget* const widget); - void add_children(const std::vector& children); + void add_children(const std::initializer_list children); void remove_child(Widget* const widget); const std::vector& children() const override; From 09222f004455ddbb5ae4c023664b48038cd39c52 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 15:04:28 -0700 Subject: [PATCH 045/100] Widget/View: Consolidate dirty code inside Widget. --- firmware/common/ui_widget.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index d760faaa..94716753 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -70,12 +70,19 @@ Widget* Widget::parent() const { } void Widget::set_parent(Widget* const widget) { + if( widget == parent_ ) { + return; + } + if( parent_ && !widget ) { // We have a parent, but are losing it. Update visible status. + dirty_overlapping_children_in_rect(screen_rect()); visible(false); } parent_ = widget; + + set_dirty(); } void Widget::set_dirty() { @@ -227,7 +234,6 @@ void View::add_child(Widget* const widget) { if( widget->parent() == nullptr ) { widget->set_parent(this); children_.push_back(widget); - widget->set_dirty(); } } } @@ -236,14 +242,12 @@ void View::add_children(const std::initializer_list children) { children_.insert(std::end(children_), children); for(auto child : children) { child->set_parent(this); - child->set_dirty(); } } void View::remove_child(Widget* const widget) { if( widget ) { children_.erase(std::remove(children_.begin(), children_.end(), widget), children_.end()); - dirty_overlapping_children_in_rect(widget->screen_rect()); widget->set_parent(nullptr); } } From 9a01d598224f004ab2d5272857d731318ec1b481 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 15:20:50 -0700 Subject: [PATCH 046/100] MenuView: Change add_items arg to initializer_list. Another code size improvement, and makes maintaining lists of menu items less stupid (you don't need to change the template arg when the item count changes). --- firmware/application/ui_debug.cpp | 8 ++++---- firmware/application/ui_menu.hpp | 3 +-- firmware/application/ui_navigation.cpp | 12 ++++++------ firmware/application/ui_setup.cpp | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/firmware/application/ui_debug.cpp b/firmware/application/ui_debug.cpp index a5cc61e6..6e1bdcca 100644 --- a/firmware/application/ui_debug.cpp +++ b/firmware/application/ui_debug.cpp @@ -247,7 +247,7 @@ void RegistersView::focus() { /* DebugPeripheralsMenuView **********************************************/ DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) { - add_items<4>({ { + add_items({ { "RFFC5072", [&nav](){ nav.push( "RFFC5072", RegistersWidgetConfig { 31, 2, 4, 4 }, [](const size_t register_number) { return radio::debug::first_if::register_read(register_number); } @@ -264,20 +264,20 @@ DebugPeripheralsMenuView::DebugPeripheralsMenuView(NavigationView& nav) { "WM8731", RegistersWidgetConfig { audio::debug::reg_count(), 1, 3, 4 }, [](const size_t register_number) { return audio::debug::reg_read(register_number); } ); } }, - } }); + }); on_left = [&nav](){ nav.pop(); }; } /* DebugMenuView *********************************************************/ DebugMenuView::DebugMenuView(NavigationView& nav) { - add_items<5>({ { + add_items({ { "Memory", [&nav](){ nav.push(); } }, { "Radio State", [&nav](){ nav.push(); } }, { "SD Card", [&nav](){ nav.push(); } }, { "Peripherals", [&nav](){ nav.push(); } }, { "Temperature", [&nav](){ nav.push(); } }, - } }); + }); on_left = [&nav](){ nav.pop(); }; } diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 0bd19c11..6873e5da 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -71,8 +71,7 @@ public: void add_item(const MenuItem item); - template - void add_items(const std::array& items) { + void add_items(const std::initializer_list items) { for(const auto& item : items) { add_item(item); } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index b8882620..cc5c40f7 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -170,28 +170,28 @@ void NavigationView::focus() { /* TransceiversMenuView **************************************************/ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) { - add_items<3>({ { + add_items({ { "AIS: Boats", [&nav](){ nav.push(); } }, { "ERT: Utility Meters", [&nav](){ nav.push(); } }, { "TPMS: Cars", [&nav](){ nav.push(); } }, - } }); + }); on_left = [&nav](){ nav.pop(); }; } /* ReceiverMenuView ******************************************************/ ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { - add_items<2>({ { + add_items({ { "Audio", [&nav](){ nav.push(); } }, { "Transponders", [&nav](){ nav.push(); } }, - } }); + }); on_left = [&nav](){ nav.pop(); }; } /* SystemMenuView ********************************************************/ SystemMenuView::SystemMenuView(NavigationView& nav) { - add_items<7>({ { + add_items({ { "Receiver", [&nav](){ nav.push(); } }, { "Capture", [&nav](){ nav.push(); } }, { "Analyze", [&nav](){ nav.push(); } }, @@ -199,7 +199,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "About", [&nav](){ nav.push(); } }, { "Debug", [&nav](){ nav.push(); } }, { "HackRF", [&nav](){ nav.push(); } }, - } }); + }); } /* SystemView ************************************************************/ diff --git a/firmware/application/ui_setup.cpp b/firmware/application/ui_setup.cpp index 2beddf7a..550af2dd 100644 --- a/firmware/application/ui_setup.cpp +++ b/firmware/application/ui_setup.cpp @@ -194,12 +194,12 @@ void AboutView::focus() { } SetupMenuView::SetupMenuView(NavigationView& nav) { - add_items<4>({ { + add_items({ { "Date/Time", [&nav](){ nav.push(); } }, { "Frequency Correction", [&nav](){ nav.push(); } }, { "Antenna Bias Voltage", [&nav](){ nav.push(); } }, { "Touch", [&nav](){ nav.push(); } }, - } }); + }); on_left = [&nav](){ nav.pop(); }; } From 722f9b68861bb48fb0c1d0d01f8edf6cafae483a Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 15:30:45 -0700 Subject: [PATCH 047/100] MenuItem: Misc const and constructor consistency adjustments. Also moved add_items() body to .cpp file. --- firmware/application/ui_menu.cpp | 8 +++++++- firmware/application/ui_menu.hpp | 11 +++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 4b79cbb1..4a04e817 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -69,10 +69,16 @@ MenuView::~MenuView() { } } -void MenuView::add_item(const MenuItem item) { +void MenuView::add_item(MenuItem item) { add_child(new MenuItemView { item }); } +void MenuView::add_items(std::initializer_list items) { + for(auto item : items) { + add_item(item); + } +} + void MenuView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 6873e5da..7d10dbf6 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -45,7 +45,7 @@ class MenuItemView : public Widget { public: MenuItemView( MenuItem item - ) : item(item) + ) : item { item } { } @@ -69,13 +69,8 @@ public: ~MenuView(); - void add_item(const MenuItem item); - - void add_items(const std::initializer_list items) { - for(const auto& item : items) { - add_item(item); - } - } + void add_item(MenuItem item); + void add_items(std::initializer_list items); void set_parent_rect(const Rect new_parent_rect) override; From 2740761ed789e9239afa5691e363f88cb75d40e4 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 5 Sep 2016 16:49:44 -0700 Subject: [PATCH 048/100] RecentEntriesX: Move non-templated bits to .cpp. --- firmware/application/recent_entries.cpp | 39 +++++++++++++++++++++++++ firmware/application/recent_entries.hpp | 31 ++------------------ 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/firmware/application/recent_entries.cpp b/firmware/application/recent_entries.cpp index bfb21aee..0521238a 100644 --- a/firmware/application/recent_entries.cpp +++ b/firmware/application/recent_entries.cpp @@ -20,3 +20,42 @@ */ #include "recent_entries.hpp" + +namespace ui { + +RecentEntriesColumns::RecentEntriesColumns( + const std::initializer_list columns +) : _columns { columns } +{ +} + +RecentEntriesHeader::RecentEntriesHeader( + const RecentEntriesColumns& columns +) : _columns { columns } +{ +} + +void RecentEntriesHeader::paint(Painter& painter) { + const auto r = screen_rect(); + const auto& parent_style = style(); + + const Style style { + .font = parent_style.font, + .background = Color::blue(), + .foreground = parent_style.foreground, + }; + + auto p = r.pos; + for(const auto& column : _columns) { + const auto width = column.second; + auto text = column.first; + if( width > text.length() ) { + text.append(width - text.length(), ' '); + } + + painter.draw_string(p, style, text); + p += { static_cast((width * 8) + 8), 0 }; + } +} + +} /* namespace ui */ diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index e4068270..568f5e6c 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -101,9 +101,7 @@ public: RecentEntriesColumns( const std::initializer_list columns - ) : _columns { columns } - { - } + ); ContainerType::const_iterator begin() const { return std::begin(_columns); } ContainerType::const_iterator end() const { return std::end(_columns); } @@ -116,32 +114,9 @@ class RecentEntriesHeader : public Widget { public: RecentEntriesHeader( const RecentEntriesColumns& columns - ) : _columns { columns } - { - } + ); - void paint(Painter& painter) override { - const auto r = screen_rect(); - const auto& parent_style = style(); - - const Style style { - .font = parent_style.font, - .background = Color::blue(), - .foreground = parent_style.foreground, - }; - - auto p = r.pos; - for(const auto& column : _columns) { - const auto width = column.second; - auto text = column.first; - if( width > text.length() ) { - text.append(width - text.length(), ' '); - } - - painter.draw_string(p, style, text); - p += { static_cast((width * 8) + 8), 0 }; - } - } + void paint(Painter& painter) override; private: const RecentEntriesColumns& _columns; From 79330015ed8f0b992f30552bb5ad6684ab903380 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 7 Sep 2016 20:46:45 -0700 Subject: [PATCH 049/100] File: Clean up directory_iterator construction, preserve pattern. FatFs requires pattern pointer to be stable during search. --- firmware/application/file.cpp | 11 ++++++----- firmware/application/file.hpp | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 8c45c8b3..487e53e4 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -126,7 +126,7 @@ Optional File::sync() { static std::filesystem::path find_last_file_matching_pattern(const std::filesystem::path& pattern) { std::filesystem::path last_match; - for(const auto& entry : std::filesystem::directory_iterator(u"", pattern.c_str())) { + for(const auto& entry : std::filesystem::directory_iterator(u"", pattern)) { if( std::filesystem::is_regular_file(entry.status()) ) { const auto match = entry.path(); if( match > last_match ) { @@ -211,11 +211,12 @@ std::string filesystem_error::what() const { } directory_iterator::directory_iterator( - const std::filesystem::path::value_type* path, - const std::filesystem::path::value_type* wild -) { + std::filesystem::path path, + std::filesystem::path wild +) : pattern { wild } +{ impl = std::make_shared(); - const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast(path), reinterpret_cast(wild)); + const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast(path.c_str()), reinterpret_cast(pattern.c_str())); if( result != FR_OK ) { impl.reset(); // TODO: Throw exception if/when I enable exceptions... diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 64691703..bc004015 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -97,6 +97,7 @@ class directory_iterator { }; std::shared_ptr impl; + const path pattern; friend bool operator!=(const directory_iterator& lhs, const directory_iterator& rhs); @@ -108,8 +109,8 @@ public: using iterator_category = std::input_iterator_tag; directory_iterator() noexcept { }; - directory_iterator(const std::filesystem::path::value_type* path, const std::filesystem::path::value_type* wild); - + directory_iterator(std::filesystem::path path, std::filesystem::path wild); + ~directory_iterator() { } directory_iterator& operator++(); From f722497b01d6e34b8f0f7fbe84dfa3bc83446c1a Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 7 Sep 2016 22:18:11 -0700 Subject: [PATCH 050/100] Rect: operator method to offset by a Point. --- firmware/common/ui.cpp | 5 +++++ firmware/common/ui.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/firmware/common/ui.cpp b/firmware/common/ui.cpp index 4fd40088..d6d881d6 100644 --- a/firmware/common/ui.cpp +++ b/firmware/common/ui.cpp @@ -57,4 +57,9 @@ Rect& Rect::operator+=(const Rect& p) { return *this; } +Rect& Rect::operator+=(const Point& p) { + pos += p; + return *this; +} + } /* namespace ui */ diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index 0a10a9f2..f363a841 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -208,6 +208,7 @@ struct Rect { } Rect& operator+=(const Rect& p); + Rect& operator+=(const Point& p); operator bool() const { return !size.is_empty(); From df0fc30fdae6f42d29dc6b51f6bd9424cd90833b Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 7 Sep 2016 22:19:30 -0700 Subject: [PATCH 051/100] Rect: Comment about a bad API method. In retrospect, I don't like Rect + Rect = union -- it doesn't make as much sense and isn't as readable as Rect.union(Rect). --- firmware/common/ui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/common/ui.cpp b/firmware/common/ui.cpp index d6d881d6..5b0f55b2 100644 --- a/firmware/common/ui.cpp +++ b/firmware/common/ui.cpp @@ -42,6 +42,8 @@ Rect Rect::intersect(const Rect& o) const { } } +// TODO: This violates the principle of least surprise! +// This does a union, but that might not be obvious from "+=" syntax. Rect& Rect::operator+=(const Rect& p) { if( is_empty() ) { *this = p; From f80706cb343f8aca86a8bf81c3f4e6882571481f Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 7 Sep 2016 22:20:51 -0700 Subject: [PATCH 052/100] File: Extract function to convert path to string. --- firmware/application/file.cpp | 7 +++++++ firmware/application/file.hpp | 2 ++ firmware/application/ui_record_view.cpp | 8 +------- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 487e53e4..6ba485d9 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -22,6 +22,8 @@ #include "file.hpp" #include +#include +#include /* Values added to FatFs FRESULT enum, values outside the FRESULT data type */ static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected."); @@ -210,6 +212,11 @@ std::string filesystem_error::what() const { } } +std::string path_to_string(const path& p) { + std::wstring_convert, path::value_type> conv; + return conv.to_bytes(p); +} + directory_iterator::directory_iterator( std::filesystem::path path, std::filesystem::path wild diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index bc004015..6c6ab0ee 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -70,6 +70,8 @@ using file_status = BYTE; static_assert(sizeof(path::value_type) == 2, "sizeof(std::filesystem::path::value_type) != 2"); static_assert(sizeof(path::value_type) == sizeof(TCHAR), "FatFs TCHAR size != std::filesystem::path::value_type"); +std::string path_to_string(const path& p); + struct space_info { static_assert(sizeof(std::uintmax_t) >= 8, "std::uintmax_t too small ( -#include -#include - class FileWriter : public Writer { public: FileWriter() = default; @@ -289,10 +286,7 @@ void RecordView::start() { }; if( writer ) { - std::wstring_convert, std::filesystem::path::value_type> conv; - const auto filename_stem_s = conv.to_bytes(filename_stem); - - text_record_filename.set(filename_stem_s); + text_record_filename.set(std::filesystem::path_to_string(filename_stem)); button_record.set_bitmap(&bitmap_stop); capture_thread = std::make_unique( std::move(writer), From b87d1456a286f8551d8aa947ab10901762b192e6 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 8 Sep 2016 12:57:34 -0700 Subject: [PATCH 053/100] File: Make path a first-class object, add some methods from C++17. --- firmware/application/file.cpp | 80 +++++++++++++----- firmware/application/file.hpp | 103 ++++++++++++++++++++++-- firmware/application/ui_navigation.cpp | 6 +- firmware/application/ui_record_view.cpp | 16 ++-- 4 files changed, 166 insertions(+), 39 deletions(-) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 6ba485d9..e7fec84e 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -139,18 +139,12 @@ static std::filesystem::path find_last_file_matching_pattern(const std::filesyst return last_match; } -static std::filesystem::path remove_filename_extension(const std::filesystem::path& filename) { - const auto extension_index = filename.find_last_of('.'); - return filename.substr(0, extension_index); -} - -static std::filesystem::path increment_filename_stem_ordinal(const std::filesystem::path& filename_stem) { - std::filesystem::path result { filename_stem }; - - auto it = result.rbegin(); +static std::filesystem::path increment_filename_stem_ordinal(std::filesystem::path path) { + auto t = path.replace_extension().native(); + auto it = t.rbegin(); // Increment decimal number before the extension. - for(; it != result.rend(); ++it) { + for(; it != t.rend(); ++it) { const auto c = *it; if( c < '0' ) { return { }; @@ -164,19 +158,18 @@ static std::filesystem::path increment_filename_stem_ordinal(const std::filesyst } } - return result; + return t; } -std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem::path& filename_stem_pattern) { - const auto filename = find_last_file_matching_pattern(filename_stem_pattern + u".*"); - auto filename_stem = remove_filename_extension(filename); - if( filename_stem.empty() ) { - filename_stem = filename_stem_pattern; - std::replace(std::begin(filename_stem), std::end(filename_stem), '?', '0'); +std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_pattern) { + const auto next_filename = find_last_file_matching_pattern(filename_pattern.replace_extension(u".*")); + if( next_filename.empty() ) { + auto pattern_s = filename_pattern.replace_extension().native(); + std::replace(std::begin(pattern_s), std::end(pattern_s), '?', '0'); + return pattern_s; } else { - filename_stem = increment_filename_stem_ordinal(filename_stem); + return increment_filename_stem_ordinal(next_filename); } - return filename_stem; } namespace std { @@ -212,9 +205,54 @@ std::string filesystem_error::what() const { } } -std::string path_to_string(const path& p) { +path path::extension() const { + const auto t = filename().native(); + const auto index = t.find_last_of(u'.'); + if( index == t.npos ) { + return { }; + } else { + return t.substr(index); + } +} + +path path::filename() const { + const auto index = _s.find_last_of(preferred_separator); + if( index == _s.npos ) { + return _s; + } else { + return _s.substr(index + 1); + } +} + +path path::stem() const { + const auto t = filename().native(); + const auto index = t.find_last_of(u'.'); + if( index == t.npos ) { + return t; + } else { + return t.substr(0, index); + } +} + +std::string path::string() const { std::wstring_convert, path::value_type> conv; - return conv.to_bytes(p); + return conv.to_bytes(native()); +} + +path& path::replace_extension(const path& replacement) { + const auto t = extension().native(); + _s.erase(_s.size() - t.size()); + if( !replacement._s.empty() ) { + if( replacement._s.front() != u'.' ) { + _s += u'.'; + } + _s += replacement._s; + } + return *this; +} + +bool operator>(const path& lhs, const path& rhs) { + return lhs.native() > rhs.native(); } directory_iterator::directory_iterator( diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 6c6ab0ee..cca7f220 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -64,14 +64,107 @@ private: uint32_t err; }; -using path = std::u16string; +struct path { + using string_type = std::u16string; + using value_type = string_type::value_type; + + static constexpr value_type preferred_separator = u'/'; + + path( + ) : _s { } + { + } + + path( + const path& p + ) : _s { p._s } + { + } + + path( + path&& p + ) : _s { std::move(p._s) } + { + } + + template + path( + const Source& source + ) : path { std::begin(source), std::end(source) } + { + } + + template + path( + InputIt first, + InputIt last + ) : _s { first, last } + { + } + + path( + const char16_t* const s + ) : _s { s } + { + } + + path( + const TCHAR* const s + ) : _s { reinterpret_cast(s) } + { + } + + path& operator=(const path& p) { + _s = p._s; + return *this; + } + + path& operator=(path&& p) { + _s = std::move(p._s); + return *this; + } + + path extension() const; + path filename() const; + path stem() const; + + bool empty() const { + return _s.empty(); + } + + const value_type* c_str() const { + return native().c_str(); + } + + const string_type& native() const { + return _s; + } + + std::string string() const; + + path& operator+=(const path& p) { + _s += p._s; + return *this; + } + + path& operator+=(const string_type& str) { + _s += str; + return *this; + } + + path& replace_extension(const path& replacement = path()); + +private: + string_type _s; +}; + +bool operator>(const path& lhs, const path& rhs); + using file_status = BYTE; static_assert(sizeof(path::value_type) == 2, "sizeof(std::filesystem::path::value_type) != 2"); static_assert(sizeof(path::value_type) == sizeof(TCHAR), "FatFs TCHAR size != std::filesystem::path::value_type"); -std::string path_to_string(const path& p); - struct space_info { static_assert(sizeof(std::uintmax_t) >= 8, "std::uintmax_t too small ((fname); }; + const std::filesystem::path path() const noexcept { return { fname }; }; }; class directory_iterator { @@ -135,7 +228,7 @@ space_info space(const path& p); } /* namespace filesystem */ } /* namespace std */ -std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem::path& filename_stem_pattern); +std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern); class File { public: diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index cc5c40f7..8572d6d7 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -81,13 +81,13 @@ void SystemStatusView::set_title(const std::string new_value) { } void SystemStatusView::on_camera() { - const auto filename_stem = next_filename_stem_matching_pattern(u"SCR_????"); - if( filename_stem.empty() ) { + auto path = next_filename_stem_matching_pattern(u"SCR_????"); + if( path.empty() ) { return; } PNGWriter png; - auto create_error = png.create(filename_stem + u".PNG"); + auto create_error = png.create(path.replace_extension(u".PNG")); if( create_error.is_valid() ) { return; } diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 296952d1..0b43ed0f 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -238,8 +238,8 @@ void RecordView::start() { return; } - const auto filename_stem = next_filename_stem_matching_pattern(filename_stem_pattern); - if( filename_stem.empty() ) { + auto base_path = next_filename_stem_matching_pattern(filename_stem_pattern); + if( base_path.empty() ) { return; } @@ -250,9 +250,7 @@ void RecordView::start() { auto p = std::make_unique( sampling_rate ); - auto create_error = p->create( - filename_stem + u".WAV" - ); + auto create_error = p->create(base_path.replace_extension(u".WAV")); if( create_error.is_valid() ) { handle_error(create_error.value()); } else { @@ -263,16 +261,14 @@ void RecordView::start() { case FileType::RawS16: { - const auto metadata_file_error = write_metadata_file(filename_stem + u".TXT"); + const auto metadata_file_error = write_metadata_file(base_path.replace_extension(u".TXT")); if( metadata_file_error.is_valid() ) { handle_error(metadata_file_error.value()); return; } auto p = std::make_unique(); - auto create_error = p->create( - filename_stem + u".C16" - ); + auto create_error = p->create(base_path.replace_extension(u".C16")); if( create_error.is_valid() ) { handle_error(create_error.value()); } else { @@ -286,7 +282,7 @@ void RecordView::start() { }; if( writer ) { - text_record_filename.set(std::filesystem::path_to_string(filename_stem)); + text_record_filename.set(base_path.replace_extension().string()); button_record.set_bitmap(&bitmap_stop); capture_thread = std::make_unique( std::move(writer), From b9e475cbf4b6cc24da95183309c358577cabe3ca Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 23 Sep 2016 12:18:42 -0700 Subject: [PATCH 054/100] Silence CMakeForceCompiler deprecation warning for >=3.6. --- firmware/toolchain-arm-cortex-m.cmake | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/firmware/toolchain-arm-cortex-m.cmake b/firmware/toolchain-arm-cortex-m.cmake index 033fb185..2304f6f8 100644 --- a/firmware/toolchain-arm-cortex-m.cmake +++ b/firmware/toolchain-arm-cortex-m.cmake @@ -23,10 +23,16 @@ set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR arm) -include(CMakeForceCompiler) +if(CMAKE_VERSION VERSION_LESS 3.6) + include(CMakeForceCompiler) -CMAKE_FORCE_C_COMPILER(arm-none-eabi-gcc GNU) -CMAKE_FORCE_CXX_COMPILER(arm-none-eabi-g++ GNU) + CMAKE_FORCE_C_COMPILER(arm-none-eabi-gcc GNU) + CMAKE_FORCE_CXX_COMPILER(arm-none-eabi-g++ GNU) +else() + set(CMAKE_C_COMPILER arm-none-eabi-gcc) + set(CMAKE_CXX_COMPILER arm-none-eabi-g++) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() execute_process( COMMAND ${CMAKE_C_COMPILER} -print-file-name=libc.a From 86f672af2b9b7ef645d4ebf325c5803e847202e2 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 1 Oct 2016 10:44:11 -0700 Subject: [PATCH 055/100] File: Add misc useful API from C++17. --- firmware/application/file.cpp | 8 ++++++++ firmware/application/file.hpp | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index e7fec84e..46d5fe81 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -251,6 +251,10 @@ path& path::replace_extension(const path& replacement) { return *this; } +bool operator<(const path& lhs, const path& rhs) { + return lhs.native() < rhs.native(); +} + bool operator>(const path& lhs, const path& rhs) { return lhs.native() > rhs.native(); } @@ -276,6 +280,10 @@ directory_iterator& directory_iterator::operator++() { return *this; } +bool is_directory(const file_status s) { + return (s & AM_DIR); +} + bool is_regular_file(const file_status s) { return !(s & AM_DIR); } diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index cca7f220..57e63fd9 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -158,6 +158,7 @@ private: string_type _s; }; +bool operator<(const path& lhs, const path& rhs); bool operator>(const path& lhs, const path& rhs); using file_status = BYTE; @@ -178,6 +179,10 @@ struct directory_entry : public FILINFO { return fattrib; } + std::uintmax_t size() const { + return fsize; + }; + const std::filesystem::path path() const noexcept { return { fname }; }; }; @@ -221,6 +226,7 @@ inline directory_iterator end(const directory_iterator&) noexcept { return { }; inline bool operator!=(const directory_iterator& lhs, const directory_iterator& rhs) { return lhs.impl != rhs.impl; }; +bool is_directory(const file_status s); bool is_regular_file(const file_status s); space_info space(const path& p); From aed58f2a3f534b786e58034530592da311725b82 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 1 Oct 2016 10:47:21 -0700 Subject: [PATCH 056/100] File: Stop copying path when iterating. TODO: I bet I've made this mistake a billion other places... --- firmware/application/file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 46d5fe81..ae846892 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -130,7 +130,7 @@ static std::filesystem::path find_last_file_matching_pattern(const std::filesyst std::filesystem::path last_match; for(const auto& entry : std::filesystem::directory_iterator(u"", pattern)) { if( std::filesystem::is_regular_file(entry.status()) ) { - const auto match = entry.path(); + const auto& match = entry.path(); if( match > last_match ) { last_match = match; } From f756ac4eac4a8c964f6a8270eabb3f5a24013c84 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 3 Oct 2016 11:34:59 -0700 Subject: [PATCH 057/100] CMake: Produce linker .map files for application, basebands. --- firmware/application/CMakeLists.txt | 1 + firmware/baseband/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 23d61736..d481844f 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -322,6 +322,7 @@ add_definitions(${DEFS}) include_directories(. ${INCDIR}) link_directories(${LLIBDIR}) target_link_libraries(${PROJECT_NAME}.elf ${LIBS}) +target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map) add_custom_command( OUTPUT ${PROJECT_NAME}.bin diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 2a8b1b53..eade87c1 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -258,6 +258,7 @@ macro(DeclareTargets chunk_tag name) include_directories(. ${INCDIR}) link_directories(${LLIBDIR}) target_link_libraries(${PROJECT_NAME}.elf ${LIBS}) + target_link_libraries(${PROJECT_NAME}.elf -Wl,-Map=${PROJECT_NAME}.map) add_custom_command( OUTPUT ${PROJECT_NAME}.bin ${PROJECT_NAME}.img From 415399594454bfd9e94937e33f474ad2732a67d7 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 3 Oct 2016 11:58:42 -0700 Subject: [PATCH 058/100] CPLD: Invert GCK2 to improve ADC sample timing. --- firmware/application/clock_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/clock_manager.cpp b/firmware/application/clock_manager.cpp index 5ec51aec..c8b75cce 100644 --- a/firmware/application/clock_manager.cpp +++ b/firmware/application/clock_manager.cpp @@ -219,7 +219,7 @@ constexpr ClockControl::Type si5351_clock_control_ms_src_clkin = ClockControl::M constexpr ClockControls si5351_clock_control_common { ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Fractional | ClockControl::CLK_PDN_Power_Off, - ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off, + ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Invert | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_IDRV_8mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_IDRV_8mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off, From b69a3abcb5d727e6456ef922f430d312c9cf7843 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 3 Oct 2016 12:31:40 -0700 Subject: [PATCH 059/100] Spectrum: Templatize various window functions. --- firmware/baseband/spectrum_collector.cpp | 29 +++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/firmware/baseband/spectrum_collector.cpp b/firmware/baseband/spectrum_collector.cpp index 0d288bee..ebe55a24 100644 --- a/firmware/baseband/spectrum_collector.cpp +++ b/firmware/baseband/spectrum_collector.cpp @@ -103,6 +103,31 @@ void SpectrumCollector::post_message(const buffer_c16_t& data) { } } +template +static typename T::value_type spectrum_window_none(const T& s, const size_t i) { + static_assert(power_of_two(s.size()), "Array size must be power of 2"); + return s[i]; +}; + +template +static typename T::value_type spectrum_window_hamming_3(const T& s, const size_t i) { + static_assert(power_of_two(s.size()), "Array size must be power of 2"); + constexpr size_t mask = s.size() - 1; + // Three point Hamming window. + return s[i] * 0.54f + (s[(i-1) & mask] + s[(i+1) & mask]) * -0.23f; +}; + +template +static typename T::value_type spectrum_window_blackman_3(const T& s, const size_t i) { + static_assert(power_of_two(s.size()), "Array size must be power of 2"); + constexpr size_t mask = s.size() - 1; + // Three term Blackman window. + constexpr float alpha = 0.42f; + constexpr float beta = 0.5f * 0.5f; + constexpr float gamma = 0.08f * 0.05f; + return s[i] * alpha - (s[(i-1) & mask] + s[(i+1) & mask]) * beta + (s[(i-2) & mask] + s[(i+2) & mask]) * gamma; +}; + void SpectrumCollector::update() { // Called from idle thread (after EVT_MASK_SPECTRUM is flagged) if( streaming && channel_spectrum_request_update ) { @@ -114,9 +139,7 @@ void SpectrumCollector::update() { spectrum.channel_filter_pass_frequency = channel_filter_pass_frequency; spectrum.channel_filter_stop_frequency = channel_filter_stop_frequency; for(size_t i=0; i Date: Tue, 4 Oct 2016 09:15:19 -0700 Subject: [PATCH 060/100] Allow modification of StreamBuffer (data values, size). --- firmware/common/message.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index a4030b5f..290d7dd8 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -406,7 +406,7 @@ public: return used_ >= capacity_; } - const void* data() const { + void* data() const { return data_; } @@ -414,6 +414,10 @@ public: return used_; } + void set_size(const size_t value) { + used_ = value; + } + void empty() { used_ = 0; } From 1bdca0fd8d7ae34c5f67cd279d55499ca89ca024 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 09:36:52 -0700 Subject: [PATCH 061/100] Extract (some) Writer classes to separate files. TODO: PNGWriter could probably reuse this stuff too, but... --- firmware/application/capture_thread.hpp | 8 +- firmware/application/io.hpp | 30 ++++++ firmware/application/io_file.hpp | 57 ++++++++++ firmware/application/io_wave.hpp | 130 +++++++++++++++++++++++ firmware/application/ui_record_view.cpp | 132 +----------------------- 5 files changed, 221 insertions(+), 136 deletions(-) create mode 100644 firmware/application/io.hpp create mode 100644 firmware/application/io_file.hpp create mode 100644 firmware/application/io_wave.hpp diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index 6e2bbaa8..e867e4ec 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -26,19 +26,13 @@ #include "event_m0.hpp" -#include "file.hpp" +#include "io.hpp" #include "optional.hpp" #include #include #include -class Writer { -public: - virtual File::Result write(const void* const buffer, const File::Size bytes) = 0; - virtual ~Writer() = default; -}; - class CaptureThread { public: CaptureThread( diff --git a/firmware/application/io.hpp b/firmware/application/io.hpp new file mode 100644 index 00000000..6333b001 --- /dev/null +++ b/firmware/application/io.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "file.hpp" + +class Writer { +public: + virtual File::Result write(const void* const buffer, const File::Size bytes) = 0; + virtual ~Writer() = default; +}; diff --git a/firmware/application/io_file.hpp b/firmware/application/io_file.hpp new file mode 100644 index 00000000..65f44826 --- /dev/null +++ b/firmware/application/io_file.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "io.hpp" + +#include "file.hpp" +#include "optional.hpp" + +#include + +class FileWriter : public Writer { +public: + FileWriter() = default; + + FileWriter(const FileWriter&) = delete; + FileWriter& operator=(const FileWriter&) = delete; + FileWriter(FileWriter&& file) = delete; + FileWriter& operator=(FileWriter&&) = delete; + + Optional create(const std::filesystem::path& filename) { + return file.create(filename); + } + + File::Result write(const void* const buffer, const File::Size bytes) override { + auto write_result = file.write(buffer, bytes) ; + if( write_result.is_ok() ) { + bytes_written += write_result.value(); + } + return write_result; + } + +protected: + File file; + uint64_t bytes_written { 0 }; +}; + +using RawFileWriter = FileWriter; diff --git a/firmware/application/io_wave.hpp b/firmware/application/io_wave.hpp new file mode 100644 index 00000000..304d98e7 --- /dev/null +++ b/firmware/application/io_wave.hpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "io_file.hpp" + +#include "file.hpp" +#include "optional.hpp" + +#include +#include + +class WAVFileWriter : public FileWriter { +public: + WAVFileWriter( + size_t sampling_rate + ) : header { sampling_rate } + { + } + + + WAVFileWriter(const WAVFileWriter&) = delete; + WAVFileWriter& operator=(const WAVFileWriter&) = delete; + WAVFileWriter(WAVFileWriter&&) = delete; + WAVFileWriter& operator=(WAVFileWriter&&) = delete; + + ~WAVFileWriter() { + update_header(); + } + + Optional create( + const std::filesystem::path& filename + ) { + const auto create_error = FileWriter::create(filename); + if( create_error.is_valid() ) { + return create_error; + } else { + return update_header(); + } + } + +private: + struct fmt_pcm_t { + constexpr fmt_pcm_t( + const uint32_t sampling_rate + ) : nSamplesPerSec { sampling_rate }, + nAvgBytesPerSec { nSamplesPerSec * nBlockAlign } + { + } + + private: + const uint8_t ckID[4] { 'f', 'm', 't', ' ' }; + const uint32_t cksize { 16 }; + const uint16_t wFormatTag { 0x0001 }; + const uint16_t nChannels { 1 }; + const uint32_t nSamplesPerSec; + const uint32_t nAvgBytesPerSec; + const uint16_t nBlockAlign { 2 }; + const uint16_t wBitsPerSample { 16 }; + }; + + struct data_t { + void set_size(const uint32_t value) { + cksize = value; + } + + private: + const uint8_t ckID[4] { 'd', 'a', 't', 'a' }; + uint32_t cksize { 0 }; + }; + + struct header_t { + constexpr header_t( + const uint32_t sampling_rate + ) : fmt { sampling_rate } + { + } + + void set_data_size(const uint32_t value) { + data.set_size(value); + cksize = sizeof(header_t) + value - 8; + } + + private: + const uint8_t riff_id[4] { 'R', 'I', 'F', 'F' }; + uint32_t cksize { 0 }; + const uint8_t wave_id[4] { 'W', 'A', 'V', 'E' }; + fmt_pcm_t fmt; + data_t data; + }; + + header_t header; + + Optional update_header() { + header.set_data_size(bytes_written); + const auto seek_0_result = file.seek(0); + if( seek_0_result.is_error() ) { + return seek_0_result.error(); + } + const auto old_position = seek_0_result.value(); + const auto write_result = file.write(&header, sizeof(header)); + if( write_result.is_error() ) { + return write_result.error(); + } + const auto seek_old_result = file.seek(old_position); + if( seek_old_result.is_error() ) { + return seek_old_result.error(); + } + return { }; + } +}; diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 0b43ed0f..60ff0ddb 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -24,7 +24,9 @@ #include "portapack.hpp" using namespace portapack; -#include "file.hpp" +#include "io_file.hpp" +#include "io_wave.hpp" + #include "rtc_time.hpp" #include "string_format.hpp" @@ -32,134 +34,6 @@ using namespace portapack; #include -class FileWriter : public Writer { -public: - FileWriter() = default; - - FileWriter(const FileWriter&) = delete; - FileWriter& operator=(const FileWriter&) = delete; - FileWriter(FileWriter&& file) = delete; - FileWriter& operator=(FileWriter&&) = delete; - - Optional create(const std::filesystem::path& filename) { - return file.create(filename); - } - - File::Result write(const void* const buffer, const File::Size bytes) override { - auto write_result = file.write(buffer, bytes) ; - if( write_result.is_ok() ) { - bytes_written += write_result.value(); - } - return write_result; - } - -protected: - File file; - uint64_t bytes_written { 0 }; -}; - -using RawFileWriter = FileWriter; - -class WAVFileWriter : public FileWriter { -public: - WAVFileWriter( - size_t sampling_rate - ) : header { sampling_rate } - { - } - - - WAVFileWriter(const WAVFileWriter&) = delete; - WAVFileWriter& operator=(const WAVFileWriter&) = delete; - WAVFileWriter(WAVFileWriter&&) = delete; - WAVFileWriter& operator=(WAVFileWriter&&) = delete; - - ~WAVFileWriter() { - update_header(); - } - - Optional create( - const std::filesystem::path& filename - ) { - const auto create_error = FileWriter::create(filename); - if( create_error.is_valid() ) { - return create_error; - } else { - return update_header(); - } - } - -private: - struct fmt_pcm_t { - constexpr fmt_pcm_t( - const uint32_t sampling_rate - ) : nSamplesPerSec { sampling_rate }, - nAvgBytesPerSec { nSamplesPerSec * nBlockAlign } - { - } - - private: - const uint8_t ckID[4] { 'f', 'm', 't', ' ' }; - const uint32_t cksize { 16 }; - const uint16_t wFormatTag { 0x0001 }; - const uint16_t nChannels { 1 }; - const uint32_t nSamplesPerSec; - const uint32_t nAvgBytesPerSec; - const uint16_t nBlockAlign { 2 }; - const uint16_t wBitsPerSample { 16 }; - }; - - struct data_t { - void set_size(const uint32_t value) { - cksize = value; - } - - private: - const uint8_t ckID[4] { 'd', 'a', 't', 'a' }; - uint32_t cksize { 0 }; - }; - - struct header_t { - constexpr header_t( - const uint32_t sampling_rate - ) : fmt { sampling_rate } - { - } - - void set_data_size(const uint32_t value) { - data.set_size(value); - cksize = sizeof(header_t) + value - 8; - } - - private: - const uint8_t riff_id[4] { 'R', 'I', 'F', 'F' }; - uint32_t cksize { 0 }; - const uint8_t wave_id[4] { 'W', 'A', 'V', 'E' }; - fmt_pcm_t fmt; - data_t data; - }; - - header_t header; - - Optional update_header() { - header.set_data_size(bytes_written); - const auto seek_0_result = file.seek(0); - if( seek_0_result.is_error() ) { - return seek_0_result.error(); - } - const auto old_position = seek_0_result.value(); - const auto write_result = file.write(&header, sizeof(header)); - if( write_result.is_error() ) { - return write_result.error(); - } - const auto seek_old_result = file.seek(old_position); - if( seek_old_result.is_error() ) { - return seek_old_result.error(); - } - return { }; - } -}; - namespace ui { RecordView::RecordView( From 1a2fd3e127045f2a5cb5ffe8f9317e78609b63db Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 09:59:47 -0700 Subject: [PATCH 062/100] Prepare WAV structures for extraction. --- firmware/application/io_wave.hpp | 56 ++++++++++++------------- firmware/application/ui_record_view.cpp | 6 +-- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/firmware/application/io_wave.hpp b/firmware/application/io_wave.hpp index 304d98e7..d315aadc 100644 --- a/firmware/application/io_wave.hpp +++ b/firmware/application/io_wave.hpp @@ -31,12 +31,7 @@ class WAVFileWriter : public FileWriter { public: - WAVFileWriter( - size_t sampling_rate - ) : header { sampling_rate } - { - } - + WAVFileWriter() = default; WAVFileWriter(const WAVFileWriter&) = delete; WAVFileWriter& operator=(const WAVFileWriter&) = delete; @@ -48,8 +43,10 @@ public: } Optional create( - const std::filesystem::path& filename + const std::filesystem::path& filename, + size_t sampling_rate ) { + sampling_rate = sampling_rate; const auto create_error = FileWriter::create(filename); if( create_error.is_valid() ) { return create_error; @@ -68,50 +65,51 @@ private: } private: - const uint8_t ckID[4] { 'f', 'm', 't', ' ' }; - const uint32_t cksize { 16 }; - const uint16_t wFormatTag { 0x0001 }; - const uint16_t nChannels { 1 }; - const uint32_t nSamplesPerSec; - const uint32_t nAvgBytesPerSec; - const uint16_t nBlockAlign { 2 }; - const uint16_t wBitsPerSample { 16 }; + uint8_t ckID[4] { 'f', 'm', 't', ' ' }; + uint32_t cksize { 16 }; + uint16_t wFormatTag { 0x0001 }; + uint16_t nChannels { 1 }; + uint32_t nSamplesPerSec; + uint32_t nAvgBytesPerSec; + uint16_t nBlockAlign { 2 }; + uint16_t wBitsPerSample { 16 }; }; struct data_t { - void set_size(const uint32_t value) { - cksize = value; + constexpr data_t( + const uint32_t size + ) : cksize { size } + { } private: - const uint8_t ckID[4] { 'd', 'a', 't', 'a' }; + uint8_t ckID[4] { 'd', 'a', 't', 'a' }; uint32_t cksize { 0 }; }; struct header_t { constexpr header_t( - const uint32_t sampling_rate - ) : fmt { sampling_rate } + const uint32_t sampling_rate, + const uint32_t data_chunk_size + ) : cksize { sizeof(header_t) + data_chunk_size - 8 }, + fmt { sampling_rate }, + data { data_chunk_size } { } - void set_data_size(const uint32_t value) { - data.set_size(value); - cksize = sizeof(header_t) + value - 8; - } - private: - const uint8_t riff_id[4] { 'R', 'I', 'F', 'F' }; + uint8_t riff_id[4] { 'R', 'I', 'F', 'F' }; uint32_t cksize { 0 }; - const uint8_t wave_id[4] { 'W', 'A', 'V', 'E' }; + uint8_t wave_id[4] { 'W', 'A', 'V', 'E' }; fmt_pcm_t fmt; data_t data; }; - header_t header; + uint32_t sampling_rate; + uint32_t bytes_written; Optional update_header() { - header.set_data_size(bytes_written); + header_t header { sampling_rate, bytes_written }; const auto seek_0_result = file.seek(0); if( seek_0_result.is_error() ) { return seek_0_result.error(); diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 60ff0ddb..48d48659 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -121,10 +121,8 @@ void RecordView::start() { switch(file_type) { case FileType::WAV: { - auto p = std::make_unique( - sampling_rate - ); - auto create_error = p->create(base_path.replace_extension(u".WAV")); + auto p = std::make_unique(); + auto create_error = p->create(base_path.replace_extension(u".WAV"), sampling_rate); if( create_error.is_valid() ) { handle_error(create_error.value()); } else { From 43c4584a3264cf52c929114dca0c0f25ce97d356 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 10:04:38 -0700 Subject: [PATCH 063/100] Move WAV structs outside of writer. --- firmware/application/io_wave.hpp | 98 ++++++++++++++++---------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/firmware/application/io_wave.hpp b/firmware/application/io_wave.hpp index d315aadc..186b2fb2 100644 --- a/firmware/application/io_wave.hpp +++ b/firmware/application/io_wave.hpp @@ -29,6 +29,55 @@ #include #include +struct fmt_pcm_t { + constexpr fmt_pcm_t( + const uint32_t sampling_rate + ) : nSamplesPerSec { sampling_rate }, + nAvgBytesPerSec { nSamplesPerSec * nBlockAlign } + { + } + +private: + uint8_t ckID[4] { 'f', 'm', 't', ' ' }; + uint32_t cksize { 16 }; + uint16_t wFormatTag { 0x0001 }; + uint16_t nChannels { 1 }; + uint32_t nSamplesPerSec; + uint32_t nAvgBytesPerSec; + uint16_t nBlockAlign { 2 }; + uint16_t wBitsPerSample { 16 }; +}; + +struct data_t { + constexpr data_t( + const uint32_t size + ) : cksize { size } + { + } + +private: + uint8_t ckID[4] { 'd', 'a', 't', 'a' }; + uint32_t cksize { 0 }; +}; + +struct header_t { + constexpr header_t( + const uint32_t sampling_rate, + const uint32_t data_chunk_size + ) : cksize { sizeof(header_t) + data_chunk_size - 8 }, + fmt { sampling_rate }, + data { data_chunk_size } + { + } + +private: + uint8_t riff_id[4] { 'R', 'I', 'F', 'F' }; + uint32_t cksize { 0 }; + uint8_t wave_id[4] { 'W', 'A', 'V', 'E' }; + fmt_pcm_t fmt; + data_t data; +}; + class WAVFileWriter : public FileWriter { public: WAVFileWriter() = default; @@ -56,55 +105,6 @@ public: } private: - struct fmt_pcm_t { - constexpr fmt_pcm_t( - const uint32_t sampling_rate - ) : nSamplesPerSec { sampling_rate }, - nAvgBytesPerSec { nSamplesPerSec * nBlockAlign } - { - } - - private: - uint8_t ckID[4] { 'f', 'm', 't', ' ' }; - uint32_t cksize { 16 }; - uint16_t wFormatTag { 0x0001 }; - uint16_t nChannels { 1 }; - uint32_t nSamplesPerSec; - uint32_t nAvgBytesPerSec; - uint16_t nBlockAlign { 2 }; - uint16_t wBitsPerSample { 16 }; - }; - - struct data_t { - constexpr data_t( - const uint32_t size - ) : cksize { size } - { - } - - private: - uint8_t ckID[4] { 'd', 'a', 't', 'a' }; - uint32_t cksize { 0 }; - }; - - struct header_t { - constexpr header_t( - const uint32_t sampling_rate, - const uint32_t data_chunk_size - ) : cksize { sizeof(header_t) + data_chunk_size - 8 }, - fmt { sampling_rate }, - data { data_chunk_size } - { - } - - private: - uint8_t riff_id[4] { 'R', 'I', 'F', 'F' }; - uint32_t cksize { 0 }; - uint8_t wave_id[4] { 'W', 'A', 'V', 'E' }; - fmt_pcm_t fmt; - data_t data; - }; - uint32_t sampling_rate; uint32_t bytes_written; From f3bfd50399be5068672542348c10e198aac8ad56 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 10:12:10 -0700 Subject: [PATCH 064/100] Move IO functions into .cpp files. --- firmware/application/CMakeLists.txt | 2 ++ firmware/application/io_file.cpp | 30 ++++++++++++++++ firmware/application/io_file.hpp | 10 ++---- firmware/application/io_wave.cpp | 53 +++++++++++++++++++++++++++++ firmware/application/io_wave.hpp | 28 ++------------- 5 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 firmware/application/io_file.cpp create mode 100644 firmware/application/io_wave.cpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index d481844f..2af3460e 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -175,6 +175,8 @@ set(CPPSRC log_file.cpp ${COMMON}/png_writer.cpp capture_thread.cpp + io_file.cpp + io_wave.cpp ${COMMON}/manchester.cpp string_format.cpp temperature_logger.cpp diff --git a/firmware/application/io_file.cpp b/firmware/application/io_file.cpp new file mode 100644 index 00000000..7daa75bc --- /dev/null +++ b/firmware/application/io_file.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "io_file.hpp" + +File::Result FileWriter::write(const void* const buffer, const File::Size bytes) { + auto write_result = file.write(buffer, bytes) ; + if( write_result.is_ok() ) { + bytes_written += write_result.value(); + } + return write_result; +} diff --git a/firmware/application/io_file.hpp b/firmware/application/io_file.hpp index 65f44826..f0647caf 100644 --- a/firmware/application/io_file.hpp +++ b/firmware/application/io_file.hpp @@ -41,14 +41,8 @@ public: return file.create(filename); } - File::Result write(const void* const buffer, const File::Size bytes) override { - auto write_result = file.write(buffer, bytes) ; - if( write_result.is_ok() ) { - bytes_written += write_result.value(); - } - return write_result; - } - + File::Result write(const void* const buffer, const File::Size bytes) override; + protected: File file; uint64_t bytes_written { 0 }; diff --git a/firmware/application/io_wave.cpp b/firmware/application/io_wave.cpp new file mode 100644 index 00000000..5222c3f9 --- /dev/null +++ b/firmware/application/io_wave.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "io_wave.hpp" + +Optional WAVFileWriter::create( + const std::filesystem::path& filename, + size_t sampling_rate +) { + sampling_rate = sampling_rate; + const auto create_error = FileWriter::create(filename); + if( create_error.is_valid() ) { + return create_error; + } else { + return update_header(); + } +} + +Optional WAVFileWriter::update_header() { + header_t header { sampling_rate, bytes_written }; + const auto seek_0_result = file.seek(0); + if( seek_0_result.is_error() ) { + return seek_0_result.error(); + } + const auto old_position = seek_0_result.value(); + const auto write_result = file.write(&header, sizeof(header)); + if( write_result.is_error() ) { + return write_result.error(); + } + const auto seek_old_result = file.seek(old_position); + if( seek_old_result.is_error() ) { + return seek_old_result.error(); + } + return { }; +} diff --git a/firmware/application/io_wave.hpp b/firmware/application/io_wave.hpp index 186b2fb2..e048be8e 100644 --- a/firmware/application/io_wave.hpp +++ b/firmware/application/io_wave.hpp @@ -94,35 +94,11 @@ public: Optional create( const std::filesystem::path& filename, size_t sampling_rate - ) { - sampling_rate = sampling_rate; - const auto create_error = FileWriter::create(filename); - if( create_error.is_valid() ) { - return create_error; - } else { - return update_header(); - } - } + ); private: uint32_t sampling_rate; uint32_t bytes_written; - Optional update_header() { - header_t header { sampling_rate, bytes_written }; - const auto seek_0_result = file.seek(0); - if( seek_0_result.is_error() ) { - return seek_0_result.error(); - } - const auto old_position = seek_0_result.value(); - const auto write_result = file.write(&header, sizeof(header)); - if( write_result.is_error() ) { - return write_result.error(); - } - const auto seek_old_result = file.seek(old_position); - if( seek_old_result.is_error() ) { - return seek_old_result.error(); - } - return { }; - } + Optional update_header(); }; From 01320d9806bb5de655d6148d04bcb889eb0973d1 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 17:04:49 -0700 Subject: [PATCH 065/100] Add a Reader interface. --- firmware/application/io.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/application/io.hpp b/firmware/application/io.hpp index 6333b001..8e21d19f 100644 --- a/firmware/application/io.hpp +++ b/firmware/application/io.hpp @@ -23,6 +23,12 @@ #include "file.hpp" +class Reader { +public: + virtual File::Result read(void* const buffer, const File::Size bytes) = 0; + virtual ~Reader() = default; +}; + class Writer { public: virtual File::Result write(const void* const buffer, const File::Size bytes) = 0; From a5793b8b9d0b9558a171866807372649e45f2e1d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 17:13:21 -0700 Subject: [PATCH 066/100] Put Reader, Writer inside "stream" namespace. --- firmware/application/capture_thread.cpp | 2 +- firmware/application/capture_thread.hpp | 4 ++-- firmware/application/io.hpp | 4 ++++ firmware/application/io_file.hpp | 2 +- firmware/application/ui_record_view.cpp | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/firmware/application/capture_thread.cpp b/firmware/application/capture_thread.cpp index 4de5cd53..a5751ac7 100644 --- a/firmware/application/capture_thread.cpp +++ b/firmware/application/capture_thread.cpp @@ -75,7 +75,7 @@ StreamOutput::~StreamOutput() { Thread* CaptureThread::thread = nullptr; CaptureThread::CaptureThread( - std::unique_ptr writer, + std::unique_ptr writer, size_t write_size, size_t buffer_count, std::function success_callback, diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index e867e4ec..01c45b2e 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -36,7 +36,7 @@ class CaptureThread { public: CaptureThread( - std::unique_ptr writer, + std::unique_ptr writer, size_t write_size, size_t buffer_count, std::function success_callback, @@ -54,7 +54,7 @@ private: static constexpr auto event_mask_loop_wake = EVENT_MASK(0); CaptureConfig config; - std::unique_ptr writer; + std::unique_ptr writer; std::function success_callback; std::function error_callback; static Thread* thread; diff --git a/firmware/application/io.hpp b/firmware/application/io.hpp index 8e21d19f..5c29da9d 100644 --- a/firmware/application/io.hpp +++ b/firmware/application/io.hpp @@ -23,6 +23,8 @@ #include "file.hpp" +namespace stream { + class Reader { public: virtual File::Result read(void* const buffer, const File::Size bytes) = 0; @@ -34,3 +36,5 @@ public: virtual File::Result write(const void* const buffer, const File::Size bytes) = 0; virtual ~Writer() = default; }; + +} /* namespace stream */ diff --git a/firmware/application/io_file.hpp b/firmware/application/io_file.hpp index f0647caf..c9049dde 100644 --- a/firmware/application/io_file.hpp +++ b/firmware/application/io_file.hpp @@ -28,7 +28,7 @@ #include -class FileWriter : public Writer { +class FileWriter : public stream::Writer { public: FileWriter() = default; diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index 48d48659..d617ac39 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -117,7 +117,7 @@ void RecordView::start() { return; } - std::unique_ptr writer; + std::unique_ptr writer; switch(file_type) { case FileType::WAV: { From 2433ea30ad4175c47204ad676713a50cac4e49b8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 22:17:27 -0700 Subject: [PATCH 067/100] Generalize StreamOutput a bit. --- firmware/application/capture_thread.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/firmware/application/capture_thread.cpp b/firmware/application/capture_thread.cpp index a5751ac7..08af9e4a 100644 --- a/firmware/application/capture_thread.cpp +++ b/firmware/application/capture_thread.cpp @@ -30,19 +30,25 @@ public: StreamOutput(CaptureConfig* const config); ~StreamOutput(); - size_t available() { - return fifo_buffers_full->len(); + StreamBuffer* get_empty() { + StreamBuffer* p { nullptr }; + fifo_buffers_empty->out(p); + return p; } - StreamBuffer* get_buffer() { + bool put_empty(StreamBuffer* const p) { + p->empty(); + return fifo_buffers_empty->in(p); + } + + StreamBuffer* get_full() { StreamBuffer* p { nullptr }; fifo_buffers_full->out(p); return p; } - bool release_buffer(StreamBuffer* const p) { - p->empty(); - return fifo_buffers_empty->in(p); + bool put_full(StreamBuffer* const p) { + return fifo_buffers_full->in(p); } static FIFO* fifo_buffers_empty; @@ -126,13 +132,13 @@ Optional CaptureThread::run() { StreamOutput stream { &config }; while( !chThdShouldTerminate() ) { - if( stream.available() ) { - auto buffer = stream.get_buffer(); + auto buffer = stream.get_full(); + if( buffer ) { auto write_result = writer->write(buffer->data(), buffer->size()); if( write_result.is_error() ) { return write_result.error(); } - stream.release_buffer(buffer); + stream.put_empty(buffer); } else { chEvtWaitAny(event_mask_loop_wake); } From fadbbcc5816eeb35903aac595c196a9dd54790c4 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 22:17:57 -0700 Subject: [PATCH 068/100] Move buffer reset out of buffer exchange class. --- firmware/application/capture_thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/application/capture_thread.cpp b/firmware/application/capture_thread.cpp index 08af9e4a..c2fe4487 100644 --- a/firmware/application/capture_thread.cpp +++ b/firmware/application/capture_thread.cpp @@ -37,7 +37,6 @@ public: } bool put_empty(StreamBuffer* const p) { - p->empty(); return fifo_buffers_empty->in(p); } @@ -138,6 +137,7 @@ Optional CaptureThread::run() { if( write_result.is_error() ) { return write_result.error(); } + buffer->empty(); stream.put_empty(buffer); } else { chEvtWaitAny(event_mask_loop_wake); From 84334ef818653864b976d870eda0ada0194b37a8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 4 Oct 2016 22:52:12 -0700 Subject: [PATCH 069/100] Further generalize StreamOutput -> BufferExchange. --- firmware/application/capture_thread.cpp | 56 +++++++++++++------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/firmware/application/capture_thread.cpp b/firmware/application/capture_thread.cpp index c2fe4487..0ac35a60 100644 --- a/firmware/application/capture_thread.cpp +++ b/firmware/application/capture_thread.cpp @@ -23,55 +23,59 @@ #include "baseband_api.hpp" -// StreamOutput /////////////////////////////////////////////////////////// +// BufferExchange /////////////////////////////////////////////////////////// -class StreamOutput { +class BufferExchange { public: - StreamOutput(CaptureConfig* const config); - ~StreamOutput(); + BufferExchange(CaptureConfig* const config); + ~BufferExchange(); - StreamBuffer* get_empty() { +#if defined(LPC43XX_M0) + StreamBuffer* get() { StreamBuffer* p { nullptr }; - fifo_buffers_empty->out(p); + fifo_buffers_for_application->out(p); return p; } - bool put_empty(StreamBuffer* const p) { - return fifo_buffers_empty->in(p); + bool put(StreamBuffer* const p) { + return fifo_buffers_for_baseband->in(p); } +#endif - StreamBuffer* get_full() { +#if defined(LPC43XX_M4) + StreamBuffer* get() { StreamBuffer* p { nullptr }; - fifo_buffers_full->out(p); + fifo_buffers_for_baseband->out(p); return p; } - bool put_full(StreamBuffer* const p) { - return fifo_buffers_full->in(p); + bool put(StreamBuffer* const p) { + return fifo_buffers_for_application->in(p); } +#endif - static FIFO* fifo_buffers_empty; - static FIFO* fifo_buffers_full; + static FIFO* fifo_buffers_for_baseband; + static FIFO* fifo_buffers_for_application; private: CaptureConfig* const config; }; -FIFO* StreamOutput::fifo_buffers_empty = nullptr; -FIFO* StreamOutput::fifo_buffers_full = nullptr; +FIFO* BufferExchange::fifo_buffers_for_baseband = nullptr; +FIFO* BufferExchange::fifo_buffers_for_application = nullptr; -StreamOutput::StreamOutput( +BufferExchange::BufferExchange( CaptureConfig* const config ) : config { config } { baseband::capture_start(config); - fifo_buffers_empty = config->fifo_buffers_empty; - fifo_buffers_full = config->fifo_buffers_full; + fifo_buffers_for_baseband = config->fifo_buffers_empty; + fifo_buffers_for_application = config->fifo_buffers_full; } -StreamOutput::~StreamOutput() { - fifo_buffers_full = nullptr; - fifo_buffers_empty = nullptr; +BufferExchange::~BufferExchange() { + fifo_buffers_for_baseband = nullptr; + fifo_buffers_for_application = nullptr; baseband::capture_stop(); } @@ -106,7 +110,7 @@ CaptureThread::~CaptureThread() { void CaptureThread::check_fifo_isr() { // TODO: Prevent over-signalling by transmitting a set of // flags from the baseband core. - const auto fifo = StreamOutput::fifo_buffers_full; + const auto fifo = BufferExchange::fifo_buffers_for_application; if( fifo ) { if( !fifo->is_empty() ) { chEvtSignalI(thread, event_mask_loop_wake); @@ -128,17 +132,17 @@ msg_t CaptureThread::static_fn(void* arg) { } Optional CaptureThread::run() { - StreamOutput stream { &config }; + BufferExchange buffers { &config }; while( !chThdShouldTerminate() ) { - auto buffer = stream.get_full(); + auto buffer = buffers.get(); if( buffer ) { auto write_result = writer->write(buffer->data(), buffer->size()); if( write_result.is_error() ) { return write_result.error(); } buffer->empty(); - stream.put_empty(buffer); + buffers.put(buffer); } else { chEvtWaitAny(event_mask_loop_wake); } From 5dfb53263ac749605fb6745a1f41f0da6a4caeff Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 6 Oct 2016 13:38:56 -0700 Subject: [PATCH 070/100] Extract BufferExchange, simplify threading. --- firmware/application/CMakeLists.txt | 1 + firmware/application/capture_thread.cpp | 86 ++++------------------- firmware/application/capture_thread.hpp | 6 +- firmware/application/event_m0.cpp | 4 +- firmware/common/buffer_exchange.cpp | 54 +++++++++++++++ firmware/common/buffer_exchange.hpp | 91 +++++++++++++++++++++++++ 6 files changed, 161 insertions(+), 81 deletions(-) create mode 100644 firmware/common/buffer_exchange.cpp create mode 100644 firmware/common/buffer_exchange.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 2af3460e..81e1d4bd 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -174,6 +174,7 @@ set(CPPSRC file.cpp log_file.cpp ${COMMON}/png_writer.cpp + ${COMMON}/buffer_exchange.cpp capture_thread.cpp io_file.cpp io_wave.cpp diff --git a/firmware/application/capture_thread.cpp b/firmware/application/capture_thread.cpp index 0ac35a60..50558a44 100644 --- a/firmware/application/capture_thread.cpp +++ b/firmware/application/capture_thread.cpp @@ -22,67 +22,20 @@ #include "capture_thread.hpp" #include "baseband_api.hpp" +#include "buffer_exchange.hpp" -// BufferExchange /////////////////////////////////////////////////////////// - -class BufferExchange { -public: - BufferExchange(CaptureConfig* const config); - ~BufferExchange(); - -#if defined(LPC43XX_M0) - StreamBuffer* get() { - StreamBuffer* p { nullptr }; - fifo_buffers_for_application->out(p); - return p; +struct BasebandCapture { + BasebandCapture(CaptureConfig* const config) { + baseband::capture_start(config); } - bool put(StreamBuffer* const p) { - return fifo_buffers_for_baseband->in(p); + ~BasebandCapture() { + baseband::capture_stop(); } -#endif - -#if defined(LPC43XX_M4) - StreamBuffer* get() { - StreamBuffer* p { nullptr }; - fifo_buffers_for_baseband->out(p); - return p; - } - - bool put(StreamBuffer* const p) { - return fifo_buffers_for_application->in(p); - } -#endif - - static FIFO* fifo_buffers_for_baseband; - static FIFO* fifo_buffers_for_application; - -private: - CaptureConfig* const config; }; -FIFO* BufferExchange::fifo_buffers_for_baseband = nullptr; -FIFO* BufferExchange::fifo_buffers_for_application = nullptr; - -BufferExchange::BufferExchange( - CaptureConfig* const config -) : config { config } -{ - baseband::capture_start(config); - fifo_buffers_for_baseband = config->fifo_buffers_empty; - fifo_buffers_for_application = config->fifo_buffers_full; -} - -BufferExchange::~BufferExchange() { - fifo_buffers_for_baseband = nullptr; - fifo_buffers_for_application = nullptr; - baseband::capture_stop(); -} - // CaptureThread ////////////////////////////////////////////////////////// -Thread* CaptureThread::thread = nullptr; - CaptureThread::CaptureThread( std::unique_ptr writer, size_t write_size, @@ -101,23 +54,11 @@ CaptureThread::CaptureThread( CaptureThread::~CaptureThread() { if( thread ) { chThdTerminate(thread); - chEvtSignal(thread, event_mask_loop_wake); chThdWait(thread); thread = nullptr; } } -void CaptureThread::check_fifo_isr() { - // TODO: Prevent over-signalling by transmitting a set of - // flags from the baseband core. - const auto fifo = BufferExchange::fifo_buffers_for_application; - if( fifo ) { - if( !fifo->is_empty() ) { - chEvtSignalI(thread, event_mask_loop_wake); - } - } -} - msg_t CaptureThread::static_fn(void* arg) { auto obj = static_cast(arg); const auto error = obj->run(); @@ -132,20 +73,17 @@ msg_t CaptureThread::static_fn(void* arg) { } Optional CaptureThread::run() { + BasebandCapture capture { &config }; BufferExchange buffers { &config }; while( !chThdShouldTerminate() ) { auto buffer = buffers.get(); - if( buffer ) { - auto write_result = writer->write(buffer->data(), buffer->size()); - if( write_result.is_error() ) { - return write_result.error(); - } - buffer->empty(); - buffers.put(buffer); - } else { - chEvtWaitAny(event_mask_loop_wake); + auto write_result = writer->write(buffer->data(), buffer->size()); + if( write_result.is_error() ) { + return write_result.error(); } + buffer->empty(); + buffers.put(buffer); } return { }; diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index 01c45b2e..5a4398b0 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -48,16 +48,12 @@ public: return config; } - static void check_fifo_isr(); - private: - static constexpr auto event_mask_loop_wake = EVENT_MASK(0); - CaptureConfig config; std::unique_ptr writer; std::function success_callback; std::function error_callback; - static Thread* thread; + Thread* thread; static msg_t static_fn(void* arg); diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index a7fae4a3..bb32041c 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -31,7 +31,7 @@ #include "irq_controls.hpp" -#include "capture_thread.hpp" +#include "buffer_exchange.hpp" #include "ch.h" @@ -48,7 +48,7 @@ CH_IRQ_HANDLER(M4Core_IRQHandler) { CH_IRQ_PROLOGUE(); chSysLockFromIsr(); - CaptureThread::check_fifo_isr(); + BufferExchange::handle_isr(); EventDispatcher::check_fifo_isr(); chSysUnlockFromIsr(); diff --git a/firmware/common/buffer_exchange.cpp b/firmware/common/buffer_exchange.cpp new file mode 100644 index 00000000..37bc47f1 --- /dev/null +++ b/firmware/common/buffer_exchange.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "buffer_exchange.hpp" + +BufferExchange* BufferExchange::obj { nullptr }; + +BufferExchange::BufferExchange( + CaptureConfig* const config +) : config { config } +{ + obj = this; + fifo_buffers_for_baseband = config->fifo_buffers_empty; + fifo_buffers_for_application = config->fifo_buffers_full; +} + +BufferExchange::~BufferExchange() { + obj = nullptr; + fifo_buffers_for_baseband = nullptr; + fifo_buffers_for_application = nullptr; +} + +StreamBuffer* BufferExchange::get(FIFO* fifo) { + while(true) { + StreamBuffer* p { nullptr }; + fifo->out(p); + if( p ) { + return p; + } + + chSysLock(); + thread = chThdSelf(); + chSchGoSleepS(THD_STATE_SUSPENDED); + chSysUnlock(); + } +} diff --git a/firmware/common/buffer_exchange.hpp b/firmware/common/buffer_exchange.hpp new file mode 100644 index 00000000..091a6ea2 --- /dev/null +++ b/firmware/common/buffer_exchange.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "ch.h" + +#include "message.hpp" +#include "fifo.hpp" +#include "io.hpp" + +class BufferExchange { +public: + BufferExchange(CaptureConfig* const config); + ~BufferExchange(); + +#if defined(LPC43XX_M0) + bool empty() const { + return fifo_buffers_for_application->is_empty(); + } + + StreamBuffer* get() { + return get(fifo_buffers_for_application); + } + + bool put(StreamBuffer* const p) { + return fifo_buffers_for_baseband->in(p); + } +#endif + +#if defined(LPC43XX_M4) + bool empty() const { + return fifo_buffers_for_baseband->is_empty(); + } + + StreamBuffer* get() { + return get(fifo_buffers_for_baseband); + } + + bool put(StreamBuffer* const p) { + return fifo_buffers_for_application->in(p); + } +#endif + + static void handle_isr() { + if( obj ) { + obj->check_fifo_isr(); + } + } + +private: + CaptureConfig* const config; + FIFO* fifo_buffers_for_baseband; + FIFO* fifo_buffers_for_application; + Thread* thread; + static BufferExchange* obj; + + void check_fifo_isr() { + if( !empty() ) { + wakeup_isr(); + } + } + + void wakeup_isr() { + auto thread_tmp = thread; + if( thread_tmp ) { + thread = nullptr; + chSchReadyI(thread_tmp); + } + } + + StreamBuffer* get(FIFO* fifo); +}; From a33476259e07891b6abe02f161c08061d4bc697e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 24 Oct 2016 11:16:48 -0700 Subject: [PATCH 071/100] Create buffer.cpp, reduce #include dependencies and impl leakage. --- firmware/application/CMakeLists.txt | 1 + firmware/baseband/CMakeLists.txt | 1 + firmware/common/buffer.cpp | 36 +++++++++++++++++++++++++++++ firmware/common/buffer.hpp | 12 +--------- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 firmware/common/buffer.cpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 81e1d4bd..856ed999 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -130,6 +130,7 @@ set(CPPSRC rffc507x_spi.cpp max2837.cpp max5864.cpp + ${COMMON}/buffer.cpp debounce.cpp touch.cpp touch_adc.cpp diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index eade87c1..f029f7c0 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -106,6 +106,7 @@ set(CPPSRC baseband_dma.cpp ${COMMON}/baseband_sgpio.cpp ${COMMON}/portapack_shared_memory.cpp + ${COMMON}/buffer.cpp baseband_thread.cpp baseband_processor.cpp baseband_stats_collector.cpp diff --git a/firmware/common/buffer.cpp b/firmware/common/buffer.cpp new file mode 100644 index 00000000..344b91a4 --- /dev/null +++ b/firmware/common/buffer.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "buffer.hpp" + +#if defined(LPC43XX_M4) +#include "lpc43xx_m4.h" + +Timestamp Timestamp::now() { + // Code stolen from LPC43xx rtc_lld.c + Timestamp timestamp; + do { + timestamp.tv_time = LPC_RTC->CTIME0; + timestamp.tv_date = LPC_RTC->CTIME1; + } while( (timestamp.tv_time != LPC_RTC->CTIME0) || (timestamp.tv_date != LPC_RTC->CTIME1) ); + return timestamp; +} +#endif diff --git a/firmware/common/buffer.hpp b/firmware/common/buffer.hpp index 2b3d7170..8676f6f5 100644 --- a/firmware/common/buffer.hpp +++ b/firmware/common/buffer.hpp @@ -33,21 +33,11 @@ * a knot to tackle at the moment, though... */ #if defined(LPC43XX_M4) -#include "lpc43xx_m4.h" - struct Timestamp { uint32_t tv_date { 0 }; uint32_t tv_time { 0 }; - static Timestamp now() { - // Code stolen from LPC43xx rtc_lld.c - Timestamp timestamp; - do { - timestamp.tv_time = LPC_RTC->CTIME0; - timestamp.tv_date = LPC_RTC->CTIME1; - } while( (timestamp.tv_time != LPC_RTC->CTIME0) || (timestamp.tv_date != LPC_RTC->CTIME1) ); - return timestamp; - } + static Timestamp now(); }; #endif From 8c8678909b97cb0a2554fc423dc48c85e0db79dc Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 5 Nov 2016 09:39:12 -0700 Subject: [PATCH 072/100] Update CI ARM GCC toolchain to 5.4-2016q3. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c75d2be..363625ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,9 @@ notifications: - "Firmware download : https://portapack-h1-builds.s3.amazonaws.com/%{repository_slug}/%{build_number}/%{build_number}.1/build/firmware/portapack-h1-firmware-%{commit}.tar.bz2" before_script: - - wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2 + - wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q3-update/+download/gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2 - tar -xf /tmp/gcc-arm.tar.bz2 - - export PATH=$PWD/gcc-arm-none-eabi-5_4-2016q2/bin:$PATH + - export PATH=$PWD/gcc-arm-none-eabi-5_4-2016q3/bin:$PATH - export CC="arm-none-eabi-gcc" - export CXX="arm-none-eabi-g++" From 94528ea5729f4f4790243d1c4f74ff01e6111936 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 5 Nov 2016 10:40:05 -0700 Subject: [PATCH 073/100] Allow overriding baseband mcuconf.h M4 clock config. --- firmware/baseband/mcuconf.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/baseband/mcuconf.h b/firmware/baseband/mcuconf.h index eae37545..0accb63a 100755 --- a/firmware/baseband/mcuconf.h +++ b/firmware/baseband/mcuconf.h @@ -43,5 +43,10 @@ #define LPC43XX_M0APPTXEVENT_IRQ_PRIORITY 4 /* M4 is initialized by M0, which has already started PLL1 */ +#if !defined(LPC43XX_M4_CLK) || defined(__DOXYGEN__) #define LPC43XX_M4_CLK 200000000 -#define LPC43XX_M4_CLK_SRC 0x09 \ No newline at end of file +#endif + +#if !defined(LPC43XX_M4_CLK_SRC) || defined(__DOXYGEN__) +#define LPC43XX_M4_CLK_SRC 0x09 +#endif From 193bf0b744dd1c85b6651b3634b0abc13a249cf4 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 5 Nov 2016 10:40:58 -0700 Subject: [PATCH 074/100] Add "BASEBAND" path variable for CMake. --- firmware/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 2c338ce3..371d715b 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -20,6 +20,7 @@ project(firmware) +set(BASEBAND ${PROJECT_SOURCE_DIR}/baseband) set(COMMON ${PROJECT_SOURCE_DIR}/common) set(CHIBIOS ${PROJECT_SOURCE_DIR}/chibios) set(CHIBIOS_PORTAPACK ${PROJECT_SOURCE_DIR}/chibios-portapack) From 229616491c61bd3f06133f1a1b28a8b263bb32ca Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 26 Nov 2016 16:28:11 -0800 Subject: [PATCH 075/100] Enable Effective C++ and uninitialized members warnings. --- firmware/application/CMakeLists.txt | 2 +- firmware/baseband/CMakeLists.txt | 2 +- firmware/bootstrap/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 856ed999..d0860c15 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -35,7 +35,7 @@ set(USE_OPT "-Os -g --specs=nano.specs") set(USE_COPT "-std=gnu99") # C++ specific options here (added to USE_OPT). -set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions") +set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") # Enable this if you want the linker to remove unused code and data set(USE_LINK_GC yes) diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index f029f7c0..faf5c2cb 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -35,7 +35,7 @@ set(USE_OPT "-O3 -g -falign-functions=16 -fno-math-errno --specs=nano.specs") set(USE_COPT "-std=gnu99") # C++ specific options here (added to USE_OPT). -set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions") +set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") # Enable this if you want the linker to remove unused code and data set(USE_LINK_GC yes) diff --git a/firmware/bootstrap/CMakeLists.txt b/firmware/bootstrap/CMakeLists.txt index 7f837998..6756f5b0 100644 --- a/firmware/bootstrap/CMakeLists.txt +++ b/firmware/bootstrap/CMakeLists.txt @@ -35,7 +35,7 @@ set(USE_OPT "-Os -g -falign-functions=16 -fno-math-errno --specs=nano.specs") set(USE_COPT "-std=gnu99") # C++ specific options here (added to USE_OPT). -set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions") +set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") # Enable this if you want the linker to remove unused code and data set(USE_LINK_GC yes) From cd31ae86d72a06958a04cc4d84cd5e2e39c9c778 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 26 Nov 2016 16:42:03 -0800 Subject: [PATCH 076/100] Add single-arg constructor for vec2_s16. --- firmware/common/simd.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/common/simd.hpp b/firmware/common/simd.hpp index 0d65b8dd..c2e9be95 100644 --- a/firmware/common/simd.hpp +++ b/firmware/common/simd.hpp @@ -41,6 +41,12 @@ struct vec2_s16 { { } + constexpr vec2_s16( + const int16_t v + ) : v { v, v } + { + } + constexpr vec2_s16( const int16_t v0, const int16_t v1 From 4eb0facacb891b758f5457c7cec3660155a290c4 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 26 Nov 2016 16:50:44 -0800 Subject: [PATCH 077/100] Add lots of value constructors. --- firmware/application/ais_app.hpp | 19 +++++----- firmware/application/analog_audio_app.hpp | 4 +-- firmware/application/capture_app.hpp | 2 +- firmware/application/capture_thread.hpp | 2 +- firmware/application/dirty_registers.hpp | 2 +- firmware/application/ert_app.hpp | 8 ++--- firmware/application/event_m0.cpp | 2 +- firmware/application/event_m0.hpp | 2 +- firmware/application/file.hpp | 13 +++---- firmware/application/io_file.hpp | 2 +- firmware/application/io_wave.hpp | 4 +-- firmware/application/log_file.hpp | 2 +- firmware/application/max2837.hpp | 2 +- firmware/application/recent_entries.hpp | 4 +-- firmware/application/rffc507x.hpp | 4 +-- firmware/application/signal.hpp | 2 +- firmware/application/temperature_logger.hpp | 2 +- firmware/application/touch.hpp | 22 +++++------- firmware/application/tpms_app.hpp | 12 +++---- firmware/application/ui_debug.hpp | 2 +- firmware/application/ui_menu.hpp | 2 +- firmware/application/ui_navigation.hpp | 12 +++---- firmware/application/ui_receiver.hpp | 26 +++++++------- firmware/application/ui_record_view.hpp | 6 ++-- firmware/application/ui_sd_card_debug.cpp | 2 +- firmware/application/ui_sd_card_debug.hpp | 2 +- .../application/ui_sd_card_status_view.hpp | 2 +- firmware/application/ui_spectrum.hpp | 4 +-- firmware/application/ui_touch_calibration.hpp | 4 +-- firmware/baseband/audio_output.hpp | 10 +++--- firmware/baseband/audio_stats_collector.hpp | 2 +- firmware/baseband/baseband_processor.hpp | 2 +- firmware/baseband/baseband_thread.hpp | 4 +-- firmware/baseband/block_decimator.hpp | 2 +- firmware/baseband/channel_decimator.hpp | 24 +++++-------- firmware/baseband/clock_recovery.hpp | 8 ++--- firmware/baseband/dsp_decimate.hpp | 35 ++++++++----------- firmware/baseband/matched_filter.hpp | 4 +-- firmware/baseband/packet_builder.hpp | 10 +++--- firmware/baseband/proc_ais.hpp | 8 ++--- firmware/baseband/proc_am_audio.hpp | 22 ++++++------ firmware/baseband/proc_capture.hpp | 10 +++--- firmware/baseband/proc_nfm_audio.hpp | 16 ++++----- firmware/baseband/proc_tpms.hpp | 6 ++-- firmware/baseband/proc_wfm_audio.hpp | 18 +++++----- firmware/baseband/proc_wideband_spectrum.hpp | 4 +-- firmware/baseband/rssi_stats_collector.hpp | 2 +- firmware/baseband/spectrum_collector.hpp | 14 +++----- firmware/baseband/stream_input.hpp | 8 ++--- firmware/common/baseband_packet.hpp | 2 +- firmware/common/buffer_exchange.hpp | 6 ++-- firmware/common/message_queue.hpp | 2 +- firmware/common/png_writer.hpp | 4 +-- firmware/common/ui_widget.hpp | 16 ++++----- 54 files changed, 194 insertions(+), 217 deletions(-) diff --git a/firmware/application/ais_app.hpp b/firmware/application/ais_app.hpp index 2e26d2ab..ba95e70b 100644 --- a/firmware/application/ais_app.hpp +++ b/firmware/application/ais_app.hpp @@ -49,8 +49,8 @@ using namespace lpc43xx; struct AISPosition { rtc::RTC timestamp { }; - ais::Latitude latitude; - ais::Longitude longitude; + ais::Latitude latitude { }; + ais::Longitude longitude { }; ais::RateOfTurn rate_of_turn { -128 }; ais::SpeedOverGround speed_over_ground { 1023 }; ais::CourseOverGround course_over_ground { 3600 }; @@ -78,6 +78,9 @@ struct AISRecentEntry { AISRecentEntry( const ais::MMSI& mmsi ) : mmsi { mmsi }, + name { }, + call_sign { }, + destination { }, last_position { }, received_count { 0 }, navigational_status { -1 } @@ -102,7 +105,7 @@ public: void on_packet(const ais::Packet& packet); private: - LogFile log_file; + LogFile log_file { }; }; namespace ui { @@ -111,7 +114,7 @@ using AISRecentEntriesView = RecentEntriesView; class AISRecentEntryDetailView : public View { public: - std::function on_close; + std::function on_close { }; AISRecentEntryDetailView(); @@ -122,7 +125,7 @@ public: void paint(Painter&) override; private: - AISRecentEntry entry_; + AISRecentEntry entry_ { }; Button button_done { { 72, 216, 96, 24 }, @@ -158,15 +161,15 @@ private: static constexpr uint32_t sampling_rate = 2457600; static constexpr uint32_t baseband_bandwidth = 1750000; - AISRecentEntries recent; - std::unique_ptr logger; + AISRecentEntries recent { }; + std::unique_ptr logger { }; const RecentEntriesColumns columns { { { "MMSI", 9 }, { "Name/Call", 20 }, } }; AISRecentEntriesView recent_entries_view { columns, recent }; - AISRecentEntryDetailView recent_entry_detail_view; + AISRecentEntryDetailView recent_entry_detail_view { }; static constexpr auto header_height = 1 * 16; diff --git a/firmware/application/analog_audio_app.hpp b/firmware/application/analog_audio_app.hpp index 697a199a..566b63d9 100644 --- a/firmware/application/analog_audio_app.hpp +++ b/firmware/application/analog_audio_app.hpp @@ -139,14 +139,14 @@ private: ' ', }; - std::unique_ptr options_widget; + std::unique_ptr options_widget { }; RecordView record_view { { 0 * 8, 2 * 16, 30 * 8, 1 * 16 }, u"AUD_????", RecordView::FileType::WAV, 4096, 4 }; - spectrum::WaterfallWidget waterfall; + spectrum::WaterfallWidget waterfall { }; void on_tuning_frequency_changed(rf::Frequency f); void on_baseband_bandwidth_changed(uint32_t bandwidth_hz); diff --git a/firmware/application/capture_app.hpp b/firmware/application/capture_app.hpp index 76d287f0..7764c76b 100644 --- a/firmware/application/capture_app.hpp +++ b/firmware/application/capture_app.hpp @@ -92,7 +92,7 @@ private: u"BBD_????", RecordView::FileType::RawS16, 16384, 3 }; - spectrum::WaterfallWidget waterfall; + spectrum::WaterfallWidget waterfall { }; }; } /* namespace ui */ diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index 5a4398b0..218a2867 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -53,7 +53,7 @@ private: std::unique_ptr writer; std::function success_callback; std::function error_callback; - Thread* thread; + Thread* thread { nullptr }; static msg_t static_fn(void* arg); diff --git a/firmware/application/dirty_registers.hpp b/firmware/application/dirty_registers.hpp index cde1914c..e2143ab2 100644 --- a/firmware/application/dirty_registers.hpp +++ b/firmware/application/dirty_registers.hpp @@ -58,7 +58,7 @@ public: } private: - mask_t mask; + mask_t mask { }; }; #endif/*__DIRTY_REGISTERS_H__*/ diff --git a/firmware/application/ert_app.hpp b/firmware/application/ert_app.hpp index 6a774ede..d7488860 100644 --- a/firmware/application/ert_app.hpp +++ b/firmware/application/ert_app.hpp @@ -72,7 +72,7 @@ struct ERTRecentEntry { size_t received_count { 0 }; - ert::Consumption last_consumption; + ert::Consumption last_consumption { }; ERTRecentEntry( const Key& key @@ -97,7 +97,7 @@ public: void on_packet(const ert::Packet& packet); private: - LogFile log_file; + LogFile log_file { }; }; using ERTRecentEntries = RecentEntries; @@ -126,8 +126,8 @@ public: std::string title() const override { return "ERT"; }; private: - ERTRecentEntries recent; - std::unique_ptr logger; + ERTRecentEntries recent { }; + std::unique_ptr logger { }; const RecentEntriesColumns columns { { { "ID", 10 }, diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index bb32041c..8c35a523 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -85,7 +85,7 @@ public: private: using MapType = std::array; - MapType map_; + MapType map_ { }; }; static MessageHandlerMap message_map; diff --git a/firmware/application/event_m0.hpp b/firmware/application/event_m0.hpp index f89f0b75..f8442106 100644 --- a/firmware/application/event_m0.hpp +++ b/firmware/application/event_m0.hpp @@ -94,7 +94,7 @@ private: static Thread* thread_event_loop; - touch::Manager touch_manager; + touch::Manager touch_manager { }; ui::Widget* const top_widget; ui::Painter painter; ui::Context& context; diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 57e63fd9..4c59f7f0 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -37,10 +37,7 @@ namespace std { namespace filesystem { struct filesystem_error { - constexpr filesystem_error( - ) : err { FR_OK } - { - } + constexpr filesystem_error() = default; constexpr filesystem_error( FRESULT fatfs_error @@ -61,7 +58,7 @@ struct filesystem_error { std::string what() const; private: - uint32_t err; + uint32_t err { FR_OK }; }; struct path { @@ -196,8 +193,8 @@ class directory_iterator { } }; - std::shared_ptr impl; - const path pattern; + std::shared_ptr impl { }; + const path pattern { }; friend bool operator!=(const directory_iterator& lhs, const directory_iterator& rhs); @@ -320,7 +317,7 @@ public: Optional sync(); private: - FIL f; + FIL f { }; Optional open_fatfs(const std::filesystem::path& filename, BYTE mode); }; diff --git a/firmware/application/io_file.hpp b/firmware/application/io_file.hpp index c9049dde..a71b1afa 100644 --- a/firmware/application/io_file.hpp +++ b/firmware/application/io_file.hpp @@ -44,7 +44,7 @@ public: File::Result write(const void* const buffer, const File::Size bytes) override; protected: - File file; + File file { }; uint64_t bytes_written { 0 }; }; diff --git a/firmware/application/io_wave.hpp b/firmware/application/io_wave.hpp index e048be8e..13b3a432 100644 --- a/firmware/application/io_wave.hpp +++ b/firmware/application/io_wave.hpp @@ -97,8 +97,8 @@ public: ); private: - uint32_t sampling_rate; - uint32_t bytes_written; + uint32_t sampling_rate { 0 }; + uint32_t bytes_written { 0 }; Optional update_header(); }; diff --git a/firmware/application/log_file.hpp b/firmware/application/log_file.hpp index 5f222a79..01861c1b 100644 --- a/firmware/application/log_file.hpp +++ b/firmware/application/log_file.hpp @@ -38,7 +38,7 @@ public: Optional write_entry(const rtc::RTC& datetime, const std::string& entry); private: - File file; + File file { }; Optional write_line(const std::string& message); }; diff --git a/firmware/application/max2837.hpp b/firmware/application/max2837.hpp index 3f1beb70..20d319a8 100644 --- a/firmware/application/max2837.hpp +++ b/firmware/application/max2837.hpp @@ -897,7 +897,7 @@ private: spi::arbiter::Target& _target; RegisterMap _map { initial_register_values }; - DirtyRegisters _dirty; + DirtyRegisters _dirty { }; void flush_one(const Register reg); diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 568f5e6c..2af1e485 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -127,7 +127,7 @@ class RecentEntriesTable : public Widget { public: using Entry = typename Entries::value_type; - std::function on_select; + std::function on_select { }; RecentEntriesTable( Entries& recent @@ -231,7 +231,7 @@ class RecentEntriesView : public View { public: using Entry = typename Entries::value_type; - std::function on_select; + std::function on_select { }; RecentEntriesView( const RecentEntriesColumns& columns, diff --git a/firmware/application/rffc507x.hpp b/firmware/application/rffc507x.hpp index 016f0f11..e6c903a9 100644 --- a/firmware/application/rffc507x.hpp +++ b/firmware/application/rffc507x.hpp @@ -813,10 +813,10 @@ public: reg_t read(const address_t reg_num); private: - spi::SPI _bus; + spi::SPI _bus { }; RegisterMap _map { default_hackrf_one }; - DirtyRegisters _dirty; + DirtyRegisters _dirty { }; void write(const address_t reg_num, const reg_t value); diff --git a/firmware/application/signal.hpp b/firmware/application/signal.hpp index 09baf777..262e4798 100644 --- a/firmware/application/signal.hpp +++ b/firmware/application/signal.hpp @@ -78,7 +78,7 @@ private: using EntryType = std::unique_ptr; - std::list entries; + std::list entries { }; SignalToken next_token = 1; }; diff --git a/firmware/application/temperature_logger.hpp b/firmware/application/temperature_logger.hpp index 51f8e451..01f6715c 100644 --- a/firmware/application/temperature_logger.hpp +++ b/firmware/application/temperature_logger.hpp @@ -39,7 +39,7 @@ public: std::vector history() const; private: - std::array samples; + std::array samples { }; static constexpr size_t sample_interval = 5; size_t sample_phase = 0; diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp index bc451e36..0c421f7d 100644 --- a/firmware/application/touch.hpp +++ b/firmware/application/touch.hpp @@ -154,13 +154,7 @@ const Calibration default_calibration(); template class Filter { public: - constexpr Filter( - ) : history(), - history_history { 0 }, - accumulator { 0 }, - n { 0 } - { - } + constexpr Filter() = default; void reset() { history.fill(0); @@ -196,10 +190,10 @@ public: private: static constexpr uint32_t history_history_mask { (1U << N) - 1 }; - std::array history; - uint32_t history_history; - uint32_t accumulator; - size_t n; + std::array history { }; + uint32_t history_history { 0 }; + uint32_t accumulator { 0 }; + size_t n { 0 }; bool history_valid() const { return (history_history & history_history_mask) == history_history_mask; @@ -208,7 +202,7 @@ private: class Manager { public: - std::function on_event; + std::function on_event { }; void feed(const Frame& frame); @@ -224,8 +218,8 @@ private: // Ensure filter length is equal or less than touch_count_threshold, // or coordinates from the last touch will be in the initial averages. - Filter filter_x; - Filter filter_y; + Filter filter_x { }; + Filter filter_y { }; //Debounce touch_debounce; diff --git a/firmware/application/tpms_app.hpp b/firmware/application/tpms_app.hpp index 771efd7f..ee17c6eb 100644 --- a/firmware/application/tpms_app.hpp +++ b/firmware/application/tpms_app.hpp @@ -54,9 +54,9 @@ struct TPMSRecentEntry { size_t received_count { 0 }; - Optional last_pressure; - Optional last_temperature; - Optional last_flags; + Optional last_pressure { }; + Optional last_temperature { }; + Optional last_flags { }; TPMSRecentEntry( const Key& key @@ -83,7 +83,7 @@ public: void on_packet(const tpms::Packet& packet, const uint32_t target_frequency); private: - LogFile log_file; + LogFile log_file { }; }; namespace ui { @@ -150,8 +150,8 @@ private: { 18 * 8, 0 * 16 } }; - TPMSRecentEntries recent; - std::unique_ptr logger; + TPMSRecentEntries recent { }; + std::unique_ptr logger { }; const RecentEntriesColumns columns { { { "Tp", 2 }, diff --git a/firmware/application/ui_debug.hpp b/firmware/application/ui_debug.hpp index e6297c14..33108dcc 100644 --- a/firmware/application/ui_debug.hpp +++ b/firmware/application/ui_debug.hpp @@ -193,7 +193,7 @@ public: void focus(); private: - Text text_title; + Text text_title { }; RegistersWidget registers_widget; diff --git a/firmware/application/ui_menu.hpp b/firmware/application/ui_menu.hpp index 7d10dbf6..d3f9c1e6 100644 --- a/firmware/application/ui_menu.hpp +++ b/firmware/application/ui_menu.hpp @@ -61,7 +61,7 @@ private: class MenuView : public View { public: - std::function on_left; + std::function on_left { }; MenuView() { set_focusable(true); diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 65fcf2fe..9e3c7df2 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -41,7 +41,7 @@ namespace ui { class SystemStatusView : public View { public: - std::function on_back; + std::function on_back { }; SystemStatusView(); @@ -86,9 +86,9 @@ private: class NavigationView : public View { public: - std::function on_view_changed; + std::function on_view_changed { }; - NavigationView() { } + NavigationView() = default; NavigationView(const NavigationView&) = delete; NavigationView(NavigationView&&) = delete; @@ -107,7 +107,7 @@ public: void focus() override; private: - std::vector> view_stack; + std::vector> view_stack { }; Widget* modal_view { nullptr }; Widget* view() const; @@ -142,8 +142,8 @@ public: Context& context() const override; private: - SystemStatusView status_view; - NavigationView navigation_view; + SystemStatusView status_view { }; + NavigationView navigation_view { }; Context& context_; }; diff --git a/firmware/application/ui_receiver.hpp b/firmware/application/ui_receiver.hpp index eb012f4d..162e5d2c 100644 --- a/firmware/application/ui_receiver.hpp +++ b/firmware/application/ui_receiver.hpp @@ -38,9 +38,9 @@ namespace ui { class FrequencyField : public Widget { public: - std::function on_change; - std::function on_edit; - std::function on_show_options; + std::function on_change { }; + std::function on_edit { }; + std::function on_show_options { }; using range_t = rf::FrequencyRange; @@ -61,7 +61,7 @@ public: private: const size_t length_; const range_t range; - rf::Frequency value_; + rf::Frequency value_ { 0 }; rf::Frequency step { 25000 }; rf::Frequency clamp_value(rf::Frequency value); @@ -135,8 +135,8 @@ public: private: using array_type = std::array; - array_type s; - Justify justify; + array_type s { }; + Justify justify { Justify::Left }; template void remove_zeros(Iterator begin, Iterator end) { @@ -174,7 +174,7 @@ private: class FrequencyKeypadView : public View { public: - std::function on_changed; + std::function on_changed { }; FrequencyKeypadView( NavigationView& nav, @@ -201,7 +201,7 @@ private: { 0, 0, text_digits * button_w, button_h } }; - std::array buttons; + std::array buttons { }; Button button_close { { 0, button_h * 4 + button_h, button_w * 3, button_h }, @@ -257,8 +257,8 @@ public: class FrequencyOptionsView : public View { public: - std::function on_change_step; - std::function on_change_reference_ppm_correction; + std::function on_change_step { }; + std::function on_change_reference_ppm_correction { }; FrequencyOptionsView(const Rect parent_rect, const Style* const style); @@ -314,7 +314,7 @@ private: class LNAGainField : public NumberField { public: - std::function on_show_options; + std::function on_show_options { }; LNAGainField(Point parent_pos); @@ -323,7 +323,7 @@ public: class VGAGainField : public NumberField { public: - std::function on_show_options; + std::function on_show_options { }; VGAGainField(Point parent_pos); @@ -332,7 +332,7 @@ public: class TXGainField : public NumberField { public: - std::function on_show_options; + std::function on_show_options { }; TXGainField(Point parent_pos); diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index 203d334c..7564d798 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -37,7 +37,7 @@ namespace ui { class RecordView : public View { public: - std::function on_error; + std::function on_error { }; enum FileType { RawS16 = 2, @@ -77,7 +77,7 @@ private: const size_t write_size; const size_t buffer_count; size_t sampling_rate { 0 }; - SignalToken signal_token_tick_second; + SignalToken signal_token_tick_second { }; Rectangle rect_background { Color::black() @@ -105,7 +105,7 @@ private: "", }; - std::unique_ptr capture_thread; + std::unique_ptr capture_thread { }; MessageHandlerRegistration message_handler_capture_thread_error { Message::ID::CaptureThreadDone, diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index 12dc5293..74367210 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -86,7 +86,7 @@ private: static Thread* thread; volatile Result _result { Result::Incomplete }; - Stats _stats; + Stats _stats { }; static msg_t static_fn(void* arg) { auto obj = static_cast(arg); diff --git a/firmware/application/ui_sd_card_debug.hpp b/firmware/application/ui_sd_card_debug.hpp index d051fd3c..170c2a68 100644 --- a/firmware/application/ui_sd_card_debug.hpp +++ b/firmware/application/ui_sd_card_debug.hpp @@ -39,7 +39,7 @@ public: void focus() override; private: - SignalToken sd_card_status_signal_token; + SignalToken sd_card_status_signal_token { }; void on_status(const sd_card::Status status); void on_test(); diff --git a/firmware/application/ui_sd_card_status_view.hpp b/firmware/application/ui_sd_card_status_view.hpp index 31388cfa..9e68c91f 100644 --- a/firmware/application/ui_sd_card_status_view.hpp +++ b/firmware/application/ui_sd_card_status_view.hpp @@ -37,7 +37,7 @@ public: void paint(Painter& painter) override; private: - SignalToken sd_card_status_signal_token; + SignalToken sd_card_status_signal_token { }; void on_status(const sd_card::Status status); }; diff --git a/firmware/application/ui_spectrum.hpp b/firmware/application/ui_spectrum.hpp index 70fe83d5..cbf45644 100644 --- a/firmware/application/ui_spectrum.hpp +++ b/firmware/application/ui_spectrum.hpp @@ -84,8 +84,8 @@ public: void paint(Painter& painter) override; private: - WaterfallView waterfall_view; - FrequencyScale frequency_scale; + WaterfallView waterfall_view { }; + FrequencyScale frequency_scale { }; ChannelSpectrumFIFO* fifo { nullptr }; MessageHandlerRegistration message_handler_spectrum_config { diff --git a/firmware/application/ui_touch_calibration.hpp b/firmware/application/ui_touch_calibration.hpp index 40329020..c9a17aed 100644 --- a/firmware/application/ui_touch_calibration.hpp +++ b/firmware/application/ui_touch_calibration.hpp @@ -65,9 +65,9 @@ private: uint32_t samples_count { 0 }; - touch::DigitizerPoint average; + touch::DigitizerPoint average { }; - std::array digitizer_points; + std::array digitizer_points { }; touch::Calibration calibration; diff --git a/firmware/baseband/audio_output.hpp b/firmware/baseband/audio_output.hpp index 6462e061..21d19f8d 100644 --- a/firmware/baseband/audio_output.hpp +++ b/firmware/baseband/audio_output.hpp @@ -55,13 +55,13 @@ private: BlockDecimator block_buffer { 1 }; - IIRBiquadFilter hpf; - IIRBiquadFilter deemph; - FMSquelch squelch; + IIRBiquadFilter hpf { }; + IIRBiquadFilter deemph { }; + FMSquelch squelch { }; - std::unique_ptr stream; + std::unique_ptr stream { }; - AudioStatsCollector audio_stats; + AudioStatsCollector audio_stats { }; uint64_t audio_present_history = 0; diff --git a/firmware/baseband/audio_stats_collector.hpp b/firmware/baseband/audio_stats_collector.hpp index 10e17edc..9eddfd88 100644 --- a/firmware/baseband/audio_stats_collector.hpp +++ b/firmware/baseband/audio_stats_collector.hpp @@ -50,7 +50,7 @@ private: float max_squared { 0 }; size_t count { 0 }; - AudioStatistics statistics; + AudioStatistics statistics { }; void consume_audio_buffer(const buffer_f32_t& src); diff --git a/firmware/baseband/baseband_processor.hpp b/firmware/baseband/baseband_processor.hpp index 28ef5063..074853b2 100644 --- a/firmware/baseband/baseband_processor.hpp +++ b/firmware/baseband/baseband_processor.hpp @@ -40,7 +40,7 @@ protected: void feed_channel_stats(const buffer_c16_t& channel); private: - ChannelStatsCollector channel_stats; + ChannelStatsCollector channel_stats { }; }; #endif/*__BASEBAND_PROCESSOR_H__*/ diff --git a/firmware/baseband/baseband_thread.hpp b/firmware/baseband/baseband_thread.hpp index 4d06e326..ce05dec7 100644 --- a/firmware/baseband/baseband_thread.hpp +++ b/firmware/baseband/baseband_thread.hpp @@ -48,8 +48,8 @@ private: static Thread* thread; BasebandProcessor* baseband_processor { nullptr }; - baseband::Direction _direction; - uint32_t sampling_rate; + baseband::Direction _direction { baseband::Direction::Receive }; + uint32_t sampling_rate { 0 }; void run() override; }; diff --git a/firmware/baseband/block_decimator.hpp b/firmware/baseband/block_decimator.hpp index 7782dc37..a3a771c4 100644 --- a/firmware/baseband/block_decimator.hpp +++ b/firmware/baseband/block_decimator.hpp @@ -85,7 +85,7 @@ public: } private: - std::array buffer; + std::array buffer { }; uint32_t input_sampling_rate_ { 0 }; size_t factor_ { 1 }; size_t src_i { 0 }; diff --git a/firmware/baseband/channel_decimator.hpp b/firmware/baseband/channel_decimator.hpp index 956964b0..4b527ee2 100644 --- a/firmware/baseband/channel_decimator.hpp +++ b/firmware/baseband/channel_decimator.hpp @@ -38,12 +38,6 @@ public: By16, By32, }; - - constexpr ChannelDecimator( - ) : decimation_factor { DecimationFactor::By32 }, - fs_over_4_downconvert { true } - { - } constexpr ChannelDecimator( const DecimationFactor decimation_factor, @@ -64,17 +58,17 @@ public: } private: - std::array work_baseband; + std::array work_baseband { }; - dsp::decimate::TranslateByFSOver4AndDecimateBy2CIC3 translate; - dsp::decimate::Complex8DecimateBy2CIC3 cic_0; - dsp::decimate::DecimateBy2CIC3 cic_1; - dsp::decimate::DecimateBy2CIC3 cic_2; - dsp::decimate::DecimateBy2CIC3 cic_3; - dsp::decimate::DecimateBy2CIC3 cic_4; + dsp::decimate::TranslateByFSOver4AndDecimateBy2CIC3 translate { }; + dsp::decimate::Complex8DecimateBy2CIC3 cic_0 { }; + dsp::decimate::DecimateBy2CIC3 cic_1 { }; + dsp::decimate::DecimateBy2CIC3 cic_2 { }; + dsp::decimate::DecimateBy2CIC3 cic_3 { }; + dsp::decimate::DecimateBy2CIC3 cic_4 { }; - DecimationFactor decimation_factor; - const bool fs_over_4_downconvert; + DecimationFactor decimation_factor { DecimationFactor::By32 }; + const bool fs_over_4_downconvert { true }; buffer_c16_t execute_decimation(const buffer_c8_t& buffer); diff --git a/firmware/baseband/clock_recovery.hpp b/firmware/baseband/clock_recovery.hpp index 9a6904a3..70d7f003 100644 --- a/firmware/baseband/clock_recovery.hpp +++ b/firmware/baseband/clock_recovery.hpp @@ -60,7 +60,7 @@ public: } private: - std::array t { { 0.0f, 0.0f, 0.0f } }; + std::array t { }; size_t symbol_phase { 0 }; }; @@ -154,9 +154,9 @@ public: } private: - dsp::interpolation::LinearResampler resampler; - GardnerTimingErrorDetector timing_error_detector; - ErrorFilter error_filter; + dsp::interpolation::LinearResampler resampler { }; + GardnerTimingErrorDetector timing_error_detector { }; + ErrorFilter error_filter { }; const SymbolHandler symbol_handler; void resampler_callback(const float interpolated_sample) { diff --git a/firmware/baseband/dsp_decimate.hpp b/firmware/baseband/dsp_decimate.hpp index 52727075..4437ef88 100644 --- a/firmware/baseband/dsp_decimate.hpp +++ b/firmware/baseband/dsp_decimate.hpp @@ -86,8 +86,8 @@ public: ); private: - std::array z; - std::array taps; + std::array z { }; + std::array taps { }; }; class FIRC8xR16x24FS4Decim4 { @@ -115,8 +115,8 @@ public: ); private: - std::array z_; - std::array taps_; + std::array z_ { }; + std::array taps_ { }; int32_t output_scale = 0; }; @@ -145,8 +145,8 @@ public: ); private: - std::array z_; - std::array taps_; + std::array z_ { }; + std::array taps_ { }; int32_t output_scale = 0; }; @@ -169,8 +169,8 @@ public: ); private: - std::array z_; - std::array taps_; + std::array z_ { }; + std::array taps_ { }; int32_t output_scale = 0; }; @@ -193,8 +193,8 @@ public: ); private: - std::array z_; - std::array taps_; + std::array z_ { }; + std::array taps_ { }; int32_t output_scale = 0; }; @@ -208,11 +208,6 @@ public: /* NOTE! Current code makes an assumption that block of samples to be * processed will be a multiple of the taps_count. */ - FIRAndDecimateComplex( - ) : taps_count_ { 0 }, - decimation_factor_ { 1 } - { - } template void configure( @@ -230,10 +225,10 @@ public: private: using samples_t = sample_t[]; - std::unique_ptr samples_; - std::unique_ptr taps_reversed_; - size_t taps_count_; - size_t decimation_factor_; + std::unique_ptr samples_ { }; + std::unique_ptr taps_reversed_ { }; + size_t taps_count_ { 0 }; + size_t decimation_factor_ { 1 }; template void configure( @@ -259,7 +254,7 @@ public: ); private: - int16_t z[5]; + int16_t z[5] { }; }; } /* namespace decimate */ diff --git a/firmware/baseband/matched_filter.hpp b/firmware/baseband/matched_filter.hpp index 49045db8..a9c6f099 100644 --- a/firmware/baseband/matched_filter.hpp +++ b/firmware/baseband/matched_filter.hpp @@ -66,8 +66,8 @@ public: private: using samples_t = sample_t[]; - std::unique_ptr samples_; - std::unique_ptr taps_reversed_; + std::unique_ptr samples_ { }; + std::unique_ptr taps_reversed_ { }; size_t taps_count_ { 0 }; size_t decimation_factor_ { 1 }; size_t decimation_phase { 0 }; diff --git a/firmware/baseband/packet_builder.hpp b/firmware/baseband/packet_builder.hpp index c8a9ea5b..6a24e803 100644 --- a/firmware/baseband/packet_builder.hpp +++ b/firmware/baseband/packet_builder.hpp @@ -122,13 +122,13 @@ private: const PayloadHandlerFunc payload_handler; - BitHistory bit_history; - PreambleMatcher preamble; - UnstuffMatcher unstuff; - EndMatcher end; + BitHistory bit_history { }; + PreambleMatcher preamble { }; + UnstuffMatcher unstuff { }; + EndMatcher end { }; State state { State::Preamble }; - baseband::Packet packet; + baseband::Packet packet { }; void reset_state() { packet.clear(); diff --git a/firmware/baseband/proc_ais.hpp b/firmware/baseband/proc_ais.hpp index 97e813ff..1130c05c 100644 --- a/firmware/baseband/proc_ais.hpp +++ b/firmware/baseband/proc_ais.hpp @@ -54,21 +54,21 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - std::array dst; + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() }; - dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0; - dsp::decimate::FIRC16xR16x32Decim8 decim_1; + dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { }; + dsp::decimate::FIRC16xR16x32Decim8 decim_1 { }; dsp::matched_filter::MatchedFilter mf { baseband::ais::square_taps_38k4_1t_p, 2 }; clock_recovery::ClockRecovery clock_recovery { 19200, 9600, { 0.0555f }, [this](const float symbol) { this->consume_symbol(symbol); } }; - symbol_coding::NRZIDecoder nrzi_decode; + symbol_coding::NRZIDecoder nrzi_decode { }; PacketBuilder packet_builder { { 0b0101010101111110, 16, 1 }, { 0b111110, 6 }, diff --git a/firmware/baseband/proc_am_audio.hpp b/firmware/baseband/proc_am_audio.hpp index 08cca3e5..55827ea0 100644 --- a/firmware/baseband/proc_am_audio.hpp +++ b/firmware/baseband/proc_am_audio.hpp @@ -49,31 +49,31 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - std::array dst; + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() }; - std::array audio; + std::array audio { }; const buffer_f32_t audio_buffer { audio.data(), audio.size() }; - dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0; - dsp::decimate::FIRC16xR16x32Decim8 decim_1; - dsp::decimate::FIRAndDecimateComplex decim_2; - dsp::decimate::FIRAndDecimateComplex channel_filter; + dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { }; + dsp::decimate::FIRC16xR16x32Decim8 decim_1 { }; + dsp::decimate::FIRAndDecimateComplex decim_2 { }; + dsp::decimate::FIRAndDecimateComplex channel_filter { }; uint32_t channel_filter_pass_f = 0; uint32_t channel_filter_stop_f = 0; bool modulation_ssb = false; - dsp::demodulate::AM demod_am; - dsp::demodulate::SSB demod_ssb; - FeedForwardCompressor audio_compressor; - AudioOutput audio_output; + dsp::demodulate::AM demod_am { }; + dsp::demodulate::SSB demod_ssb { }; + FeedForwardCompressor audio_compressor { }; + AudioOutput audio_output { }; - SpectrumCollector channel_spectrum; + SpectrumCollector channel_spectrum { }; bool configured { false }; void configure(const AMConfigureMessage& message); diff --git a/firmware/baseband/proc_capture.hpp b/firmware/baseband/proc_capture.hpp index c2b48b0c..b30a7889 100644 --- a/firmware/baseband/proc_capture.hpp +++ b/firmware/baseband/proc_capture.hpp @@ -51,20 +51,20 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - std::array dst; + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() }; - dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0; - dsp::decimate::FIRC16xR16x16Decim2 decim_1; + dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { }; + dsp::decimate::FIRC16xR16x16Decim2 decim_1 { }; uint32_t channel_filter_pass_f = 0; uint32_t channel_filter_stop_f = 0; - std::unique_ptr stream; + std::unique_ptr stream { }; - SpectrumCollector channel_spectrum; + SpectrumCollector channel_spectrum { }; size_t spectrum_interval_samples = 0; size_t spectrum_samples = 0; diff --git a/firmware/baseband/proc_nfm_audio.hpp b/firmware/baseband/proc_nfm_audio.hpp index f4529a73..9eba9ef7 100644 --- a/firmware/baseband/proc_nfm_audio.hpp +++ b/firmware/baseband/proc_nfm_audio.hpp @@ -46,28 +46,28 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - std::array dst; + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() }; - std::array audio; + std::array audio { }; const buffer_f32_t audio_buffer { audio.data(), audio.size() }; - dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0; - dsp::decimate::FIRC16xR16x32Decim8 decim_1; - dsp::decimate::FIRAndDecimateComplex channel_filter; + dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { }; + dsp::decimate::FIRC16xR16x32Decim8 decim_1 { }; + dsp::decimate::FIRAndDecimateComplex channel_filter { }; uint32_t channel_filter_pass_f = 0; uint32_t channel_filter_stop_f = 0; - dsp::demodulate::FM demod; + dsp::demodulate::FM demod { }; - AudioOutput audio_output; + AudioOutput audio_output { }; - SpectrumCollector channel_spectrum; + SpectrumCollector channel_spectrum { }; bool configured { false }; void configure(const NBFMConfigureMessage& message); diff --git a/firmware/baseband/proc_tpms.hpp b/firmware/baseband/proc_tpms.hpp index f81c4800..2a09bb71 100644 --- a/firmware/baseband/proc_tpms.hpp +++ b/firmware/baseband/proc_tpms.hpp @@ -69,14 +69,14 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - std::array dst; + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() }; - dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0; - dsp::decimate::FIRC16xR16x16Decim2 decim_1; + dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { }; + dsp::decimate::FIRC16xR16x16Decim2 decim_1 { }; dsp::matched_filter::MatchedFilter mf_38k4_1t_19k2 { rect_taps_307k2_38k4_1t_19k2_p, 8 }; diff --git a/firmware/baseband/proc_wfm_audio.hpp b/firmware/baseband/proc_wfm_audio.hpp index 446990f5..2b21133d 100644 --- a/firmware/baseband/proc_wfm_audio.hpp +++ b/firmware/baseband/proc_wfm_audio.hpp @@ -45,7 +45,7 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - std::array dst; + std::array dst { }; const buffer_c16_t dst_buffer { dst.data(), dst.size() @@ -55,19 +55,19 @@ private: sizeof(dst) / sizeof(int16_t) }; - dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0; - dsp::decimate::FIRC16xR16x16Decim2 decim_1; + dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { }; + dsp::decimate::FIRC16xR16x16Decim2 decim_1 { }; uint32_t channel_filter_pass_f = 0; uint32_t channel_filter_stop_f = 0; - dsp::demodulate::FM demod; - dsp::decimate::DecimateBy2CIC4Real audio_dec_1; - dsp::decimate::DecimateBy2CIC4Real audio_dec_2; - dsp::decimate::FIR64AndDecimateBy2Real audio_filter; + dsp::demodulate::FM demod { }; + dsp::decimate::DecimateBy2CIC4Real audio_dec_1 { }; + dsp::decimate::DecimateBy2CIC4Real audio_dec_2 { }; + dsp::decimate::FIR64AndDecimateBy2Real audio_filter { }; - AudioOutput audio_output; + AudioOutput audio_output { }; - SpectrumCollector channel_spectrum; + SpectrumCollector channel_spectrum { }; size_t spectrum_interval_samples = 0; size_t spectrum_samples = 0; diff --git a/firmware/baseband/proc_wideband_spectrum.hpp b/firmware/baseband/proc_wideband_spectrum.hpp index 7a650ee0..117a1f5b 100644 --- a/firmware/baseband/proc_wideband_spectrum.hpp +++ b/firmware/baseband/proc_wideband_spectrum.hpp @@ -46,9 +46,9 @@ private: BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20 }; RSSIThread rssi_thread { NORMALPRIO + 10 }; - SpectrumCollector channel_spectrum; + SpectrumCollector channel_spectrum { }; - std::array spectrum; + std::array spectrum { }; size_t phase = 0; }; diff --git a/firmware/baseband/rssi_stats_collector.hpp b/firmware/baseband/rssi_stats_collector.hpp index 7a1cd494..68143768 100644 --- a/firmware/baseband/rssi_stats_collector.hpp +++ b/firmware/baseband/rssi_stats_collector.hpp @@ -69,7 +69,7 @@ public: private: static constexpr float update_interval { 0.1f }; - RSSIStatistics statistics; + RSSIStatistics statistics { }; }; #endif/*__RSSI_STATS_COLLECTOR_H__*/ diff --git a/firmware/baseband/spectrum_collector.hpp b/firmware/baseband/spectrum_collector.hpp index b238c1fe..83d30a42 100644 --- a/firmware/baseband/spectrum_collector.hpp +++ b/firmware/baseband/spectrum_collector.hpp @@ -34,12 +34,6 @@ class SpectrumCollector { public: - constexpr SpectrumCollector( - ) : channel_spectrum_decimator { 1 }, - fifo { fifo_data, ChannelSpectrumConfigMessage::fifo_k } - { - } - void on_message(const Message* const message); void set_decimation_factor(const size_t decimation_factor); @@ -51,13 +45,13 @@ public: ); private: - BlockDecimator channel_spectrum_decimator; - ChannelSpectrumFIFO fifo; - ChannelSpectrum fifo_data[1 << ChannelSpectrumConfigMessage::fifo_k]; + BlockDecimator channel_spectrum_decimator { 1 }; + ChannelSpectrum fifo_data[1 << ChannelSpectrumConfigMessage::fifo_k] { }; + ChannelSpectrumFIFO fifo { fifo_data, ChannelSpectrumConfigMessage::fifo_k }; volatile bool channel_spectrum_request_update { false }; bool streaming { false }; - std::array, 256> channel_spectrum; + std::array, 256> channel_spectrum { }; uint32_t channel_spectrum_sampling_rate { 0 }; uint32_t channel_filter_pass_frequency { 0 }; uint32_t channel_filter_stop_frequency { 0 }; diff --git a/firmware/baseband/stream_input.hpp b/firmware/baseband/stream_input.hpp index ce4a29a4..1e73b8c0 100644 --- a/firmware/baseband/stream_input.hpp +++ b/firmware/baseband/stream_input.hpp @@ -42,12 +42,12 @@ private: FIFO fifo_buffers_empty; FIFO fifo_buffers_full; - std::array buffers; - std::array buffers_empty; - std::array buffers_full; + std::array buffers { }; + std::array buffers_empty { }; + std::array buffers_full { }; StreamBuffer* active_buffer { nullptr }; CaptureConfig* const config { nullptr }; - std::unique_ptr data; + std::unique_ptr data { }; }; #endif/*__STREAM_INPUT_H__*/ diff --git a/firmware/common/baseband_packet.hpp b/firmware/common/baseband_packet.hpp index f5bf161c..eb9fd9fb 100644 --- a/firmware/common/baseband_packet.hpp +++ b/firmware/common/baseband_packet.hpp @@ -62,7 +62,7 @@ public: } private: - std::bitset<1408> data; + std::bitset<1408> data { }; Timestamp timestamp_ { }; size_t count { 0 }; }; diff --git a/firmware/common/buffer_exchange.hpp b/firmware/common/buffer_exchange.hpp index 091a6ea2..1f12da3d 100644 --- a/firmware/common/buffer_exchange.hpp +++ b/firmware/common/buffer_exchange.hpp @@ -68,9 +68,9 @@ public: private: CaptureConfig* const config; - FIFO* fifo_buffers_for_baseband; - FIFO* fifo_buffers_for_application; - Thread* thread; + FIFO* fifo_buffers_for_baseband { nullptr }; + FIFO* fifo_buffers_for_application { nullptr }; + Thread* thread { nullptr }; static BufferExchange* obj; void check_fifo_isr() { diff --git a/firmware/common/message_queue.hpp b/firmware/common/message_queue.hpp index 84bbaa9c..0a12fb62 100644 --- a/firmware/common/message_queue.hpp +++ b/firmware/common/message_queue.hpp @@ -80,7 +80,7 @@ public: private: FIFO fifo; - Mutex mutex_write; + Mutex mutex_write { }; Message* peek(std::array& buf) { Message* const p = reinterpret_cast(buf.data()); diff --git a/firmware/common/png_writer.hpp b/firmware/common/png_writer.hpp index 020a118a..bf0fcc8a 100644 --- a/firmware/common/png_writer.hpp +++ b/firmware/common/png_writer.hpp @@ -44,10 +44,10 @@ private: static constexpr int width { 240 }; static constexpr int height { 320 }; - File file; + File file { }; int scanline_count { 0 }; CRC<32, true, true> crc { 0x04c11db7, 0xffffffff, 0xffffffff }; - Adler32 adler_32; + Adler32 adler_32 { }; void write_chunk_header(const size_t length, const std::array& type); void write_chunk_content(const void* const p, const size_t count); diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 18a03158..008bdaaf 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -46,7 +46,7 @@ public: } private: - FocusManager focus_manager_; + FocusManager focus_manager_ { }; }; class Widget { @@ -161,7 +161,7 @@ public: virtual std::string title() const; protected: - std::vector children_; + std::vector children_ { }; void invalidate_child(Widget* const widget); }; @@ -198,7 +198,7 @@ private: class Button : public Widget { public: - std::function on_select; + std::function on_select { }; Button(Rect parent_rect, std::string text); @@ -243,7 +243,7 @@ private: class ImageButton : public Image { public: - std::function on_select; + std::function on_select { }; ImageButton( const Rect parent_rect, @@ -263,8 +263,8 @@ public: using option_t = std::pair; using options_t = std::vector; - std::function on_change; - std::function on_show_options; + std::function on_change { }; + std::function on_show_options { }; OptionsField(Point parent_pos, size_t length, options_t options); @@ -287,7 +287,7 @@ private: class NumberField : public Widget { public: - std::function on_change; + std::function on_change { }; using range_t = std::pair; @@ -309,7 +309,7 @@ private: const int32_t step; const size_t length_; const char fill_char; - int32_t value_; + int32_t value_ { 0 }; int32_t clip_value(int32_t value); }; From 46b3d9d0871505811ac4fe80a678bd636c8fa212 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 26 Nov 2016 16:52:57 -0800 Subject: [PATCH 078/100] Disallow copy constructors/assignments. For classes containing pointers/state that should not be copied. --- firmware/application/capture_thread.hpp | 5 +++++ firmware/application/event_m0.hpp | 5 +++++ firmware/application/ui_navigation.hpp | 2 ++ firmware/application/ui_spectrum.hpp | 5 +++++ firmware/baseband/baseband_thread.hpp | 5 +++++ firmware/baseband/stream_input.hpp | 5 +++++ firmware/common/buffer_exchange.hpp | 5 +++++ firmware/common/ui_widget.hpp | 7 +++++++ 8 files changed, 39 insertions(+) diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index 218a2867..225c1938 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -44,6 +44,11 @@ public: ); ~CaptureThread(); + CaptureThread(const CaptureThread&) = delete; + CaptureThread(CaptureThread&&) = delete; + CaptureThread& operator=(const CaptureThread&) = delete; + CaptureThread& operator=(CaptureThread&&) = delete; + const CaptureConfig& state() const { return config; } diff --git a/firmware/application/event_m0.hpp b/firmware/application/event_m0.hpp index f8442106..56f0a5c0 100644 --- a/firmware/application/event_m0.hpp +++ b/firmware/application/event_m0.hpp @@ -49,6 +49,11 @@ public: ui::Context& context ); + EventDispatcher(const EventDispatcher&) = delete; + EventDispatcher(EventDispatcher&&) = delete; + EventDispatcher& operator=(const EventDispatcher&) = delete; + EventDispatcher& operator=(EventDispatcher&&) = delete; + void run(); static void request_stop(); diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 9e3c7df2..2b94d2f3 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -92,6 +92,8 @@ public: NavigationView(const NavigationView&) = delete; NavigationView(NavigationView&&) = delete; + NavigationView& operator=(const NavigationView&) = delete; + NavigationView& operator=(NavigationView&&) = delete; bool is_top() const; diff --git a/firmware/application/ui_spectrum.hpp b/firmware/application/ui_spectrum.hpp index cbf45644..ce0a8133 100644 --- a/firmware/application/ui_spectrum.hpp +++ b/firmware/application/ui_spectrum.hpp @@ -76,6 +76,11 @@ class WaterfallWidget : public View { public: WaterfallWidget(); + WaterfallWidget(const WaterfallWidget&) = delete; + WaterfallWidget(WaterfallWidget&&) = delete; + WaterfallWidget& operator=(const WaterfallWidget&) = delete; + WaterfallWidget& operator=(WaterfallWidget&&) = delete; + void on_show() override; void on_hide() override; diff --git a/firmware/baseband/baseband_thread.hpp b/firmware/baseband/baseband_thread.hpp index ce05dec7..54fa9023 100644 --- a/firmware/baseband/baseband_thread.hpp +++ b/firmware/baseband/baseband_thread.hpp @@ -37,6 +37,11 @@ public: const baseband::Direction direction = baseband::Direction::Receive ); ~BasebandThread(); + + BasebandThread(const BasebandThread&) = delete; + BasebandThread(BasebandThread&&) = delete; + BasebandThread& operator=(const BasebandThread&) = delete; + BasebandThread& operator=(BasebandThread&&) = delete; // This getter should die, it's just here to leak information to code that // isn't in the right place to begin with. diff --git a/firmware/baseband/stream_input.hpp b/firmware/baseband/stream_input.hpp index 1e73b8c0..1500d2e5 100644 --- a/firmware/baseband/stream_input.hpp +++ b/firmware/baseband/stream_input.hpp @@ -34,6 +34,11 @@ class StreamInput { public: StreamInput(CaptureConfig* const config); + StreamInput(const StreamInput&) = delete; + StreamInput(StreamInput&&) = delete; + StreamInput& operator=(const StreamInput&) = delete; + StreamInput& operator=(StreamInput&&) = delete; + size_t write(const void* const data, const size_t length); private: diff --git a/firmware/common/buffer_exchange.hpp b/firmware/common/buffer_exchange.hpp index 1f12da3d..7029f606 100644 --- a/firmware/common/buffer_exchange.hpp +++ b/firmware/common/buffer_exchange.hpp @@ -32,6 +32,11 @@ public: BufferExchange(CaptureConfig* const config); ~BufferExchange(); + BufferExchange(const BufferExchange&) = delete; + BufferExchange(BufferExchange&&) = delete; + BufferExchange& operator=(const BufferExchange&) = delete; + BufferExchange& operator=(BufferExchange&&) = delete; + #if defined(LPC43XX_M0) bool empty() const { return fifo_buffers_for_application->is_empty(); diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 008bdaaf..3ec09d26 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -64,6 +64,8 @@ public: Widget(const Widget&) = delete; Widget(Widget&&) = delete; + Widget& operator=(const Widget&) = delete; + Widget& operator=(Widget&&) = delete; virtual ~Widget() = default; @@ -229,6 +231,11 @@ public: const Color background ); + Image(const Image&) = delete; + Image(Image&&) = delete; + Image& operator=(const Image&) = delete; + Image& operator=(Image&&) = delete; + void set_bitmap(const Bitmap* bitmap); void set_foreground(const Color color); void set_background(const Color color); From ed0d5331ad631589fef8088ac92b027309767b9d Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 26 Nov 2016 16:53:35 -0800 Subject: [PATCH 079/100] Fix member initialization order. --- firmware/baseband/baseband_thread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/baseband/baseband_thread.cpp b/firmware/baseband/baseband_thread.cpp index 3f683a59..8901f528 100644 --- a/firmware/baseband/baseband_thread.cpp +++ b/firmware/baseband/baseband_thread.cpp @@ -47,8 +47,8 @@ BasebandThread::BasebandThread( const tprio_t priority, baseband::Direction direction ) : baseband_processor { baseband_processor }, - sampling_rate { sampling_rate }, - _direction { direction } + _direction { direction }, + sampling_rate { sampling_rate } { thread = chThdCreateStatic(baseband_thread_wa, sizeof(baseband_thread_wa), priority, ThreadBase::fn, From 606c1cebac82abba4127ce7b5af5457563f048c5 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 26 Nov 2016 16:58:42 -0800 Subject: [PATCH 080/100] Work around apparent alignment bug in G++ 5.4.1? Padding struct to be sizeof() % 4 == 0, because it was crashing the baseband... I think. --- firmware/baseband/dsp_decimate.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/baseband/dsp_decimate.hpp b/firmware/baseband/dsp_decimate.hpp index 4437ef88..bf8a82bc 100644 --- a/firmware/baseband/dsp_decimate.hpp +++ b/firmware/baseband/dsp_decimate.hpp @@ -255,6 +255,7 @@ public: private: int16_t z[5] { }; + int16_t _dummy { }; // TODO: Addresses GCC bug when constructing a class that's not sizeof() % 4 == 0? }; } /* namespace decimate */ From aac2d31548da1087fef4a537df7593ada91ec5b3 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 28 Nov 2016 10:39:10 -0800 Subject: [PATCH 081/100] Hide ui::Point implementation. --- firmware/application/recent_entries.hpp | 2 +- firmware/application/touch.hpp | 12 ++-- firmware/application/ui_console.cpp | 17 +++--- firmware/application/ui_menu.cpp | 2 +- firmware/application/ui_touch_calibration.cpp | 4 +- firmware/common/lcd_ili9341.cpp | 12 ++-- firmware/common/ui.cpp | 9 ++- firmware/common/ui.hpp | 55 ++++++++++++------- firmware/common/ui_focus.cpp | 8 +-- firmware/common/ui_painter.cpp | 10 ++-- firmware/common/ui_widget.cpp | 4 +- 11 files changed, 78 insertions(+), 57 deletions(-) diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 2af1e485..335cf0b7 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -155,7 +155,7 @@ public: const auto is_selected_key = (selected_key == entry.key()); const auto item_style = (has_focus() && is_selected_key) ? s.invert() : s; draw(entry, target_rect, painter, item_style); - target_rect.pos.y += target_rect.height(); + target_rect += { 0, target_rect.height() }; } painter.fill_rectangle( diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp index 0c421f7d..549d3809 100644 --- a/firmware/application/touch.hpp +++ b/firmware/application/touch.hpp @@ -128,12 +128,12 @@ struct Calibration { const std::array& s, const std::array& d ) : k { (s[0].x - s[2].x) * (s[1].y - s[2].y) - (s[1].x - s[2].x) * (s[0].y - s[2].y) }, - a { (d[0].x - d[2].x) * (s[1].y - s[2].y) - (d[1].x - d[2].x) * (s[0].y - s[2].y) }, - b { (s[0].x - s[2].x) * (d[1].x - d[2].x) - (d[0].x - d[2].x) * (s[1].x - s[2].x) }, - c { s[0].y * (s[2].x * d[1].x - s[1].x * d[2].x) + s[1].y * (s[0].x * d[2].x - s[2].x * d[0].x) + s[2].y * (s[1].x * d[0].x - s[0].x * d[1].x) }, - d { (d[0].y - d[2].y) * (s[1].y - s[2].y) - (d[1].y - d[2].y) * (s[0].y - s[2].y) }, - e { (s[0].x - s[2].x) * (d[1].y - d[2].y) - (d[0].y - d[2].y) * (s[1].x - s[2].x) }, - f { s[0].y * (s[2].x * d[1].y - s[1].x * d[2].y) + s[1].y * (s[0].x * d[2].y - s[2].x * d[0].y) + s[2].y * (s[1].x * d[0].y - s[0].x * d[1].y) } + a { (d[0].x() - d[2].x()) * (s[1].y - s[2].y) - (d[1].x() - d[2].x()) * (s[0].y - s[2].y) }, + b { (s[0].x - s[2].x) * (d[1].x() - d[2].x()) - (d[0].x() - d[2].x()) * (s[1].x - s[2].x) }, + c { s[0].y * (s[2].x * d[1].x() - s[1].x * d[2].x()) + s[1].y * (s[0].x * d[2].x() - s[2].x * d[0].x()) + s[2].y * (s[1].x * d[0].x() - s[0].x * d[1].x()) }, + d { (d[0].y() - d[2].y()) * (s[1].y - s[2].y) - (d[1].y() - d[2].y()) * (s[0].y - s[2].y) }, + e { (s[0].x - s[2].x) * (d[1].y() - d[2].y()) - (d[0].y() - d[2].y()) * (s[1].x - s[2].x) }, + f { s[0].y * (s[2].x * d[1].y() - s[1].x * d[2].y()) + s[1].y * (s[0].x * d[2].y() - s[2].x * d[0].y()) + s[2].y * (s[1].x * d[0].y() - s[0].x * d[1].y()) } { } diff --git a/firmware/application/ui_console.cpp b/firmware/application/ui_console.cpp index 28b9f298..af71ee14 100644 --- a/firmware/application/ui_console.cpp +++ b/firmware/application/ui_console.cpp @@ -45,15 +45,15 @@ void Console::write(const std::string& message) { } else { const auto glyph = font.glyph(c); const auto advance = glyph.advance(); - if( (pos.x + advance.x) > rect.width() ) { + if( (pos.x() + advance.x()) > rect.width() ) { crlf(); } const Point pos_glyph { - rect.pos.x + pos.x, - display.scroll_area_y(pos.y) + rect.pos.x() + pos.x(), + display.scroll_area_y(pos.y()) }; display.draw_glyph(pos_glyph, glyph, s.foreground, s.background); - pos.x += advance.x; + pos += { advance.x(), 0 }; } } } @@ -86,14 +86,13 @@ void Console::crlf() { const Style& s = style(); const auto sr = screen_rect(); const auto line_height = s.font.line_height(); - pos.x = 0; - pos.y += line_height; - const int32_t y_excess = pos.y + line_height - sr.height(); + pos = { 0, pos.y() + line_height }; + const int32_t y_excess = pos.y() + line_height - sr.height(); if( y_excess > 0 ) { display.scroll(-y_excess); - pos.y -= y_excess; + pos = { pos.x(), pos.y() - y_excess }; - const Rect dirty { sr.left(), display.scroll_area_y(pos.y), sr.width(), line_height }; + const Rect dirty { sr.left(), display.scroll_area_y(pos.y()), sr.width(), line_height }; display.fill_rectangle(dirty, s.background); } } diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 4a04e817..1406875b 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -54,7 +54,7 @@ void MenuItemView::paint(Painter& painter) { ); painter.draw_string( - { r.pos.x + 8, r.pos.y + (r.size.h - font_height) / 2 }, + { r.pos.x() + 8, r.pos.y() + (r.size.h - font_height) / 2 }, paint_style, item.text ); diff --git a/firmware/application/ui_touch_calibration.cpp b/firmware/application/ui_touch_calibration.cpp index 37cd0df8..a5a7c348 100644 --- a/firmware/application/ui_touch_calibration.cpp +++ b/firmware/application/ui_touch_calibration.cpp @@ -92,8 +92,8 @@ void TouchCalibrationView::set_phase(const Phase value) { uint32_t TouchCalibrationView::distance_squared(const Point& touch_point, const Image& target) { const auto target_point = target.screen_rect().center(); - const int32_t dx = target_point.x - touch_point.x; - const int32_t dy = target_point.y - touch_point.y; + const int32_t dx = target_point.x() - touch_point.x(); + const int32_t dy = target_point.y() - touch_point.y(); const uint32_t dx2 = dx * dx; const uint32_t dy2 = dy * dy; return dx2 + dy2; diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index ddda0f8c..68a04ef9 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -196,8 +196,8 @@ void lcd_start_ram_write( const ui::Point p, const ui::Size s ) { - lcd_caset(p.x, p.x + s.w - 1); - lcd_paset(p.y, p.y + s.h - 1); + lcd_caset(p.x(), p.x() + s.w - 1); + lcd_paset(p.y(), p.y() + s.h - 1); lcd_ramwr_start(); } @@ -205,8 +205,8 @@ void lcd_start_ram_read( const ui::Point p, const ui::Size s ) { - lcd_caset(p.x, p.x + s.w - 1); - lcd_paset(p.y, p.y + s.h - 1); + lcd_caset(p.x(), p.x() + s.w - 1); + lcd_paset(p.y(), p.y() + s.h - 1); lcd_ramrd_start(); } @@ -292,8 +292,8 @@ void ILI9341::fill_circle( const bool inside = d2 < radius2; const auto color = inside ? foreground : background; draw_pixel({ - static_cast(x + center.x), - static_cast(y + center.y) + static_cast(x + center.x()), + static_cast(y + center.y()) }, color); } } diff --git a/firmware/common/ui.cpp b/firmware/common/ui.cpp index 5b0f55b2..a9a3eae9 100644 --- a/firmware/common/ui.cpp +++ b/firmware/common/ui.cpp @@ -26,8 +26,8 @@ namespace ui { bool Rect::contains(const Point p) const { - return (p.x >= left()) && (p.y >= top()) && - (p.x < right()) && (p.y < bottom()); + return (p.x() >= left()) && (p.y() >= top()) && + (p.x() < right()) && (p.y() < bottom()); } Rect Rect::intersect(const Rect& o) const { @@ -64,4 +64,9 @@ Rect& Rect::operator+=(const Point& p) { return *this; } +Rect& Rect::operator-=(const Point& p) { + pos -= p; + return *this; +} + } /* namespace ui */ diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index f363a841..fb331f12 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -82,38 +82,54 @@ struct ColorRGB888 { }; struct Point { - Coord x; - Coord y; +private: + Coord _x; + Coord _y; +public: constexpr Point( - ) : x { 0 }, - y { 0 } + ) : _x { 0 }, + _y { 0 } { } constexpr Point( int x, int y - ) : x { static_cast(x) }, - y { static_cast(y) } + ) : _x { static_cast(x) }, + _y { static_cast(y) } { } - Point operator-() const { - return { -x, -y }; + constexpr int x() const { + return _x; } - Point operator+(const Point& p) const { - return { x + p.x, y + p.y }; + constexpr int y() const { + return _y; } - Point operator-(const Point& p) const { - return { x - p.x, y - p.y }; + constexpr Point operator-() const { + return { -_x, -_y }; + } + + constexpr Point operator+(const Point& p) const { + return { _x + p._x, _y + p._y }; + } + + constexpr Point operator-(const Point& p) const { + return { _x - p._x, _y - p._y }; } Point& operator+=(const Point& p) { - x += p.x; - y += p.y; + _x += p._x; + _y += p._y; + return *this; + } + + Point& operator-=(const Point& p) { + _x -= p._x; + _y -= p._y; return *this; } }; @@ -168,19 +184,19 @@ struct Rect { } int top() const { - return pos.y; + return pos.y(); } int bottom() const { - return pos.y + size.h; + return pos.y() + size.h; } int left() const { - return pos.x; + return pos.x(); } int right() const { - return pos.x + size.w; + return pos.x() + size.w; } int width() const { @@ -192,7 +208,7 @@ struct Rect { } Point center() const { - return { pos.x + size.w / 2, pos.y + size.h / 2 }; + return { pos.x() + size.w / 2, pos.y() + size.h / 2 }; } bool is_empty() const { @@ -209,6 +225,7 @@ struct Rect { Rect& operator+=(const Rect& p); Rect& operator+=(const Point& p); + Rect& operator-=(const Point& p); operator bool() const { return !size.is_empty(); diff --git a/firmware/common/ui_focus.cpp b/firmware/common/ui_focus.cpp index 92547d35..48d30b02 100644 --- a/firmware/common/ui_focus.cpp +++ b/firmware/common/ui_focus.cpp @@ -127,14 +127,14 @@ static int32_t rect_distances( switch(direction) { case KeyEvent::Right: case KeyEvent::Left: - perpendicular_axis_start = rect_start.center().y; - perpendicular_axis_end = rect_end.center().y; + perpendicular_axis_start = rect_start.center().y(); + perpendicular_axis_end = rect_end.center().y(); break; case KeyEvent::Up: case KeyEvent::Down: - perpendicular_axis_start = rect_start.center().x; - perpendicular_axis_end = rect_end.center().x; + perpendicular_axis_start = rect_start.center().x(); + perpendicular_axis_end = rect_end.center().x(); break; default: diff --git a/firmware/common/ui_painter.cpp b/firmware/common/ui_painter.cpp index 2b54e194..6ad11a0b 100644 --- a/firmware/common/ui_painter.cpp +++ b/firmware/common/ui_painter.cpp @@ -39,7 +39,7 @@ Style Style::invert() const { int Painter::draw_char(const Point p, const Style& style, const char c) { const auto glyph = style.font.glyph(c); display.draw_glyph(p, glyph, style.foreground, style.background); - return glyph.advance().x; + return glyph.advance().x(); } int Painter::draw_string(Point p, const Style& style, const std::string text) { @@ -49,7 +49,7 @@ int Painter::draw_string(Point p, const Style& style, const std::string text) { display.draw_glyph(p, glyph, style.foreground, style.background); const auto advance = glyph.advance(); p += advance; - width += advance.x; + width += advance.x(); } return width; } @@ -68,9 +68,9 @@ void Painter::draw_vline(Point p, int height, const Color c) { void Painter::draw_rectangle(const Rect r, const Color c) { draw_hline(r.pos, r.size.w, c); - draw_vline({ r.pos.x, r.pos.y + 1 }, r.size.h - 2, c); - draw_vline({ r.pos.x + r.size.w - 1, r.pos.y + 1 }, r.size.h - 2, c); - draw_hline({ r.pos.x, r.pos.y + r.size.h - 1 }, r.size.w, c); + draw_vline({ r.pos.x(), r.pos.y() + 1 }, r.size.h - 2, c); + draw_vline({ r.pos.x() + r.size.w - 1, r.pos.y() + 1 }, r.size.h - 2, c); + draw_hline({ r.pos.x(), r.pos.y() + r.size.h - 1 }, r.size.w, c); } void Painter::fill_rectangle(const Rect r, const Color c) { diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 94716753..a84b731a 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -351,13 +351,13 @@ void Button::paint(Painter& painter) { painter.draw_rectangle(r, style().foreground); painter.fill_rectangle( - { r.pos.x + 1, r.pos.y + 1, r.size.w - 2, r.size.h - 2 }, + { r.pos.x() + 1, r.pos.y() + 1, r.size.w - 2, r.size.h - 2 }, paint_style.background ); const auto label_r = paint_style.font.size_of(text_); painter.draw_string( - { r.pos.x + (r.size.w - label_r.w) / 2, r.pos.y + (r.size.h - label_r.h) / 2 }, + { r.pos.x() + (r.size.w - label_r.w) / 2, r.pos.y() + (r.size.h - label_r.h) / 2 }, paint_style, text_ ); From d15ace46766d8ade8a4451c9d3c2f767aa98ff00 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 28 Nov 2016 10:55:45 -0800 Subject: [PATCH 082/100] Hide ui::Size implementation. --- firmware/application/ui_debug.cpp | 2 +- firmware/application/ui_menu.cpp | 4 ++-- firmware/application/ui_spectrum.cpp | 2 +- firmware/common/lcd_ili9341.cpp | 12 +++++----- firmware/common/ui.hpp | 34 ++++++++++++++++++---------- firmware/common/ui_painter.cpp | 8 +++---- firmware/common/ui_text.cpp | 6 +++-- firmware/common/ui_text.hpp | 4 ++-- firmware/common/ui_widget.cpp | 4 ++-- 9 files changed, 44 insertions(+), 32 deletions(-) diff --git a/firmware/application/ui_debug.cpp b/firmware/application/ui_debug.cpp index 6e1bdcca..11aff219 100644 --- a/firmware/application/ui_debug.cpp +++ b/firmware/application/ui_debug.cpp @@ -164,7 +164,7 @@ void RegistersWidget::update() { } void RegistersWidget::paint(Painter& painter) { - const Coord left = (size().w - config.row_width()) / 2; + const Coord left = (size().width() - config.row_width()) / 2; draw_legend(left, painter); draw_values(left, painter); diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 1406875b..2d6bf7ff 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -54,7 +54,7 @@ void MenuItemView::paint(Painter& painter) { ); painter.draw_string( - { r.pos.x() + 8, r.pos.y() + (r.size.h - font_height) / 2 }, + { r.pos.x() + 8, r.pos.y() + (r.size.height() - font_height) / 2 }, paint_style, item.text ); @@ -87,7 +87,7 @@ void MenuView::set_parent_rect(const Rect new_parent_rect) { for(auto child : children_) { child->set_parent_rect({ { 0, static_cast(i * item_height) }, - { size().w, item_height } + { size().width(), item_height } }); i++; } diff --git a/firmware/application/ui_spectrum.cpp b/firmware/application/ui_spectrum.cpp index 448e0766..07739ee0 100644 --- a/firmware/application/ui_spectrum.cpp +++ b/firmware/application/ui_spectrum.cpp @@ -112,7 +112,7 @@ void FrequencyScale::draw_frequency_ticks(Painter& painter, const Rect r) { (magnitude_n >= 6) ? "M" : (magnitude_n >= 3) ? "k" : ""; const std::string label = to_string_dec_uint(tick_offset) + zero_pad + unit; - const auto label_width = style().font.size_of(label).w; + const auto label_width = style().font.size_of(label).width(); const Coord offset_low = r.left() + x_center - pixel_offset; const Rect tick_low { offset_low, r.top(), 1, r.height() }; diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index 68a04ef9..77868949 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -196,8 +196,8 @@ void lcd_start_ram_write( const ui::Point p, const ui::Size s ) { - lcd_caset(p.x(), p.x() + s.w - 1); - lcd_paset(p.y(), p.y() + s.h - 1); + lcd_caset(p.x(), p.x() + s.width() - 1); + lcd_paset(p.y(), p.y() + s.height() - 1); lcd_ramwr_start(); } @@ -205,8 +205,8 @@ void lcd_start_ram_read( const ui::Point p, const ui::Size s ) { - lcd_caset(p.x(), p.x() + s.w - 1); - lcd_paset(p.y(), p.y() + s.h - 1); + lcd_caset(p.x(), p.x() + s.width() - 1); + lcd_paset(p.y(), p.y() + s.height() - 1); lcd_ramrd_start(); } @@ -272,7 +272,7 @@ void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) { const auto r_clipped = r.intersect(screen_rect()); if( !r_clipped.is_empty() ) { lcd_start_ram_write(r_clipped); - size_t count = r_clipped.size.w * r_clipped.size.h; + size_t count = r_clipped.size.width() * r_clipped.size.height(); io.lcd_write_pixels(c, count); } } @@ -341,7 +341,7 @@ void ILI9341::draw_bitmap( ) { lcd_start_ram_write(p, size); - const size_t count = size.w * size.h; + const size_t count = size.width() * size.height(); for(size_t i=0; i> 3] & (1U << (i & 0x7)); io.lcd_write_pixel(pixel ? foreground : background); diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index fb331f12..8861eb7c 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -135,25 +135,35 @@ public: }; struct Size { - Dim w; - Dim h; +private: + Dim _w; + Dim _h; +public: constexpr Size( - ) : w { 0 }, - h { 0 } + ) : _w { 0 }, + _h { 0 } { } constexpr Size( int w, int h - ) : w { static_cast(w) }, - h { static_cast(h) } + ) : _w { static_cast(w) }, + _h { static_cast(h) } { } + int width() const { + return _w; + } + + int height() const { + return _h; + } + bool is_empty() const { - return (w < 1) || (h < 1); + return (_w < 1) || (_h < 1); } }; @@ -188,7 +198,7 @@ struct Rect { } int bottom() const { - return pos.y() + size.h; + return pos.y() + size.height(); } int left() const { @@ -196,19 +206,19 @@ struct Rect { } int right() const { - return pos.x() + size.w; + return pos.x() + size.width(); } int width() const { - return size.w; + return size.width(); } int height() const { - return size.h; + return size.height(); } Point center() const { - return { pos.x() + size.w / 2, pos.y() + size.h / 2 }; + return { pos.x() + size.width() / 2, pos.y() + size.height() / 2 }; } bool is_empty() const { diff --git a/firmware/common/ui_painter.cpp b/firmware/common/ui_painter.cpp index 6ad11a0b..47f5b02b 100644 --- a/firmware/common/ui_painter.cpp +++ b/firmware/common/ui_painter.cpp @@ -67,10 +67,10 @@ void Painter::draw_vline(Point p, int height, const Color c) { } void Painter::draw_rectangle(const Rect r, const Color c) { - draw_hline(r.pos, r.size.w, c); - draw_vline({ r.pos.x(), r.pos.y() + 1 }, r.size.h - 2, c); - draw_vline({ r.pos.x() + r.size.w - 1, r.pos.y() + 1 }, r.size.h - 2, c); - draw_hline({ r.pos.x(), r.pos.y() + r.size.h - 1 }, r.size.w, c); + draw_hline(r.pos, r.size.width(), c); + draw_vline({ r.pos.x(), r.pos.y() + 1 }, r.size.height() - 2, c); + draw_vline({ r.pos.x() + r.size.width() - 1, r.pos.y() + 1 }, r.size.height() - 2, c); + draw_hline({ r.pos.x(), r.pos.y() + r.size.height() - 1 }, r.size.width(), c); } void Painter::fill_rectangle(const Rect r, const Color c) { diff --git a/firmware/common/ui_text.cpp b/firmware/common/ui_text.cpp index 0f55c5f6..e926ba0d 100644 --- a/firmware/common/ui_text.cpp +++ b/firmware/common/ui_text.cpp @@ -44,8 +44,10 @@ Size Font::size_of(const std::string s) const { for(const auto c : s) { const auto glyph_data = glyph(c); - size.w += glyph_data.w(); - size.h = std::max(size.h, glyph_data.h()); + size = { + size.width() + glyph_data.w(), + std::max(size.height(), glyph_data.h()) + }; } return size; diff --git a/firmware/common/ui_text.hpp b/firmware/common/ui_text.hpp index ae3c94b7..d60c746f 100644 --- a/firmware/common/ui_text.hpp +++ b/firmware/common/ui_text.hpp @@ -42,11 +42,11 @@ public: { } - Dim w() const { + int w() const { return w_; } - Dim h() const { + int h() const { return h_; } diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index a84b731a..897c9b85 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -351,13 +351,13 @@ void Button::paint(Painter& painter) { painter.draw_rectangle(r, style().foreground); painter.fill_rectangle( - { r.pos.x() + 1, r.pos.y() + 1, r.size.w - 2, r.size.h - 2 }, + { r.pos.x() + 1, r.pos.y() + 1, r.size.width() - 2, r.size.height() - 2 }, paint_style.background ); const auto label_r = paint_style.font.size_of(text_); painter.draw_string( - { r.pos.x() + (r.size.w - label_r.w) / 2, r.pos.y() + (r.size.h - label_r.h) / 2 }, + { r.pos.x() + (r.size.width() - label_r.width()) / 2, r.pos.y() + (r.size.height() - label_r.height()) / 2 }, paint_style, text_ ); From e820bed09746419b36a285178c5f2991c464c34e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 28 Nov 2016 11:25:27 -0800 Subject: [PATCH 083/100] Hide ui::Rect implementation. --- firmware/application/ais_app.cpp | 2 +- firmware/application/ert_app.cpp | 2 +- firmware/application/recent_entries.cpp | 2 +- firmware/application/recent_entries.hpp | 2 +- firmware/application/tpms_app.cpp | 2 +- firmware/application/ui_console.cpp | 2 +- firmware/application/ui_menu.cpp | 2 +- firmware/common/lcd_ili9341.cpp | 8 ++--- firmware/common/ui.cpp | 8 ++--- firmware/common/ui.hpp | 46 +++++++++++++++---------- firmware/common/ui_painter.cpp | 8 ++--- firmware/common/ui_widget.cpp | 10 +++--- 12 files changed, 52 insertions(+), 42 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 8a53da71..0823d050 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -200,7 +200,7 @@ void RecentEntriesTable::draw( } line.resize(target_rect.width() / 8, ' '); - painter.draw_string(target_rect.pos, style, line); + painter.draw_string(target_rect.location(), style, line); } AISRecentEntryDetailView::AISRecentEntryDetailView() { diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 5df0f336..91b3e5e1 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -91,7 +91,7 @@ void RecentEntriesTable::draw( } line.resize(target_rect.width() / 8, ' '); - painter.draw_string(target_rect.pos, style, line); + painter.draw_string(target_rect.location(), style, line); } ERTAppView::ERTAppView(NavigationView&) { diff --git a/firmware/application/recent_entries.cpp b/firmware/application/recent_entries.cpp index 0521238a..bc6ef17a 100644 --- a/firmware/application/recent_entries.cpp +++ b/firmware/application/recent_entries.cpp @@ -45,7 +45,7 @@ void RecentEntriesHeader::paint(Painter& painter) { .foreground = parent_style.foreground, }; - auto p = r.pos; + auto p = r.location(); for(const auto& column : _columns) { const auto width = column.second; auto text = column.first; diff --git a/firmware/application/recent_entries.hpp b/firmware/application/recent_entries.hpp index 335cf0b7..90fd5203 100644 --- a/firmware/application/recent_entries.hpp +++ b/firmware/application/recent_entries.hpp @@ -140,7 +140,7 @@ public: const auto r = screen_rect(); const auto& s = style(); - Rect target_rect { r.pos, { r.width(), s.font.line_height() }}; + Rect target_rect { r.location(), { r.width(), s.font.line_height() }}; const size_t visible_item_count = r.height() / s.font.line_height(); auto selected = find(recent, selected_key); diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 7fe5ab6f..82cdbd3f 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -129,7 +129,7 @@ void RecentEntriesTable::draw( } line.resize(target_rect.width() / 8, ' '); - painter.draw_string(target_rect.pos, style, line); + painter.draw_string(target_rect.location(), style, line); } TPMSAppView::TPMSAppView(NavigationView&) { diff --git a/firmware/application/ui_console.cpp b/firmware/application/ui_console.cpp index af71ee14..fc37b8ce 100644 --- a/firmware/application/ui_console.cpp +++ b/firmware/application/ui_console.cpp @@ -49,7 +49,7 @@ void Console::write(const std::string& message) { crlf(); } const Point pos_glyph { - rect.pos.x() + pos.x(), + rect.left() + pos.x(), display.scroll_area_y(pos.y()) }; display.draw_glyph(pos_glyph, glyph, s.foreground, s.background); diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 2d6bf7ff..7498a611 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -54,7 +54,7 @@ void MenuItemView::paint(Painter& painter) { ); painter.draw_string( - { r.pos.x() + 8, r.pos.y() + (r.size.height() - font_height) / 2 }, + { r.left() + 8, r.top() + (r.height() - font_height) / 2 }, paint_style, item.text ); diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index 77868949..db434d6c 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -213,13 +213,13 @@ void lcd_start_ram_read( void lcd_start_ram_write( const ui::Rect& r ) { - lcd_start_ram_write(r.pos, r.size); + lcd_start_ram_write(r.location(), r.size()); } void lcd_start_ram_read( const ui::Rect& r ) { - lcd_start_ram_read(r.pos, r.size); + lcd_start_ram_read(r.location(), r.size()); } void lcd_vertical_scrolling_definition( @@ -272,7 +272,7 @@ void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) { const auto r_clipped = r.intersect(screen_rect()); if( !r_clipped.is_empty() ) { lcd_start_ram_write(r_clipped); - size_t count = r_clipped.size.width() * r_clipped.size.height(); + size_t count = r_clipped.width() * r_clipped.height(); io.lcd_write_pixels(c, count); } } @@ -315,7 +315,7 @@ void ILI9341::draw_pixels( const size_t count ) { /* TODO: Assert that rectangle width x height < count */ - lcd_start_ram_write(r.pos, r.size); + lcd_start_ram_write(r); io.lcd_write_pixels(colors, count); } diff --git a/firmware/common/ui.cpp b/firmware/common/ui.cpp index a9a3eae9..06255c2d 100644 --- a/firmware/common/ui.cpp +++ b/firmware/common/ui.cpp @@ -51,21 +51,21 @@ Rect& Rect::operator+=(const Rect& p) { if( !p.is_empty() ) { const auto x1 = std::min(left(), p.left()); const auto y1 = std::min(top(), p.top()); - pos = { x1, y1 }; + _pos = { x1, y1 }; const auto x2 = std::max(right(), p.right()); const auto y2 = std::max(bottom(), p.bottom()); - size = { x2 - x1, y2 - y1 }; + _size = { x2 - x1, y2 - y1 }; } return *this; } Rect& Rect::operator+=(const Point& p) { - pos += p; + _pos += p; return *this; } Rect& Rect::operator-=(const Point& p) { - pos -= p; + _pos -= p; return *this; } diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp index 8861eb7c..368f4959 100644 --- a/firmware/common/ui.hpp +++ b/firmware/common/ui.hpp @@ -168,61 +168,71 @@ public: }; struct Rect { - Point pos; - Size size; +private: + Point _pos; + Size _size; +public: constexpr Rect( - ) : pos { }, - size { } + ) : _pos { }, + _size { } { } constexpr Rect( int x, int y, int w, int h - ) : pos { x, y }, - size { w, h } + ) : _pos { x, y }, + _size { w, h } { } constexpr Rect( Point pos, Size size - ) : pos(pos), - size(size) + ) : _pos(pos), + _size(size) { } + Point location() const { + return _pos; + } + + Size size() const { + return _size; + } + int top() const { - return pos.y(); + return _pos.y(); } int bottom() const { - return pos.y() + size.height(); + return _pos.y() + _size.height(); } int left() const { - return pos.x(); + return _pos.x(); } int right() const { - return pos.x() + size.width(); + return _pos.x() + _size.width(); } int width() const { - return size.width(); + return _size.width(); } int height() const { - return size.height(); + return _size.height(); } Point center() const { - return { pos.x() + size.width() / 2, pos.y() + size.height() / 2 }; + return { _pos.x() + _size.width() / 2, _pos.y() + _size.height() / 2 }; } bool is_empty() const { - return size.is_empty(); + return _size.is_empty(); } bool contains(const Point p) const; @@ -230,7 +240,7 @@ struct Rect { Rect intersect(const Rect& o) const; Rect operator+(const Point& p) const { - return { pos + p, size }; + return { _pos + p, _size }; } Rect& operator+=(const Rect& p); @@ -238,7 +248,7 @@ struct Rect { Rect& operator-=(const Point& p); operator bool() const { - return !size.is_empty(); + return !_size.is_empty(); } }; diff --git a/firmware/common/ui_painter.cpp b/firmware/common/ui_painter.cpp index 47f5b02b..97f223a2 100644 --- a/firmware/common/ui_painter.cpp +++ b/firmware/common/ui_painter.cpp @@ -67,10 +67,10 @@ void Painter::draw_vline(Point p, int height, const Color c) { } void Painter::draw_rectangle(const Rect r, const Color c) { - draw_hline(r.pos, r.size.width(), c); - draw_vline({ r.pos.x(), r.pos.y() + 1 }, r.size.height() - 2, c); - draw_vline({ r.pos.x() + r.size.width() - 1, r.pos.y() + 1 }, r.size.height() - 2, c); - draw_hline({ r.pos.x(), r.pos.y() + r.size.height() - 1 }, r.size.width(), c); + draw_hline(r.location(), r.width(), c); + draw_vline({ r.left(), r.top() + 1 }, r.height() - 2, c); + draw_vline({ r.left() + r.width() - 1, r.top() + 1 }, r.height() - 2, c); + draw_hline({ r.left(), r.top() + r.height() - 1 }, r.width(), c); } void Painter::fill_rectangle(const Rect r, const Color c) { diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 897c9b85..61abaecf 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -49,11 +49,11 @@ bool is_dirty() { const std::vector Widget::no_children { }; Point Widget::screen_pos() { - return screen_rect().pos; + return screen_rect().location(); } Size Widget::size() const { - return parent_rect.size; + return parent_rect.size(); } Rect Widget::screen_rect() const { @@ -317,7 +317,7 @@ void Text::paint(Painter& painter) { painter.fill_rectangle(rect, s.background); painter.draw_string( - rect.pos, + rect.location(), s, text ); @@ -351,13 +351,13 @@ void Button::paint(Painter& painter) { painter.draw_rectangle(r, style().foreground); painter.fill_rectangle( - { r.pos.x() + 1, r.pos.y() + 1, r.size.width() - 2, r.size.height() - 2 }, + { r.left() + 1, r.top() + 1, r.width() - 2, r.height() - 2 }, paint_style.background ); const auto label_r = paint_style.font.size_of(text_); painter.draw_string( - { r.pos.x() + (r.size.width() - label_r.width()) / 2, r.pos.y() + (r.size.height() - label_r.height()) / 2 }, + { r.left() + (r.width() - label_r.width()) / 2, r.top() + (r.height() - label_r.height()) / 2 }, paint_style, text_ ); From 86d2576d3e76008580a7255114ba29c1960632f6 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 28 Nov 2016 12:00:56 -0800 Subject: [PATCH 084/100] Fix types on touch Filter accumulator/value. --- firmware/application/touch.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/application/touch.hpp b/firmware/application/touch.hpp index 549d3809..ebea3c92 100644 --- a/firmware/application/touch.hpp +++ b/firmware/application/touch.hpp @@ -171,7 +171,7 @@ public: history_history = (history_history << 1) | 1U; } - uint32_t value() const { + int32_t value() const { return accumulator / N; } @@ -192,7 +192,7 @@ private: std::array history { }; uint32_t history_history { 0 }; - uint32_t accumulator { 0 }; + int32_t accumulator { 0 }; size_t n { 0 }; bool history_valid() const { From 227719ff1de77635ab5fa34516fbd96f0c264f11 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 28 Nov 2016 12:05:24 -0800 Subject: [PATCH 085/100] Fix static_cast warning. --- firmware/common/tpms_packet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/tpms_packet.cpp b/firmware/common/tpms_packet.cpp index 0bc3064b..8cca23f2 100644 --- a/firmware/common/tpms_packet.cpp +++ b/firmware/common/tpms_packet.cpp @@ -88,7 +88,7 @@ Optional Packet::reading_ook_8k192_schrader() const { reader_.read(3, 24), Pressure { static_cast(reader_.read(27, 8)) * 4 / 3 }, { }, - Flags { (flags << 4) | checksum } + Flags { static_cast((flags << 4) | checksum) } }; } else { return { }; From 4c8550bb7d68f2d0f71749d2fd67282a66ba90b3 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 28 Nov 2016 12:09:02 -0800 Subject: [PATCH 086/100] Fix narrowing conversion warnings. --- firmware/baseband/ook.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/baseband/ook.hpp b/firmware/baseband/ook.hpp index 2453f2f4..04324fe6 100644 --- a/firmware/baseband/ook.hpp +++ b/firmware/baseband/ook.hpp @@ -70,8 +70,8 @@ public: constexpr OOKClockRecovery( const float samples_per_symbol ) : symbol_phase_inc_nominal { static_cast(std::round((1ULL << 32) / samples_per_symbol)) }, - symbol_phase_inc_k { symbol_phase_inc_nominal * (2.0f / 8.0f) / samples_per_symbol }, - phase_detector { samples_per_symbol }, + symbol_phase_inc_k { static_cast(std::round(symbol_phase_inc_nominal * (2.0f / 8.0f) / samples_per_symbol)) }, + phase_detector { static_cast(std::round(samples_per_symbol)) }, phase_accumulator { symbol_phase_inc_nominal } { } From 3f94591083ce995d2e2a3d14b8a278624e02c24a Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 29 Nov 2016 10:13:56 -0800 Subject: [PATCH 087/100] Remove a lot of static_cast<>s involving UI structs. Also starting to get religion on using unsigned integers only when I want their wrapping/modulus behavior. --- firmware/application/analog_audio_app.cpp | 2 +- firmware/application/capture_app.cpp | 2 +- firmware/application/touch.cpp | 5 +---- firmware/application/ui_audio.cpp | 20 ++++-------------- firmware/application/ui_channel.cpp | 15 +++----------- firmware/application/ui_menu.cpp | 9 +++----- firmware/application/ui_navigation.cpp | 5 +---- firmware/application/ui_rssi.cpp | 25 +++++------------------ firmware/common/lcd_ili9341.cpp | 5 +---- firmware/common/ui_widget.cpp | 8 ++++---- firmware/common/ui_widget.hpp | 8 ++++---- 11 files changed, 28 insertions(+), 76 deletions(-) diff --git a/firmware/application/analog_audio_app.cpp b/firmware/application/analog_audio_app.cpp index 0a6009ca..0f2c41f9 100644 --- a/firmware/application/analog_audio_app.cpp +++ b/firmware/application/analog_audio_app.cpp @@ -161,7 +161,7 @@ void AnalogAudioView::on_hide() { void AnalogAudioView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); - const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast(new_parent_rect.height() - header_height) }; + const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height }; waterfall.set_parent_rect(waterfall_rect); } diff --git a/firmware/application/capture_app.cpp b/firmware/application/capture_app.cpp index cd2a3824..e5b9a36c 100644 --- a/firmware/application/capture_app.cpp +++ b/firmware/application/capture_app.cpp @@ -98,7 +98,7 @@ void CaptureAppView::on_hide() { void CaptureAppView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); - const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast(new_parent_rect.height() - header_height) }; + const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height }; waterfall.set_parent_rect(waterfall_rect); } diff --git a/firmware/application/touch.cpp b/firmware/application/touch.cpp index ac48c053..d3fc6c92 100644 --- a/firmware/application/touch.cpp +++ b/firmware/application/touch.cpp @@ -73,10 +73,7 @@ ui::Point Calibration::translate(const DigitizerPoint& p) const { const int32_t y = (d * p.x + e * p.y + f) / k; const auto x_clipped = x_range.clip(x); const auto y_clipped = y_range.clip(y); - return { - static_cast(x_clipped), - static_cast(y_clipped) - }; + return { x_clipped, y_clipped }; } const Calibration default_calibration() { diff --git a/firmware/application/ui_audio.cpp b/firmware/application/ui_audio.cpp index 389a65e1..1f51c3a3 100644 --- a/firmware/application/ui_audio.cpp +++ b/firmware/application/ui_audio.cpp @@ -38,37 +38,25 @@ void Audio::paint(Painter& painter) { const range_t x_max_range { x_rms + 1, r.width() }; const auto x_max = x_max_range.clip((max_db_ - db_min) * r.width() / db_delta); - const Rect r0 { - static_cast(r.left()), r.top(), - static_cast(x_rms), r.height() - }; + const Rect r0 { r.left(), r.top(), x_rms, r.height() }; painter.fill_rectangle( r0, Color::green() ); - const Rect r1 { - static_cast(r.left() + x_rms), r.top(), - 1, r.height() - }; + const Rect r1 { r.left() + x_rms, r.top(), 1, r.height() }; painter.fill_rectangle( r1, Color::black() ); - const Rect r2 { - static_cast(r.left() + x_rms + 1), r.top(), - static_cast(x_max - (x_rms + 1)), r.height() - }; + const Rect r2 { r.left() + x_rms + 1, r.top(), x_max - (x_rms + 1), r.height() }; painter.fill_rectangle( r2, Color::red() ); - const Rect r3 { - static_cast(r.left() + x_max), r.top(), - static_cast(r.width() - x_max), r.height() - }; + const Rect r3 { r.left() + x_max, r.top(), r.width() - x_max, r.height() }; painter.fill_rectangle( r3, Color::black() diff --git a/firmware/application/ui_channel.cpp b/firmware/application/ui_channel.cpp index 3d21e535..227d71fe 100644 --- a/firmware/application/ui_channel.cpp +++ b/firmware/application/ui_channel.cpp @@ -36,28 +36,19 @@ void Channel::paint(Painter& painter) { const range_t x_max_range { 0, r.width() - 1 }; const auto x_max = x_max_range.clip((max_db_ - db_min) * r.width() / db_delta); - const Rect r0 { - static_cast(r.left()), r.top(), - static_cast(x_max), r.height() - }; + const Rect r0 { r.left(), r.top(), x_max, r.height() }; painter.fill_rectangle( r0, Color::blue() ); - const Rect r1 { - static_cast(r.left() + x_max), r.top(), - 1, r.height() - }; + const Rect r1 { r.left() + x_max, r.top(), 1, r.height() }; painter.fill_rectangle( r1, Color::white() ); - const Rect r2 { - static_cast(r.left() + x_max + 1), r.top(), - static_cast(r.width() - (x_max + 1)), r.height() - }; + const Rect r2 { r.left() + x_max + 1, r.top(), r.width() - (x_max + 1), r.height() }; painter.fill_rectangle( r2, Color::black() diff --git a/firmware/application/ui_menu.cpp b/firmware/application/ui_menu.cpp index 7498a611..f7ce7031 100644 --- a/firmware/application/ui_menu.cpp +++ b/firmware/application/ui_menu.cpp @@ -82,13 +82,10 @@ void MenuView::add_items(std::initializer_list items) { void MenuView::set_parent_rect(const Rect new_parent_rect) { View::set_parent_rect(new_parent_rect); - constexpr size_t item_height = 24; - size_t i = 0; + constexpr int item_height = 24; + int i = 0; for(auto child : children_) { - child->set_parent_rect({ - { 0, static_cast(i * item_height) }, - { size().width(), item_height } - }); + child->set_parent_rect({ 0, i * item_height, size().width(), item_height }); i++; } } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 8572d6d7..d6a35521 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -230,10 +230,7 @@ SystemView::SystemView( }; add_child(&navigation_view); - navigation_view.set_parent_rect({ - { 0, status_view_height }, - { parent_rect.width(), static_cast(parent_rect.height() - status_view_height) } - }); + navigation_view.set_parent_rect({ 0, status_view_height, parent_rect.width(), parent_rect.height() - status_view_height }); navigation_view.on_view_changed = [this](const View& new_view) { this->status_view.set_back_enabled(!this->navigation_view.is_top()); this->status_view.set_title(new_view.title()); diff --git a/firmware/application/ui_rssi.cpp b/firmware/application/ui_rssi.cpp index ab506906..36e8dacf 100644 --- a/firmware/application/ui_rssi.cpp +++ b/firmware/application/ui_rssi.cpp @@ -44,46 +44,31 @@ void RSSI::paint(Painter& painter) { const range_t x_max_range { x_avg + 1, r.width() }; const auto x_max = x_max_range.clip((max_ - raw_min) * r.width() / raw_delta); - const Rect r0 { - static_cast(r.left()), r.top(), - static_cast(x_min), r.height() - }; + const Rect r0 { r.left(), r.top(), x_min, r.height() }; painter.fill_rectangle( r0, Color::blue() ); - const Rect r1 { - static_cast(r.left() + x_min), r.top(), - static_cast(x_avg - x_min), r.height() - }; + const Rect r1 { r.left() + x_min, r.top(), x_avg - x_min, r.height() }; painter.fill_rectangle( r1, Color::red() ); - const Rect r2 { - static_cast(r.left() + x_avg), r.top(), - 1, r.height() - }; + const Rect r2 { r.left() + x_avg, r.top(), 1, r.height() }; painter.fill_rectangle( r2, Color::white() ); - const Rect r3 { - static_cast(r.left() + x_avg + 1), r.top(), - static_cast(x_max - (x_avg + 1)), r.height() - }; + const Rect r3 { r.left() + x_avg + 1, r.top(), x_max - (x_avg + 1), r.height() }; painter.fill_rectangle( r3, Color::red() ); - const Rect r4 { - static_cast(r.left() + x_max), r.top(), - static_cast(r.width() - x_max), r.height() - }; + const Rect r4 { r.left() + x_max, r.top(), r.width() - x_max, r.height() }; painter.fill_rectangle( r4, Color::black() diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index db434d6c..539535dc 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -291,10 +291,7 @@ void ILI9341::fill_circle( const uint32_t d2 = x2 + y2; const bool inside = d2 < radius2; const auto color = inside ? foreground : background; - draw_pixel({ - static_cast(x + center.x()), - static_cast(y + center.y()) - }, color); + draw_pixel({ x + center.x(), y + center.y() }, color); } } } diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 61abaecf..6255a0ab 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -523,9 +523,9 @@ bool ImageButton::on_touch(const TouchEvent event) { OptionsField::OptionsField( Point parent_pos, - size_t length, + int length, options_t options -) : Widget { { parent_pos, { static_cast(8 * length), 16 } } }, +) : Widget { { parent_pos, { 8 * length, 16 } } }, length_ { length }, options { options } { @@ -594,11 +594,11 @@ bool OptionsField::on_touch(const TouchEvent event) { NumberField::NumberField( Point parent_pos, - size_t length, + int length, range_t range, int32_t step, char fill_char -) : Widget { { parent_pos, { static_cast(8 * length), 16 } } }, +) : Widget { { parent_pos, { 8 * length, 16 } } }, range { range }, step { step }, length_ { length }, diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 3ec09d26..68a8fdba 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -273,7 +273,7 @@ public: std::function on_change { }; std::function on_show_options { }; - OptionsField(Point parent_pos, size_t length, options_t options); + OptionsField(Point parent_pos, int length, options_t options); size_t selected_index() const; void set_selected_index(const size_t new_index); @@ -287,7 +287,7 @@ public: bool on_touch(const TouchEvent event) override; private: - const size_t length_; + const int length_; options_t options; size_t selected_index_ { 0 }; }; @@ -298,7 +298,7 @@ public: using range_t = std::pair; - NumberField(Point parent_pos, size_t length, range_t range, int32_t step, char fill_char); + NumberField(Point parent_pos, int length, range_t range, int32_t step, char fill_char); NumberField(const NumberField&) = delete; NumberField(NumberField&&) = delete; @@ -314,7 +314,7 @@ public: private: const range_t range; const int32_t step; - const size_t length_; + const int length_; const char fill_char; int32_t value_ { 0 }; From f2dd6827eab132c283f565abe9d087b57df3a5a3 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 6 Dec 2016 09:28:48 -0800 Subject: [PATCH 088/100] Add Widget::parent_rect() accessor, rename member variable. Some day I will settle on a convention for naming members... I think that day is near. --- firmware/common/ui_widget.cpp | 14 +++++++++----- firmware/common/ui_widget.hpp | 7 ++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 6255a0ab..88d5cc16 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -53,15 +53,19 @@ Point Widget::screen_pos() { } Size Widget::size() const { - return parent_rect.size(); + return _parent_rect.size(); } Rect Widget::screen_rect() const { - return parent() ? (parent_rect + parent()->screen_pos()) : parent_rect; + return parent() ? (parent_rect() + parent()->screen_pos()) : parent_rect(); +} + +Rect Widget::parent_rect() const { + return _parent_rect; } void Widget::set_parent_rect(const Rect new_parent_rect) { - parent_rect = new_parent_rect; + _parent_rect = new_parent_rect; set_dirty(); } @@ -106,7 +110,7 @@ void Widget::hidden(bool hide) { if( hide ) { // TODO: Instead of dirtying parent entirely, dirty only children // that overlap with this widget. - parent()->dirty_overlapping_children_in_rect(parent_rect); + parent()->dirty_overlapping_children_in_rect(parent_rect()); /* TODO: Notify self and all non-hidden children that they're * now effectively hidden? */ @@ -214,7 +218,7 @@ void Widget::set_highlighted(const bool value) { void Widget::dirty_overlapping_children_in_rect(const Rect& child_rect) { for(auto child : children()) { - if( !child_rect.intersect(child->parent_rect).is_empty() ) { + if( !child_rect.intersect(child->parent_rect()).is_empty() ) { child->set_dirty(); } } diff --git a/firmware/common/ui_widget.hpp b/firmware/common/ui_widget.hpp index 68a8fdba..6a081b6f 100644 --- a/firmware/common/ui_widget.hpp +++ b/firmware/common/ui_widget.hpp @@ -52,13 +52,13 @@ private: class Widget { public: Widget( - ) : parent_rect { } + ) : _parent_rect { } { } Widget( Rect parent_rect - ) : parent_rect { parent_rect } + ) : _parent_rect { parent_rect } { } @@ -72,6 +72,7 @@ public: Point screen_pos(); Size size() const; Rect screen_rect() const; + Rect parent_rect() const; virtual void set_parent_rect(const Rect new_parent_rect); Widget* parent() const; @@ -119,7 +120,7 @@ protected: private: /* Widget rectangle relative to parent pos(). */ - Rect parent_rect; + Rect _parent_rect; const Style* style_ { nullptr }; Widget* parent_ { nullptr }; From 431aae333a696dda21573ffaa3eed4de263f2e9e Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 6 Dec 2016 09:34:45 -0800 Subject: [PATCH 089/100] Move additional FR_* error values to file.hpp for public use. --- firmware/application/file.cpp | 7 ------- firmware/application/file.hpp | 10 ++++++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index ae846892..ef7dc3ed 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -25,13 +25,6 @@ #include #include -/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */ -static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected."); -#define FR_DISK_FULL (0x100) -#define FR_EOF (0x101) -#define FR_BAD_SEEK (0x102) -#define FR_UNEXPECTED (0x103) - Optional File::open_fatfs(const std::filesystem::path& filename, BYTE mode) { auto result = f_open(&f, reinterpret_cast(filename.c_str()), mode); if( result == FR_OK ) { diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index 4c59f7f0..42cce7f5 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -233,6 +233,16 @@ space_info space(const path& p); std::filesystem::path next_filename_stem_matching_pattern(std::filesystem::path filename_stem_pattern); +/* Values added to FatFs FRESULT enum, values outside the FRESULT data type */ +static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected."); + +/* Dangerous to expose these, as FatFs native error values are byte-sized. However, + * my filesystem_error implemetation is fine with it. */ +#define FR_DISK_FULL (0x100) +#define FR_EOF (0x101) +#define FR_BAD_SEEK (0x102) +#define FR_UNEXPECTED (0x103) + class File { public: using Size = uint64_t; From ad9a63a66606001e1047b044cb6924e5e51c321c Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 21 Dec 2016 22:20:28 -0800 Subject: [PATCH 090/100] GPIO: Fix apparent dumb bit-logic bug. Not due to any observable incorrect behavior, but just noticing that the code, as previously written, should not work... --- firmware/common/gpio.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/common/gpio.hpp b/firmware/common/gpio.hpp index 0f02d6ec..97e69952 100644 --- a/firmware/common/gpio.hpp +++ b/firmware/common/gpio.hpp @@ -37,12 +37,12 @@ struct PinConfig { constexpr operator uint16_t() { return - ((~ifilt) << 7) - | (input << 6) - | (fast << 5) - | ((~pu) << 4) - | (pd << 3) - | (mode << 0); + (((~ifilt) & 1) << 7) + | ((input & 1) << 6) + | ((fast & 1) << 5) + | (((~pu) & 1) << 4) + | ((pd & 1) << 3) + | ((mode & 1) << 0); } /* constexpr operator uint32_t() { From 01cd8c7776d4ab5ebcdeedad504700e2a61acf35 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Wed, 21 Dec 2016 22:24:07 -0800 Subject: [PATCH 091/100] GPIO: Fix PinConfig -> uint16_t type conversion signature. --- firmware/common/gpio.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/gpio.hpp b/firmware/common/gpio.hpp index 97e69952..69e12c91 100644 --- a/firmware/common/gpio.hpp +++ b/firmware/common/gpio.hpp @@ -35,7 +35,7 @@ struct PinConfig { const uint32_t input; const uint32_t ifilt; - constexpr operator uint16_t() { + constexpr operator uint16_t() const { return (((~ifilt) & 1) << 7) | ((input & 1) << 6) From 0ea2f9650e6b915c285635025e7e1b810482c4c2 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 5 Jan 2017 17:06:44 -0800 Subject: [PATCH 092/100] C++14: const all the methods! --- firmware/application/si5351.hpp | 26 +++++++++++++------------- firmware/common/i2c_pp.hpp | 6 +++--- firmware/common/memory_map.hpp | 6 +++--- firmware/common/spi_image.hpp | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/firmware/application/si5351.hpp b/firmware/application/si5351.hpp index e76a4bbb..58104f82 100644 --- a/firmware/application/si5351.hpp +++ b/firmware/application/si5351.hpp @@ -168,7 +168,7 @@ struct Inputs { const uint32_t f_clkin; const uint32_t clkin_div; - constexpr uint32_t f_clkin_out() { + constexpr uint32_t f_clkin_out() const { return f_clkin / clkin_div; } }; @@ -181,23 +181,23 @@ struct PLL { const uint32_t b; const uint32_t c; - constexpr uint32_t f_vco() { + constexpr uint32_t f_vco() const { return f_in * (a + (float)b / (float)c); } - constexpr uint32_t p1() { + constexpr uint32_t p1() const { return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512; } - constexpr uint32_t p2() { + constexpr uint32_t p2() const { return 128 * b - c * (uint32_t)(128 * (float)b / (float)c); } - constexpr uint32_t p3() { + constexpr uint32_t p3() const { return c; } - constexpr PLLReg reg(const uint8_t pll_n) { + constexpr PLLReg reg(const uint8_t pll_n) const { return { uint8_t(26 + (pll_n * 8)), uint8_t((p3() >> 8) & 0xff), @@ -224,23 +224,23 @@ struct MultisynthFractional { const uint32_t c; const uint32_t r_div; - constexpr uint32_t p1() { + constexpr uint32_t p1() const { return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512; } - constexpr uint32_t p2() { + constexpr uint32_t p2() const { return 128 * b - c * (uint32_t)(128 * (float)b / (float)c); } - constexpr uint32_t p3() { + constexpr uint32_t p3() const { return c; } - constexpr uint32_t f_out() { + constexpr uint32_t f_out() const { return f_src / (a + (float)b / (float)c) / (1 << r_div); } - constexpr MultisynthFractionalReg reg(const uint8_t multisynth_n) { + constexpr MultisynthFractionalReg reg(const uint8_t multisynth_n) const { return { uint8_t(42 + (multisynth_n * 8)), uint8_t((p3() >> 8) & 0xFF), @@ -260,11 +260,11 @@ struct MultisynthInteger { const uint32_t a; const uint32_t r_div; - constexpr uint8_t p1() { + constexpr uint8_t p1() const { return a; } - constexpr uint32_t f_out() { + constexpr uint32_t f_out() const { return f_src / a / (1 << r_div); } }; diff --git a/firmware/common/i2c_pp.hpp b/firmware/common/i2c_pp.hpp index 7eabab0b..62f729e7 100644 --- a/firmware/common/i2c_pp.hpp +++ b/firmware/common/i2c_pp.hpp @@ -46,15 +46,15 @@ struct I2CClockConfig { return 1e9 / f; } - constexpr uint32_t i2c_period_count() { + constexpr uint32_t i2c_period_count() const { return period_ns(bus_f) / period_ns(clock_source_f) + 0.5f; } - constexpr uint32_t i2c_high_count() { + constexpr uint32_t i2c_high_count() const { return high_period_ns / period_ns(clock_source_f) + 0.5f; } - constexpr uint32_t i2c_low_count() { + constexpr uint32_t i2c_low_count() const { return i2c_period_count() - i2c_high_count(); } }; diff --git a/firmware/common/memory_map.hpp b/firmware/common/memory_map.hpp index 8b32a0cd..d8624d74 100644 --- a/firmware/common/memory_map.hpp +++ b/firmware/common/memory_map.hpp @@ -43,15 +43,15 @@ public: } - constexpr uint32_t base() { + constexpr uint32_t base() const { return base_; } - constexpr uint32_t end() { + constexpr uint32_t end() const { return base_ + size_; } - constexpr size_t size() { + constexpr size_t size() const { return size_; } diff --git a/firmware/common/spi_image.hpp b/firmware/common/spi_image.hpp index e1143712..7b53fd75 100644 --- a/firmware/common/spi_image.hpp +++ b/firmware/common/spi_image.hpp @@ -86,7 +86,7 @@ struct region_t { const size_t offset; const size_t size; - constexpr const void* base() { + constexpr const void* base() const { return reinterpret_cast(portapack::memory::map::spifi_cached.base() + offset); } }; From a22dc150bc4326295f27c5fa854cb81e56179e95 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 5 Jan 2017 17:10:00 -0800 Subject: [PATCH 093/100] C++14: make some wrapper classes static. Also address GCC 6.2 not allowing constexpr from reinterpret_cast<> values. --- firmware/application/touch_adc.cpp | 10 ++--- firmware/baseband/rssi.cpp | 12 +++--- firmware/common/adc.hpp | 65 ++++++++++++++---------------- firmware/common/hackrf_hal.hpp | 4 +- firmware/common/i2s.hpp | 46 +++++++++++---------- 5 files changed, 68 insertions(+), 69 deletions(-) diff --git a/firmware/application/touch_adc.cpp b/firmware/application/touch_adc.cpp index be731282..91748ff2 100644 --- a/firmware/application/touch_adc.cpp +++ b/firmware/application/touch_adc.cpp @@ -57,14 +57,14 @@ constexpr lpc43xx::adc::Config adc0_config { }; void init() { - adc0.clock_enable(); - adc0.interrupts_disable(); - adc0.power_up(adc0_config); - adc0.interrupts_enable(adc0_interrupt_mask); + adc0::clock_enable(); + adc0::interrupts_disable(); + adc0::power_up(adc0_config); + adc0::interrupts_enable(adc0_interrupt_mask); } void start() { - adc0.start_burst(); + adc0::start_burst(); } // static constexpr bool monitor_overruns_and_not_dones = false; diff --git a/firmware/baseband/rssi.cpp b/firmware/baseband/rssi.cpp index 2e9cfa32..1abf10a1 100644 --- a/firmware/baseband/rssi.cpp +++ b/firmware/baseband/rssi.cpp @@ -52,22 +52,22 @@ constexpr adc::Config adc1_config { }; void init() { - adc1.clock_enable(); - adc1.interrupts_disable(); - adc1.power_up(adc1_config); - adc1.interrupts_enable(adc1_interrupt_mask); + adc1::clock_enable(); + adc1::interrupts_disable(); + adc1::power_up(adc1_config); + adc1::interrupts_enable(adc1_interrupt_mask); dma::init(); } void start() { dma::enable(); - adc1.start_burst(); + adc1::start_burst(); } void stop() { dma::disable(); - adc1.stop_burst(); + adc1::stop_burst(); } } /* namespace rssi */ diff --git a/firmware/common/adc.hpp b/firmware/common/adc.hpp index e419ee22..71414666 100644 --- a/firmware/common/adc.hpp +++ b/firmware/common/adc.hpp @@ -52,84 +52,81 @@ struct Config { uint32_t cr; }; +template class ADC { public: - constexpr ADC( - LPC_ADCx_Type* adcp - ) : adcp(adcp) - { + static void power_up(const Config config) { + adcp().CR = config.cr; } - void power_up(const Config config) const { - adcp->CR = config.cr; - } - - void clock_enable() const { - if( adcp == LPC_ADC0 ) { + static void clock_enable() { + if( &adcp() == LPC_ADC0 ) { LPC_CCU1->CLK_APB3_ADC0_CFG.AUTO = 1; LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 1; } - if( adcp == LPC_ADC1 ) { + if( &adcp() == LPC_ADC1 ) { LPC_CCU1->CLK_APB3_ADC1_CFG.AUTO = 1; LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 1; } } - void clock_disable() const { - if( adcp == LPC_ADC0 ) { + static void clock_disable() { + if( &adcp() == LPC_ADC0 ) { LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 0; } - if( adcp == LPC_ADC1 ) { + if( &adcp() == LPC_ADC1 ) { LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 0; } } - void disable() const { - adcp->INTEN = 0; - adcp->CR = 0; + static void disable() { + adcp().INTEN = 0; + adcp().CR = 0; clock_disable(); } - void interrupts_disable() const { - adcp->INTEN = 0; + static void interrupts_disable() { + adcp().INTEN = 0; } - void interrupts_enable(const uint32_t mask) const { - adcp->INTEN = mask; + static void interrupts_enable(const uint32_t mask) { + adcp().INTEN = mask; } - void start_burst() const { - adcp->CR |= (1U << 16); + static void start_burst() { + adcp().CR |= (1U << 16); } - void start_once() const { - adcp->CR |= (1U << 24); + static void start_once() { + adcp().CR |= (1U << 24); } - void start_once(size_t n) const { - uint32_t cr = adcp->CR; + static void start_once(size_t n) { + uint32_t cr = adcp().CR; cr &= ~(0xffU); cr |= (1 << 24) | (1 << n); - adcp->CR = cr; + adcp().CR = cr; } - void stop_burst() const { - adcp->CR &= ~(1U << 16); + static void stop_burst() { + adcp().CR &= ~(1U << 16); } - uint32_t convert(size_t n) const { + static uint32_t convert(size_t n) { start_once(n); while(true) { - const uint32_t data = adcp->DR[n]; + const uint32_t data = adcp().DR[n]; if( (data >> 31) & 1 ) { return (data >> 6) & 0x3ff; } } } - + private: - LPC_ADCx_Type* const adcp; + static LPC_ADCx_Type& adcp() { + return *reinterpret_cast(BaseAddress); + } }; } /* namespace adc */ diff --git a/firmware/common/hackrf_hal.hpp b/firmware/common/hackrf_hal.hpp index 8b41f0a3..b7d5e1c0 100644 --- a/firmware/common/hackrf_hal.hpp +++ b/firmware/common/hackrf_hal.hpp @@ -67,11 +67,11 @@ constexpr size_t clock_generator_output_mcu_clkin = 7; /* ADC0 */ -constexpr adc::ADC adc0 { LPC_ADC0 }; +using adc0 = adc::ADC; /* ADC1 */ -constexpr adc::ADC adc1 { LPC_ADC1 }; +using adc1 = adc::ADC; void reset(); diff --git a/firmware/common/i2s.hpp b/firmware/common/i2s.hpp index b7d4d46a..0ddaa966 100644 --- a/firmware/common/i2s.hpp +++ b/firmware/common/i2s.hpp @@ -155,8 +155,6 @@ struct ConfigDMA { template class I2S { public: - static constexpr LPC_I2S_Type* Peripheral = reinterpret_cast(BaseAddress); - static void configure( const ConfigTX& config_tx, const ConfigRX& config_rx @@ -167,28 +165,28 @@ public: /* NOTE: Documentation of CREG6 is quite confusing. Refer to "I2S clocking and * pin connections" and other I2S diagrams for more clarity. */ - if( Peripheral == LPC_I2S0 ) { + if( &p() == LPC_I2S0 ) { LPC_CREG->CREG6 |= (1U << 12) | (1U << 13) ; } - if( Peripheral == LPC_I2S1 ) { + if( &p() == LPC_I2S1 ) { LPC_CREG->CREG6 |= (1U << 14) | (1U << 15) ; } - Peripheral->DAO = config_tx.dao; - Peripheral->TXRATE = config_tx.txrate; - Peripheral->TXBITRATE = config_tx.txbitrate; - Peripheral->TXMODE = config_tx.txmode; + p().DAO = config_tx.dao; + p().TXRATE = config_tx.txrate; + p().TXBITRATE = config_tx.txbitrate; + p().TXMODE = config_tx.txmode; - Peripheral->DAI = config_rx.dai; - Peripheral->RXRATE = config_rx.rxrate; - Peripheral->RXBITRATE = config_rx.rxbitrate; - Peripheral->RXMODE = config_rx.rxmode; + p().DAI = config_rx.dai; + p().RXRATE = config_rx.rxrate; + p().RXBITRATE = config_rx.rxbitrate; + p().RXMODE = config_rx.rxmode; } static void configure( @@ -198,38 +196,42 @@ public: ) { configure(config_tx, config_rx); - Peripheral->DMA1 = config_dma.dma1; - Peripheral->DMA2 = config_dma.dma2; + p().DMA1 = config_dma.dma1; + p().DMA2 = config_dma.dma2; } static void rx_start() { - Peripheral->DAI &= ~(1U << 3); + p().DAI &= ~(1U << 3); } static void rx_stop() { - Peripheral->DAI |= (1U << 3); + p().DAI |= (1U << 3); } static void tx_start() { - Peripheral->DAO &= ~(1U << 3); + p().DAO &= ~(1U << 3); } static void tx_stop() { - Peripheral->DAO |= (1U << 3); + p().DAO |= (1U << 3); } static void tx_mute() { - Peripheral->DAO |= (1U << 15); + p().DAO |= (1U << 15); } static void tx_unmute() { - Peripheral->DAO &= ~(1U << 15); + p().DAO &= ~(1U << 15); } private: static void reset() { - Peripheral->DAO |= (1U << 4); - Peripheral->DAI |= (1U << 4); + p().DAO |= (1U << 4); + p().DAI |= (1U << 4); + } + + static LPC_I2S_Type& p() { + return *reinterpret_cast(BaseAddress); } }; From 0d1e48ae9cb3f29bc201c462f3e738424e8b1239 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 5 Jan 2017 17:13:03 -0800 Subject: [PATCH 094/100] C++14: Add two-argument delete() implementations. Just passing to one-argument versions. --- firmware/common/chibios_cpp.cpp | 8 ++++++++ firmware/common/chibios_cpp.hpp | 2 ++ 2 files changed, 10 insertions(+) diff --git a/firmware/common/chibios_cpp.cpp b/firmware/common/chibios_cpp.cpp index eab2fcb0..d148ca1d 100644 --- a/firmware/common/chibios_cpp.cpp +++ b/firmware/common/chibios_cpp.cpp @@ -41,6 +41,14 @@ void operator delete[](void* p) noexcept { chHeapFree(p); } +void operator delete(void* ptr, std::size_t) noexcept { + ::operator delete(ptr); +} + +void operator delete[](void* ptr, std::size_t) noexcept { + ::operator delete(ptr); +} + extern uint8_t __heap_base__[]; extern uint8_t __heap_end__[]; diff --git a/firmware/common/chibios_cpp.hpp b/firmware/common/chibios_cpp.hpp index 5cb4af2e..fd952aaf 100644 --- a/firmware/common/chibios_cpp.hpp +++ b/firmware/common/chibios_cpp.hpp @@ -30,6 +30,8 @@ void* operator new(size_t size); void* operator new[](size_t size); void operator delete(void* p); void operator delete[](void* p); +void operator delete(void* ptr, std::size_t); +void operator delete[](void* ptr, std::size_t); namespace chibios { From 87383d735cb6de4d179e0933e538775db6bda4e5 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 5 Jan 2017 17:14:07 -0800 Subject: [PATCH 095/100] C++14: Decommission my own make_unique. --- firmware/baseband/baseband_thread.cpp | 2 ++ firmware/common/utility.hpp | 42 --------------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/firmware/baseband/baseband_thread.cpp b/firmware/baseband/baseband_thread.cpp index 8901f528..7083e9f4 100644 --- a/firmware/baseband/baseband_thread.cpp +++ b/firmware/baseband/baseband_thread.cpp @@ -33,6 +33,8 @@ using namespace lpc43xx; #include "portapack_shared_memory.hpp" +#include "utility.hpp" + #include static baseband::SGPIO baseband_sgpio; diff --git a/firmware/common/utility.hpp b/firmware/common/utility.hpp index c6cfab94..feab67ec 100644 --- a/firmware/common/utility.hpp +++ b/firmware/common/utility.hpp @@ -113,46 +113,4 @@ struct range_t { } }; -namespace std { - -/*! Stephan T Lavavej (STL!) implementation of make_unique, which has been accepted into the C++14 standard. - * It includes handling for arrays. - * Paper here: http://isocpp.org/files/papers/N3656.txt - */ -template struct _Unique_if { - typedef unique_ptr _Single_object; -}; - -//! Specialization for unbound array -template struct _Unique_if { - typedef unique_ptr _Unknown_bound; -}; - -//! Specialization for array of known size -template struct _Unique_if { - typedef void _Known_bound; -}; - -//! Specialization for normal object type -template -typename _Unique_if::_Single_object -make_unique(Args&& ... args) { - return unique_ptr(new T(std::forward(args)...)); -} - -//! Specialization for unknown bound -template -typename _Unique_if::_Unknown_bound -make_unique(size_t n) { - typedef typename remove_extent::type U; - return unique_ptr(new U[n]()); -} - -//! Deleted specialization -template -typename _Unique_if::_Known_bound -make_unique(Args&& ...) = delete; - -} /* namespace std */ - #endif/*__UTILITY_H__*/ From e763592adbdb2fc8d0a281ba7a3d7e9899760fe6 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Thu, 5 Jan 2017 17:15:00 -0800 Subject: [PATCH 096/100] Compile firmware as C++14. --- firmware/application/CMakeLists.txt | 2 +- firmware/baseband/CMakeLists.txt | 2 +- firmware/bootstrap/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index d0860c15..0243f760 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -35,7 +35,7 @@ set(USE_OPT "-Os -g --specs=nano.specs") set(USE_COPT "-std=gnu99") # C++ specific options here (added to USE_OPT). -set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") +set(USE_CPPOPT "-std=c++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") # Enable this if you want the linker to remove unused code and data set(USE_LINK_GC yes) diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index faf5c2cb..b6230dfe 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -35,7 +35,7 @@ set(USE_OPT "-O3 -g -falign-functions=16 -fno-math-errno --specs=nano.specs") set(USE_COPT "-std=gnu99") # C++ specific options here (added to USE_OPT). -set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") +set(USE_CPPOPT "-std=c++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") # Enable this if you want the linker to remove unused code and data set(USE_LINK_GC yes) diff --git a/firmware/bootstrap/CMakeLists.txt b/firmware/bootstrap/CMakeLists.txt index 6756f5b0..0c5e4a29 100644 --- a/firmware/bootstrap/CMakeLists.txt +++ b/firmware/bootstrap/CMakeLists.txt @@ -35,7 +35,7 @@ set(USE_OPT "-Os -g -falign-functions=16 -fno-math-errno --specs=nano.specs") set(USE_COPT "-std=gnu99") # C++ specific options here (added to USE_OPT). -set(USE_CPPOPT "-std=c++11 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") +set(USE_CPPOPT "-std=c++14 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized") # Enable this if you want the linker to remove unused code and data set(USE_LINK_GC yes) From 177d49b769331a1aeb63ec589b1d54c2ebc93dca Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 6 Jan 2017 14:22:27 -0800 Subject: [PATCH 097/100] GPIO: Fix for incorrect pin-funciton bit mask. Caused device to not boot. Oops. --- firmware/common/gpio.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/gpio.hpp b/firmware/common/gpio.hpp index 69e12c91..75c729c5 100644 --- a/firmware/common/gpio.hpp +++ b/firmware/common/gpio.hpp @@ -42,7 +42,7 @@ struct PinConfig { | ((fast & 1) << 5) | (((~pu) & 1) << 4) | ((pd & 1) << 3) - | ((mode & 1) << 0); + | ((mode & 7) << 0); } /* constexpr operator uint32_t() { From 1986d1faca61117a4a1de9b286458d57c59fe697 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 6 Jan 2017 14:28:41 -0800 Subject: [PATCH 098/100] Travis-CI: Update compiler to ARM-GCC 6.2. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 363625ea..b3cfb7f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,9 @@ notifications: - "Firmware download : https://portapack-h1-builds.s3.amazonaws.com/%{repository_slug}/%{build_number}/%{build_number}.1/build/firmware/portapack-h1-firmware-%{commit}.tar.bz2" before_script: - - wget https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q3-update/+download/gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2 + - wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2016q4/gcc-arm-none-eabi-6_2-2016q4-20161216-linux.tar.bz2 -O /tmp/gcc-arm.tar.bz2 - tar -xf /tmp/gcc-arm.tar.bz2 - - export PATH=$PWD/gcc-arm-none-eabi-5_4-2016q3/bin:$PATH + - export PATH=$PWD/gcc-arm-none-eabi-6_2-2016q4/bin:$PATH - export CC="arm-none-eabi-gcc" - export CXX="arm-none-eabi-g++" From 05eb694c0a9d29e3098e396b53a7e0fb05fe9b93 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 6 Jan 2017 16:57:36 -0800 Subject: [PATCH 099/100] Introduce simd32_t type. Discontinue use of disagreeable __SIMD #define. --- firmware/baseband/channel_stats_collector.hpp | 8 +- firmware/baseband/dsp_decimate.cpp | 78 ++++++++++--------- firmware/baseband/dsp_demodulate.cpp | 27 +++---- .../os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h | 6 -- firmware/common/simd.hpp | 24 ++++++ 5 files changed, 83 insertions(+), 60 deletions(-) diff --git a/firmware/baseband/channel_stats_collector.hpp b/firmware/baseband/channel_stats_collector.hpp index ca7d0eed..44d70753 100644 --- a/firmware/baseband/channel_stats_collector.hpp +++ b/firmware/baseband/channel_stats_collector.hpp @@ -23,6 +23,7 @@ #define __CHANNEL_STATS_COLLECTOR_H__ #include "dsp_types.hpp" +#include "simd.hpp" #include "message.hpp" #include "utility.hpp" @@ -35,9 +36,10 @@ class ChannelStatsCollector { public: template void feed(const buffer_c16_t& src, Callback callback) { - auto src_p = src.p; - while(src_p < &src.p[src.count]) { - const uint32_t sample = *__SIMD32(src_p)++; + auto src_p = simd32_ptr(src.p); + const auto end_p = simd32_ptr(&src.p[src.count]); + while(src_p < end_p) { + const uint32_t sample = *(src_p++); const uint32_t mag_sq = __SMUAD(sample, sample); if( mag_sq > max_squared ) { max_squared = mag_sq; diff --git a/firmware/baseband/dsp_decimate.cpp b/firmware/baseband/dsp_decimate.cpp index 93dbc602..09aa45df 100644 --- a/firmware/baseband/dsp_decimate.cpp +++ b/firmware/baseband/dsp_decimate.cpp @@ -21,6 +21,8 @@ #include "dsp_decimate.hpp" +#include "simd.hpp" + #include namespace dsp { @@ -566,39 +568,39 @@ buffer_c16_t DecimateBy2CIC3::execute( uint32_t t1 = _iq0; uint32_t t2 = _iq1; const uint32_t taps = 0x00000003; - auto s = src.p; - auto d = dst.p; - const auto d_end = &dst.p[src.count / 2]; + auto s = simd32_ptr(&src.p[0]); + auto d = simd32_ptr(&dst.p[0]); + const auto d_end = simd32_ptr(&dst.p[src.count / 2]); while(d < d_end) { uint32_t i = __SXTH(t1, 0); /* 1: I0 */ uint32_t q = __SXTH(t1, 16); /* 1: Q0 */ i = __SMLABB(t2, taps, i); /* 1: I1*3 + I0 */ q = __SMLATB(t2, taps, q); /* 1: Q1*3 + Q0 */ - const uint32_t t3 = *__SIMD32(s)++; /* 3: Q2:I2 */ - const uint32_t t4 = *__SIMD32(s)++; /* Q3:I3 */ + const uint32_t t3 = *(s++); /* 3: Q2:I2 */ + const uint32_t t4 = *(s++); /* Q3:I3 */ i = __SMLABB(t3, taps, i); /* 1: I2*3 + I1*3 + I0 */ q = __SMLATB(t3, taps, q); /* 1: Q2*3 + Q1*3 + Q0 */ int32_t si0 = __SXTAH(i, t4, 0); /* 1: I3 + Q2*3 + Q1*3 + Q0 */ int32_t sq0 = __SXTAH(q, t4, 16); /* 1: Q3 + Q2*3 + Q1*3 + Q0 */ i = __BFI(si0 / 8, sq0 / 8, 16, 16); /* 1: D2_Q0:D2_I0 */ - *__SIMD32(d)++ = i; /* D2_Q0:D2_I0 */ + *(d++) = i; /* D2_Q0:D2_I0 */ i = __SXTH(t3, 0); /* 1: I2 */ q = __SXTH(t3, 16); /* 1: Q2 */ i = __SMLABB(t4, taps, i); /* 1: I3*3 + I2 */ q = __SMLATB(t4, taps, q); /* 1: Q3*3 + Q2 */ - t1 = *__SIMD32(s)++; /* 3: Q4:I4 */ - t2 = *__SIMD32(s)++; /* Q5:I5 */ + t1 = *(s++); /* 3: Q4:I4 */ + t2 = *(s++); /* Q5:I5 */ i = __SMLABB(t1, taps, i); /* 1: I4*3 + I3*3 + I2 */ q = __SMLATB(t1, taps, q); /* 1: Q4*3 + Q3*3 + Q2 */ int32_t si1 = __SXTAH(i, t2, 0) ; /* 1: I5 + Q4*3 + Q3*3 + Q2 */ int32_t sq1 = __SXTAH(q, t2, 16); /* 1: Q5 + Q4*3 + Q3*3 + Q2 */ i = __BFI(si1 / 8, sq1 / 8, 16, 16); /* 1: D2_Q1:D2_I1 */ - *__SIMD32(d)++ = i; /* D2_Q1:D2_I1 */ + *(d++) = i; /* D2_Q1:D2_I1 */ } _iq0 = t1; _iq1 = t2; @@ -665,57 +667,57 @@ buffer_c16_t FIRAndDecimateComplex::execute( const auto output_sampling_rate = src.sampling_rate / decimation_factor_; const size_t output_samples = src.count / decimation_factor_; - sample_t* dst_p = dst.p; + auto dst_p = simd32_ptr(dst.p); const buffer_c16_t result { dst.p, output_samples, output_sampling_rate }; - const sample_t* src_p = src.p; + auto src_p = simd32_ptr(src.p); size_t outer_count = output_samples; while(outer_count > 0) { /* Put new samples into delay buffer */ - auto z_new_p = &samples_[taps_count_ - decimation_factor_]; + auto z_new_p = simd32_ptr(&samples_[taps_count_ - decimation_factor_]); for(size_t i=0; i 0) { - const auto tap0 = *__SIMD32(t_p)++; - const auto sample0 = *__SIMD32(z_p)++; - const auto tap1 = *__SIMD32(t_p)++; - const auto sample1 = *__SIMD32(z_p)++; + const auto tap0 = *(t_p++); + const auto sample0 = *(z_p++); + const auto tap1 = *(t_p++); + const auto sample1 = *(z_p++); t_real = __SMLSLD(sample0, tap0, t_real); t_imag = __SMLALDX(sample0, tap0, t_imag); t_real = __SMLSLD(sample1, tap1, t_real); t_imag = __SMLALDX(sample1, tap1, t_imag); - const auto tap2 = *__SIMD32(t_p)++; - const auto sample2 = *__SIMD32(z_p)++; - const auto tap3 = *__SIMD32(t_p)++; - const auto sample3 = *__SIMD32(z_p)++; + const auto tap2 = *(t_p++); + const auto sample2 = *(z_p++); + const auto tap3 = *(t_p++); + const auto sample3 = *(z_p++); t_real = __SMLSLD(sample2, tap2, t_real); t_imag = __SMLALDX(sample2, tap2, t_imag); t_real = __SMLSLD(sample3, tap3, t_real); t_imag = __SMLALDX(sample3, tap3, t_imag); - const auto tap4 = *__SIMD32(t_p)++; - const auto sample4 = *__SIMD32(z_p)++; - const auto tap5 = *__SIMD32(t_p)++; - const auto sample5 = *__SIMD32(z_p)++; + const auto tap4 = *(t_p++); + const auto sample4 = *(z_p++); + const auto tap5 = *(t_p++); + const auto sample5 = *(z_p++); t_real = __SMLSLD(sample4, tap4, t_real); t_imag = __SMLALDX(sample4, tap4, t_imag); t_real = __SMLSLD(sample5, tap5, t_real); t_imag = __SMLALDX(sample5, tap5, t_imag); - const auto tap6 = *__SIMD32(t_p)++; - const auto sample6 = *__SIMD32(z_p)++; - const auto tap7 = *__SIMD32(t_p)++; - const auto sample7 = *__SIMD32(z_p)++; + const auto tap6 = *(t_p++); + const auto sample6 = *(z_p++); + const auto tap7 = *(t_p++); + const auto sample7 = *(z_p++); t_real = __SMLSLD(sample6, tap6, t_real); t_imag = __SMLALDX(sample6, tap6, t_imag); t_real = __SMLSLD(sample7, tap7, t_real); @@ -731,7 +733,7 @@ buffer_c16_t FIRAndDecimateComplex::execute( const int32_t i = t_imag >> 16; const int32_t r_sat = __SSAT(r, 16); const int32_t i_sat = __SSAT(i, 16); - *__SIMD32(dst_p)++ = __PKHBT( + *(dst_p++) = __PKHBT( r_sat, i_sat, 16 @@ -741,14 +743,14 @@ buffer_c16_t FIRAndDecimateComplex::execute( const size_t unroll_factor = 4; size_t shift_count = (taps_count_ - decimation_factor_) / unroll_factor; - sample_t* t = &samples_[0]; - const sample_t* s = &samples_[decimation_factor_]; + auto t = simd32_ptr(&samples_[0]); + auto s = simd32_ptr(&samples_[decimation_factor_]); while(shift_count > 0) { - *__SIMD32(t)++ = *__SIMD32(s)++; - *__SIMD32(t)++ = *__SIMD32(s)++; - *__SIMD32(t)++ = *__SIMD32(s)++; - *__SIMD32(t)++ = *__SIMD32(s)++; + *(t++) = *(s++); + *(t++) = *(s++); + *(t++) = *(s++); + *(t++) = *(s++); shift_count--; } diff --git a/firmware/baseband/dsp_demodulate.cpp b/firmware/baseband/dsp_demodulate.cpp index cf79d0d0..22348a35 100644 --- a/firmware/baseband/dsp_demodulate.cpp +++ b/firmware/baseband/dsp_demodulate.cpp @@ -24,6 +24,7 @@ #include "complex.hpp" #include "fxpt_atan2.hpp" #include "utility_m4.hpp" +#include "simd.hpp" #include @@ -34,12 +35,12 @@ buffer_f32_t AM::execute( const buffer_c16_t& src, const buffer_f32_t& dst ) { - const auto src_p = src.p; - const auto src_end = &src.p[src.count]; + auto src_p = simd32_ptr(src.p); + auto src_end = simd32_ptr(&src.p[src.count]); auto dst_p = dst.p; while(src_p < src_end) { - const uint32_t sample0 = *__SIMD32(src_p)++; - const uint32_t sample1 = *__SIMD32(src_p)++; + const uint32_t sample0 = *(src_p++); + const uint32_t sample1 = *(src_p++); const uint32_t mag_sq0 = __SMUAD(sample0, sample0); const uint32_t mag_sq1 = __SMUAD(sample1, sample1); *(dst_p++) = __builtin_sqrtf(mag_sq0) * k; @@ -90,12 +91,12 @@ buffer_f32_t FM::execute( ) { auto z = z_; - const auto src_p = src.p; - const auto src_end = &src.p[src.count]; + auto src_p = simd32_ptr(src.p); + auto src_end = simd32_ptr(&src.p[src.count]); auto dst_p = dst.p; while(src_p < src_end) { - const auto s0 = *__SIMD32(src_p)++; - const auto s1 = *__SIMD32(src_p)++; + const auto s0 = *(src_p++); + const auto s1 = *(src_p++); const auto t0 = multiply_conjugate_s16_s32(s0, z); const auto t1 = multiply_conjugate_s16_s32(s1, s0); z = s1; @@ -113,12 +114,12 @@ buffer_s16_t FM::execute( ) { auto z = z_; - const auto src_p = src.p; - const auto src_end = &src.p[src.count]; + auto src_p = simd32_ptr(src.p); + auto src_end = simd32_ptr(&src.p[src.count]); auto dst_p = dst.p; while(src_p < src_end) { - const auto s0 = *__SIMD32(src_p)++; - const auto s1 = *__SIMD32(src_p)++; + const auto s0 = *(src_p++); + const auto s1 = *(src_p++); const auto t0 = multiply_conjugate_s16_s32(s0, z); const auto t1 = multiply_conjugate_s16_s32(s1, s0); z = s1; @@ -126,7 +127,7 @@ buffer_s16_t FM::execute( const int32_t theta0_sat = __SSAT(theta0_int, 16); const int32_t theta1_int = angle_approx_0deg27(t1) * ks16; const int32_t theta1_sat = __SSAT(theta1_int, 16); - *__SIMD32(dst_p)++ = __PKHBT( + *(dst_p++) = __PKHBT( theta0_sat, theta1_sat, 16 diff --git a/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h b/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h index d56457ae..4a80e82a 100644 --- a/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h +++ b/firmware/chibios-portapack/os/hal/platforms/LPC43xx_M4/lpc43xx_m4.h @@ -125,12 +125,6 @@ typedef enum IRQn { #ifdef __cplusplus -/* NOTE: Override old, misbehaving SIMD #defines */ - -#define __SIMD32_TYPE int32_t -#define __SIMD32(addr) (*(__SIMD32_TYPE **) & (addr)) -#define _SIMD32_OFFSET(addr) (*(__SIMD32_TYPE *) (addr)) - /* Overload of __SXTB16() to add ROR argument, since using __ROR() as an * argument to the existing __SXTB16() doesn't produce optimum/sane code. */ diff --git a/firmware/common/simd.hpp b/firmware/common/simd.hpp index c2e9be95..1724066b 100644 --- a/firmware/common/simd.hpp +++ b/firmware/common/simd.hpp @@ -28,6 +28,30 @@ #include +template +struct simd32_t { + union { + uint32_t raw; + T vec; + }; + + operator uint32_t() const { + return raw; + } + + simd32_t& operator=(uint32_t v) { + raw = v; + return *this; + } + + static_assert(sizeof(raw) == sizeof(vec), "simd32_t types are not the same size."); +}; + +template +simd32_t* simd32_ptr(T* const p) { + return reinterpret_cast*>(p); +} + struct vec4_s8 { union { int8_t v[4]; From 052fd1c407e506fd3e4a4593b06193cc7d31c2c3 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 6 Jan 2017 16:59:57 -0800 Subject: [PATCH 100/100] Extract loop into static method. Performance boost as compiler is no longer updating member variable every pass through the loop. --- firmware/baseband/channel_stats_collector.hpp | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/firmware/baseband/channel_stats_collector.hpp b/firmware/baseband/channel_stats_collector.hpp index 44d70753..8e69448e 100644 --- a/firmware/baseband/channel_stats_collector.hpp +++ b/firmware/baseband/channel_stats_collector.hpp @@ -36,15 +36,7 @@ class ChannelStatsCollector { public: template void feed(const buffer_c16_t& src, Callback callback) { - auto src_p = simd32_ptr(src.p); - const auto end_p = simd32_ptr(&src.p[src.count]); - while(src_p < end_p) { - const uint32_t sample = *(src_p++); - const uint32_t mag_sq = __SMUAD(sample, sample); - if( mag_sq > max_squared ) { - max_squared = mag_sq; - } - } + max_squared = compute_max_squared(src, max_squared); count += src.count; const size_t samples_per_update = src.sampling_rate * update_interval; @@ -63,6 +55,24 @@ private: static constexpr float update_interval { 0.1f }; uint32_t max_squared { 0 }; size_t count { 0 }; + + static uint32_t compute_max_squared( + const buffer_c16_t& src, + uint32_t max_squared + ) { + auto p = simd32_ptr(src.p); + const auto end_p = simd32_ptr(&src.p[src.count]); + + while(p < end_p) { + const uint32_t sample = *(p++); + const uint32_t mag_sq = __SMUAD(sample, sample); + if( mag_sq > max_squared ) { + max_squared = mag_sq; + } + } + + return max_squared; + } }; #endif/*__CHANNEL_STATS_COLLECTOR_H__*/