Reformat, user SPI begin, SPI array functions, bug fixes
This commit is contained in:
parent
628effa1c2
commit
57900b21d2
140 changed files with 5404 additions and 4712 deletions
243
.gitignore
vendored
243
.gitignore
vendored
|
|
@ -1,215 +1,36 @@
|
|||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
*.ncrunch*
|
||||
.*crunch*.local.xml
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
#packages/
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
#############
|
||||
## Windows detritus
|
||||
#############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac crap
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# =========================
|
||||
# Operating System Files
|
||||
# =========================
|
||||
|
||||
# OSX
|
||||
# =========================
|
||||
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must ends with two \r.
|
||||
Icon
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
*.py[co]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist/
|
||||
build/
|
||||
eggs/
|
||||
parts/
|
||||
var/
|
||||
sdist/
|
||||
develop-eggs/
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -1,8 +1,13 @@
|
|||
### Warning: This is SdFat Version 2.
|
||||
### Warning: Major Reformat of Source in 2.2.2
|
||||
|
||||
Earlier releases of Version 1 are here:
|
||||
There are a huge number of changes in 2.2.2 since I decided to use clang-format
|
||||
to force Google style formatting.
|
||||
|
||||
https://github.com/greiman/SdFat/releases
|
||||
I did this to avoid warnings from the static analysis programs Cppcheck and
|
||||
cpplint.
|
||||
|
||||
clang-format is aggressive so it may actually cause code to fail. For example
|
||||
clang-format rearranges the order of includes according to the selected style.
|
||||
|
||||
UTF-8 encoded filenames are supported in v2.1.0 or later.
|
||||
|
||||
|
|
|
|||
260
doc/Doxyfile
260
doc/Doxyfile
|
|
@ -1,4 +1,4 @@
|
|||
# Doxyfile 1.9.2
|
||||
# Doxyfile 1.9.6
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
|
|
@ -12,6 +12,16 @@
|
|||
# For lists, items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (\" \").
|
||||
#
|
||||
# Note:
|
||||
#
|
||||
# Use doxygen to compare the used configuration file with the template
|
||||
# configuration file:
|
||||
# doxygen -x [configFile]
|
||||
# Use doxygen to compare the used configuration file with the template
|
||||
# configuration file without replacing the environment variables or CMake type
|
||||
# replacement variables:
|
||||
# doxygen -x_noenv [configFile]
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
|
|
@ -60,16 +70,28 @@ PROJECT_LOGO =
|
|||
|
||||
OUTPUT_DIRECTORY = .
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
# will distribute the generated files over these directories. Enabling this
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
|
||||
# sub-directories (in 2 levels) under the output directory of each output format
|
||||
# and will distribute the generated files over these directories. Enabling this
|
||||
# option can be useful when feeding doxygen a huge amount of source files, where
|
||||
# putting all generated files in the same directory would otherwise causes
|
||||
# performance problems for the file system.
|
||||
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
|
||||
# control the number of sub-directories.
|
||||
# The default value is: NO.
|
||||
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# Controls the number of sub-directories that will be created when
|
||||
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
|
||||
# level increment doubles the number of directories, resulting in 4096
|
||||
# directories at level 8 which is the default and also the maximum value. The
|
||||
# sub-directories are organized in 2 levels, the first level always has a fixed
|
||||
# number of 16 directories.
|
||||
# Minimum value: 0, maximum value: 8, default value: 8.
|
||||
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
||||
|
||||
CREATE_SUBDIRS_LEVEL = 8
|
||||
|
||||
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
|
||||
# characters to appear in the names of generated files. If set to NO, non-ASCII
|
||||
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
|
||||
|
|
@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO
|
|||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
|
||||
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
|
||||
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
|
||||
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
||||
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
|
||||
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
|
||||
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
|
||||
# Ukrainian and Vietnamese.
|
||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
|
||||
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
|
||||
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
|
||||
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
|
||||
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
|
||||
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
|
||||
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
|
||||
# Swedish, Turkish, Ukrainian and Vietnamese.
|
||||
# The default value is: English.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
|
@ -452,7 +474,7 @@ TYPEDEF_HIDES_STRUCT = NO
|
|||
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
|
||||
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
|
||||
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
|
||||
# during processing. When set to 0 doxygen will based this on the number of
|
||||
# cores available in the system. You can set it explicitly to a value larger
|
||||
# than 0 to get more control over the balance between CPU load and processing
|
||||
|
|
@ -546,7 +568,8 @@ HIDE_UNDOC_MEMBERS = NO
|
|||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy. If set
|
||||
# to NO, these classes will be included in the various overviews. This option
|
||||
# has no effect if EXTRACT_ALL is enabled.
|
||||
# will also hide undocumented C++ concepts if enabled. This option has no effect
|
||||
# if EXTRACT_ALL is enabled.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
|
@ -577,14 +600,15 @@ INTERNAL_DOCS = NO
|
|||
# filesystem is case sensitive (i.e. it supports files in the same directory
|
||||
# whose names only differ in casing), the option must be set to YES to properly
|
||||
# deal with such files in case they appear in the input. For filesystems that
|
||||
# are not case sensitive the option should be be set to NO to properly deal with
|
||||
# are not case sensitive the option should be set to NO to properly deal with
|
||||
# output files written for symbols that only differ in casing, such as for two
|
||||
# classes, one named CLASS and the other named Class, and to also support
|
||||
# references to files without having to specify the exact matching casing. On
|
||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||
# YES.
|
||||
# The default value is: system dependent.
|
||||
# Possible values are: SYSTEM, NO and YES.
|
||||
# The default value is: SYSTEM.
|
||||
|
||||
CASE_SENSE_NAMES = NO
|
||||
|
||||
|
|
@ -836,6 +860,14 @@ WARN_IF_INCOMPLETE_DOC = YES
|
|||
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
|
||||
# undocumented enumeration values. If set to NO, doxygen will accept
|
||||
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
|
||||
# will automatically be disabled.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_IF_UNDOC_ENUM_VAL = NO
|
||||
|
||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||
|
|
@ -851,13 +883,27 @@ WARN_AS_ERROR = NO
|
|||
# and the warning text. Optionally the format may contain $version, which will
|
||||
# be replaced by the version of the file (if it could be obtained via
|
||||
# FILE_VERSION_FILTER)
|
||||
# See also: WARN_LINE_FORMAT
|
||||
# The default value is: $file:$line: $text.
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
# In the $text part of the WARN_FORMAT command it is possible that a reference
|
||||
# to a more specific place is given. To make it easier to jump to this place
|
||||
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
|
||||
# Example:
|
||||
# WARN_LINE_FORMAT = "'vi $file +$line'"
|
||||
# See also: WARN_FORMAT
|
||||
# The default value is: at line $line of file $file.
|
||||
|
||||
WARN_LINE_FORMAT = "at line $line of file $file"
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
|
||||
# messages should be written. If left blank the output is written to standard
|
||||
# error (stderr).
|
||||
# error (stderr). In case the file specified cannot be opened for writing the
|
||||
# warning and error messages are written to standard error. When as file - is
|
||||
# specified the warning and error messages are written to standard output
|
||||
# (stdout).
|
||||
|
||||
WARN_LOGFILE =
|
||||
|
||||
|
|
@ -887,10 +933,21 @@ INPUT = ../src \
|
|||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see:
|
||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||
# See also: INPUT_FILE_ENCODING
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
|
||||
# character encoding on a per file pattern basis. Doxygen will compare the file
|
||||
# name with each pattern and apply the encoding instead of the default
|
||||
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
|
||||
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
|
||||
# "INPUT_ENCODING" for further information on supported encodings.
|
||||
|
||||
INPUT_FILE_ENCODING =
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
||||
# *.h) to filter out the source-files in the directories.
|
||||
|
|
@ -981,7 +1038,7 @@ EXCLUDE_PATTERNS =
|
|||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# AClass::ANamespace, ANamespace::*Test
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
|
|
@ -1029,6 +1086,11 @@ IMAGE_PATH =
|
|||
# code is scanned, but not when the output code is generated. If lines are added
|
||||
# or removed, the anchors will not be placed correctly.
|
||||
#
|
||||
# Note that doxygen will use the data processed and written to standard output
|
||||
# for further processing, therefore nothing else, like debug statements or used
|
||||
# commands (so in case of a Windows batch file always use @echo OFF), should be
|
||||
# written to standard output.
|
||||
#
|
||||
# Note that for custom extensions or not directly supported extensions you also
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# properly processed by doxygen.
|
||||
|
|
@ -1070,6 +1132,15 @@ FILTER_SOURCE_PATTERNS =
|
|||
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
|
||||
# The Fortran standard specifies that for fixed formatted Fortran code all
|
||||
# characters from position 72 are to be considered as comment. A common
|
||||
# extension is to allow longer lines before the automatic comment starts. The
|
||||
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
|
||||
# be processed before the automatic comment starts.
|
||||
# Minimum value: 7, maximum value: 10000, default value: 72.
|
||||
|
||||
FORTRAN_COMMENT_AFTER = 72
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -1207,10 +1278,11 @@ CLANG_DATABASE_PATH =
|
|||
|
||||
ALPHABETICAL_INDEX = NO
|
||||
|
||||
# In case all classes in a project start with a common prefix, all classes will
|
||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||
# while generating the index headers.
|
||||
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
||||
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
||||
# tag works for classes, function and member names. The entity will be placed in
|
||||
# the alphabetical list under the first letter of the entity name that remains
|
||||
# after removing the prefix.
|
||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||
|
||||
IGNORE_PREFIX =
|
||||
|
|
@ -1289,7 +1361,12 @@ HTML_STYLESHEET =
|
|||
# Doxygen will copy the style sheet files to the output directory.
|
||||
# Note: The order of the extra style sheet files is of importance (e.g. the last
|
||||
# style sheet in the list overrules the setting of the previous ones in the
|
||||
# list). For an example see the documentation.
|
||||
# list).
|
||||
# Note: Since the styling of scrollbars can currently not be overruled in
|
||||
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
|
||||
# one or more extra stylesheets have been specified. So if scrollbar
|
||||
# customization is desired it has to be added explicitly. For an example see the
|
||||
# documentation.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
|
|
@ -1304,6 +1381,19 @@ HTML_EXTRA_STYLESHEET =
|
|||
|
||||
HTML_EXTRA_FILES =
|
||||
|
||||
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
|
||||
# should be rendered with a dark or light theme.
|
||||
# Possible values are: LIGHT always generate light mode output, DARK always
|
||||
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
|
||||
# the user preference, use light mode if no preference is set (the default),
|
||||
# AUTO_DARK automatically set the mode according to the user preference, use
|
||||
# dark mode if no preference is set and TOGGLE allow to user to switch between
|
||||
# light and dark mode via a button.
|
||||
# The default value is: AUTO_LIGHT.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_COLORSTYLE = AUTO_LIGHT
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
# this color. Hue is specified as an angle on a color-wheel, see
|
||||
|
|
@ -1398,6 +1488,13 @@ GENERATE_DOCSET = NO
|
|||
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
|
||||
# This tag determines the URL of the docset feed. A documentation feed provides
|
||||
# an umbrella under which multiple documentation sets from a single provider
|
||||
# (such as a company or product suite) can be grouped.
|
||||
# This tag requires that the tag GENERATE_DOCSET is set to YES.
|
||||
|
||||
DOCSET_FEEDURL =
|
||||
|
||||
# This tag specifies a string that should uniquely identify the documentation
|
||||
# set bundle. This should be a reverse domain-name style string, e.g.
|
||||
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
|
||||
|
|
@ -1602,7 +1699,7 @@ GENERATE_TREEVIEW = NO
|
|||
# area (value NO) or if it should extend to the full height of the window (value
|
||||
# YES). Setting this to YES gives a layout similar to
|
||||
# https://docs.readthedocs.io with more room for contents, but less room for the
|
||||
# project logo, title, and description. If either GENERATOR_TREEVIEW or
|
||||
# project logo, title, and description. If either GENERATE_TREEVIEW or
|
||||
# DISABLE_INDEX is set to NO, this option has no effect.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
|
@ -1633,6 +1730,13 @@ TREEVIEW_WIDTH = 250
|
|||
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
|
||||
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
|
||||
# addresses.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
OBFUSCATE_EMAILS = YES
|
||||
|
||||
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
|
||||
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
|
||||
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
|
||||
|
|
@ -1653,17 +1757,6 @@ HTML_FORMULA_FORMAT = png
|
|||
|
||||
FORMULA_FONTSIZE = 10
|
||||
|
||||
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
|
||||
# generated for formulas are transparent PNGs. Transparent PNGs are not
|
||||
# supported properly for IE 6.0, but are supported on all modern browsers.
|
||||
#
|
||||
# Note that when changing this option you need to delete any form_*.png files in
|
||||
# the HTML output directory before the changes have effect.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
||||
# to create new LaTeX commands to be used in formulas as building blocks. See
|
||||
# the section "Including formulas" for details.
|
||||
|
|
@ -2258,7 +2351,8 @@ SEARCH_INCLUDES = YES
|
|||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by the
|
||||
# preprocessor.
|
||||
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
|
||||
# RECURSIVE has no effect here.
|
||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
||||
|
||||
INCLUDE_PATH =
|
||||
|
|
@ -2354,15 +2448,6 @@ EXTERNAL_PAGES = YES
|
|||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
|
||||
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
|
||||
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
|
||||
# disabled, but it is recommended to install and use dot, since it yields more
|
||||
# powerful graphs.
|
||||
# The default value is: YES.
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
|
|
@ -2395,35 +2480,50 @@ HAVE_DOT = YES
|
|||
|
||||
DOT_NUM_THREADS = 0
|
||||
|
||||
# When you want a differently looking font in the dot files that doxygen
|
||||
# generates you can specify the font name using DOT_FONTNAME. You need to make
|
||||
# sure dot is able to find the font, which can be done by putting it in a
|
||||
# standard location or by setting the DOTFONTPATH environment variable or by
|
||||
# setting DOT_FONTPATH to the directory containing the font.
|
||||
# The default value is: Helvetica.
|
||||
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
|
||||
# subgraphs. When you want a differently looking font in the dot files that
|
||||
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
|
||||
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
|
||||
# Edge and Graph Attributes specification</a> You need to make sure dot is able
|
||||
# to find the font, which can be done by putting it in a standard location or by
|
||||
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
|
||||
# directory containing the font. Default graphviz fontsize is 14.
|
||||
# The default value is: fontname=Helvetica,fontsize=10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
|
||||
|
||||
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
|
||||
# dot graphs.
|
||||
# Minimum value: 4, maximum value: 24, default value: 10.
|
||||
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
|
||||
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
|
||||
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
|
||||
# arrows shapes.</a>
|
||||
# The default value is: labelfontname=Helvetica,labelfontsize=10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
|
||||
|
||||
# By default doxygen will tell dot to use the default font as specified with
|
||||
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
|
||||
# the path where dot can find it using this tag.
|
||||
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
|
||||
# around nodes set 'shape=plain' or 'shape=plaintext' <a
|
||||
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
|
||||
# The default value is: shape=box,height=0.2,width=0.4.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
|
||||
|
||||
# You can set the path where dot can find font specified with fontname in
|
||||
# DOT_COMMON_ATTR and others dot attributes.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_FONTPATH =
|
||||
|
||||
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
|
||||
# each documented class showing the direct and indirect inheritance relations.
|
||||
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
|
||||
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
||||
# graph for each documented class showing the direct and indirect inheritance
|
||||
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
||||
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
||||
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
||||
# links.
|
||||
# Possible values are: NO, YES, TEXT and GRAPH.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
|
|
@ -2437,7 +2537,8 @@ CLASS_GRAPH = YES
|
|||
COLLABORATION_GRAPH = YES
|
||||
|
||||
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
||||
# groups, showing the direct groups dependencies.
|
||||
# groups, showing the direct groups dependencies. See also the chapter Grouping
|
||||
# in the manual.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
|
|
@ -2552,6 +2653,13 @@ GRAPHICAL_HIERARCHY = YES
|
|||
|
||||
DIRECTORY_GRAPH = YES
|
||||
|
||||
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
|
||||
# of child directories generated in directory dependency graphs by dot.
|
||||
# Minimum value: 1, maximum value: 25, default value: 1.
|
||||
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
|
||||
|
||||
DIR_GRAPH_MAX_DEPTH = 1
|
||||
|
||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. For an explanation of the image formats see the section
|
||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||
|
|
@ -2605,10 +2713,10 @@ MSCFILE_DIRS =
|
|||
DIAFILE_DIRS =
|
||||
|
||||
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
|
||||
# path where java can find the plantuml.jar file. If left blank, it is assumed
|
||||
# PlantUML is not used or called during a preprocessing step. Doxygen will
|
||||
# generate a warning when it encounters a \startuml command in this case and
|
||||
# will not generate output for the diagram.
|
||||
# path where java can find the plantuml.jar file or to the filename of jar file
|
||||
# to be used. If left blank, it is assumed PlantUML is not used or called during
|
||||
# a preprocessing step. Doxygen will generate a warning when it encounters a
|
||||
# \startuml command in this case and will not generate output for the diagram.
|
||||
|
||||
PLANTUML_JAR_PATH =
|
||||
|
||||
|
|
@ -2646,18 +2754,6 @@ DOT_GRAPH_MAX_NODES = 50
|
|||
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
|
||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
||||
# background. This is disabled by default, because dot on Windows does not seem
|
||||
# to support this out of the box.
|
||||
#
|
||||
# Warning: Depending on the platform used, enabling this option may lead to
|
||||
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
|
||||
# read).
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_TRANSPARENT = YES
|
||||
|
||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||
|
|
@ -2670,6 +2766,8 @@ DOT_MULTI_TARGETS = NO
|
|||
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
|
||||
# explaining the meaning of the various boxes and arrows in the dot generated
|
||||
# graphs.
|
||||
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
|
||||
# graphical representation for inheritance and collaboration diagrams is used.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
|
|
|
|||
BIN
doc/html.zip
BIN
doc/html.zip
Binary file not shown.
|
|
@ -3,7 +3,8 @@
|
|||
const size_t BLOCK_SIZE = 64;
|
||||
//------------------------------------------------------------------------------
|
||||
// First block of file.
|
||||
const size_t PIN_NUM_DIM = BLOCK_SIZE - 3*sizeof(uint32_t) - 2*sizeof(uint8_t);
|
||||
const size_t PIN_NUM_DIM =
|
||||
BLOCK_SIZE - 3 * sizeof(uint32_t) - 2 * sizeof(uint8_t);
|
||||
struct metadata_t {
|
||||
uint32_t adcFrequency; // ADC clock frequency
|
||||
uint32_t cpuFrequency; // CPU clock frequency
|
||||
|
|
@ -14,15 +15,16 @@ struct metadata_t {
|
|||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// Data block for 8-bit ADC mode.
|
||||
const size_t DATA_DIM8 = (BLOCK_SIZE - 2*sizeof(uint16_t))/sizeof(uint8_t);
|
||||
const size_t DATA_DIM8 = (BLOCK_SIZE - 2 * sizeof(uint16_t)) / sizeof(uint8_t);
|
||||
struct block8_t {
|
||||
uint16_t count; // count of data values
|
||||
uint16_t overrun; // count of overruns since last block
|
||||
uint8_t data[DATA_DIM8];
|
||||
uint8_t data[DATA_DIM8];
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// Data block for 10-bit ADC mode.
|
||||
const size_t DATA_DIM16 = (BLOCK_SIZE - 2*sizeof(uint16_t))/sizeof(uint16_t);
|
||||
const size_t DATA_DIM16 =
|
||||
(BLOCK_SIZE - 2 * sizeof(uint16_t)) / sizeof(uint16_t);
|
||||
struct block16_t {
|
||||
unsigned short count; // count of data values
|
||||
unsigned short overrun; // count of overruns since last block
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@
|
|||
*/
|
||||
#ifdef __AVR__
|
||||
#include <SPI.h>
|
||||
#include "SdFat.h"
|
||||
|
||||
#include "AvrAdcLogger.h"
|
||||
#include "BufferedPrint.h"
|
||||
#include "FreeStack.h"
|
||||
#include "AvrAdcLogger.h"
|
||||
#include "SdFat.h"
|
||||
|
||||
// Save SRAM if 328.
|
||||
#ifdef __AVR_ATmega328P__
|
||||
|
|
@ -73,7 +74,7 @@ const float SAMPLE_RATE = 5000; // Must be 0.25 or greater.
|
|||
// constant instead of being calculated from SAMPLE_RATE. SAMPLE_RATE is not
|
||||
// used in the code below. For example, setting SAMPLE_INTERVAL = 2.0e-4
|
||||
// will result in a 200 microsecond sample interval.
|
||||
const float SAMPLE_INTERVAL = 1.0/SAMPLE_RATE;
|
||||
const float SAMPLE_INTERVAL = 1.0 / SAMPLE_RATE;
|
||||
|
||||
// Setting ROUND_SAMPLE_INTERVAL non-zero will cause the sample interval to
|
||||
// be rounded to a a multiple of the ADC clock period and will reduce sample
|
||||
|
|
@ -109,11 +110,11 @@ const size_t NAME_DIM = 40;
|
|||
#elif RAMEND < 0X10FF
|
||||
const size_t FIFO_SIZE_BYTES = 512;
|
||||
#elif RAMEND < 0X20FF
|
||||
const size_t FIFO_SIZE_BYTES = 4*512;
|
||||
const size_t FIFO_SIZE_BYTES = 4 * 512;
|
||||
#elif RAMEND < 0X40FF
|
||||
const size_t FIFO_SIZE_BYTES = 12*512;
|
||||
#else // RAMEND
|
||||
const size_t FIFO_SIZE_BYTES = 16*512;
|
||||
const size_t FIFO_SIZE_BYTES = 12 * 512;
|
||||
#else // RAMEND
|
||||
const size_t FIFO_SIZE_BYTES = 16 * 512;
|
||||
#endif // RAMEND
|
||||
//------------------------------------------------------------------------------
|
||||
// ADC clock rate.
|
||||
|
|
@ -136,7 +137,7 @@ const size_t FIFO_SIZE_BYTES = 16*512;
|
|||
#define TMP_FILE_NAME "tmp_adc.bin"
|
||||
|
||||
// Number of analog pins to log.
|
||||
const uint8_t PIN_COUNT = sizeof(PIN_LIST)/sizeof(PIN_LIST[0]);
|
||||
const uint8_t PIN_COUNT = sizeof(PIN_LIST) / sizeof(PIN_LIST[0]);
|
||||
|
||||
// Minimum ADC clock cycles per sample interval
|
||||
const uint16_t MIN_ADC_CYCLES = 15;
|
||||
|
|
@ -181,19 +182,19 @@ file_t csvFile;
|
|||
char binName[] = LOG_FILE_NAME;
|
||||
|
||||
#if RECORD_EIGHT_BITS
|
||||
const size_t BLOCK_MAX_COUNT = PIN_COUNT*(DATA_DIM8/PIN_COUNT);
|
||||
const size_t BLOCK_MAX_COUNT = PIN_COUNT * (DATA_DIM8 / PIN_COUNT);
|
||||
typedef block8_t block_t;
|
||||
#else // RECORD_EIGHT_BITS
|
||||
const size_t BLOCK_MAX_COUNT = PIN_COUNT*(DATA_DIM16/PIN_COUNT);
|
||||
#else // RECORD_EIGHT_BITS
|
||||
const size_t BLOCK_MAX_COUNT = PIN_COUNT * (DATA_DIM16 / PIN_COUNT);
|
||||
typedef block16_t block_t;
|
||||
#endif // RECORD_EIGHT_BITS
|
||||
#endif // RECORD_EIGHT_BITS
|
||||
|
||||
// Size of FIFO in blocks.
|
||||
size_t const FIFO_DIM = FIFO_SIZE_BYTES/sizeof(block_t);
|
||||
size_t const FIFO_DIM = FIFO_SIZE_BYTES / sizeof(block_t);
|
||||
block_t* fifoData;
|
||||
volatile size_t fifoCount = 0; // volatile - shared, ISR and background.
|
||||
size_t fifoHead = 0; // Only accessed by ISR during logging.
|
||||
size_t fifoTail = 0; // Only accessed by writer during logging.
|
||||
volatile size_t fifoCount = 0; // volatile - shared, ISR and background.
|
||||
size_t fifoHead = 0; // Only accessed by ISR during logging.
|
||||
size_t fifoTail = 0; // Only accessed by writer during logging.
|
||||
//==============================================================================
|
||||
// Interrupt Service Routines
|
||||
|
||||
|
|
@ -220,7 +221,7 @@ ISR(ADC_vect) {
|
|||
// Read ADC data.
|
||||
#if RECORD_EIGHT_BITS
|
||||
uint8_t d = ADCH;
|
||||
#else // RECORD_EIGHT_BITS
|
||||
#else // RECORD_EIGHT_BITS
|
||||
// This will access ADCL first.
|
||||
uint16_t d = ADC;
|
||||
#endif // RECORD_EIGHT_BITS
|
||||
|
|
@ -246,7 +247,7 @@ ISR(ADC_vect) {
|
|||
if (adcindex == 0) {
|
||||
timerFlag = false;
|
||||
}
|
||||
adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
|
||||
adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
|
||||
} else {
|
||||
timerFlag = false;
|
||||
}
|
||||
|
|
@ -278,7 +279,7 @@ ISR(TIMER1_COMPB_vect) {
|
|||
}
|
||||
//==============================================================================
|
||||
// Error messages stored in flash.
|
||||
#define error(msg) (Serial.println(F(msg)),errorHalt())
|
||||
#define error(msg) (Serial.println(F(msg)), errorHalt())
|
||||
#define assert(e) ((e) ? (void)0 : error("assert: " #e))
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
|
|
@ -337,12 +338,13 @@ void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
|
|||
#error unexpected ADC prescaler bits
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool adcActive() {return (1 << ADIE) & ADCSRA;}
|
||||
inline bool adcActive() { return (1 << ADIE) & ADCSRA; }
|
||||
//------------------------------------------------------------------------------
|
||||
// initialize ADC and timer1
|
||||
void adcInit(metadata_t* meta) {
|
||||
uint8_t adps; // prescaler bits for ADCSRA
|
||||
uint32_t ticks = F_CPU*SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.
|
||||
uint32_t ticks =
|
||||
F_CPU * SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.
|
||||
|
||||
if (ADC_REF & ~((1 << REFS0) | (1 << REFS1))) {
|
||||
error("Invalid ADC reference");
|
||||
|
|
@ -352,9 +354,9 @@ void adcInit(metadata_t* meta) {
|
|||
error("Invalid ADC prescaler");
|
||||
}
|
||||
adps = ADC_PRESCALER;
|
||||
#else // ADC_PRESCALER
|
||||
#else // ADC_PRESCALER
|
||||
// Allow extra cpu cycles to change ADC settings if more than one pin.
|
||||
int32_t adcCycles = (ticks - ISR_TIMER0)/PIN_COUNT - ISR_SETUP_ADC;
|
||||
int32_t adcCycles = (ticks - ISR_TIMER0) / PIN_COUNT - ISR_SETUP_ADC;
|
||||
|
||||
for (adps = 7; adps > 0; adps--) {
|
||||
if (adcCycles >= (MIN_ADC_CYCLES << adps)) {
|
||||
|
|
@ -411,19 +413,19 @@ void adcInit(metadata_t* meta) {
|
|||
// no prescale, CTC mode
|
||||
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
|
||||
tshift = 0;
|
||||
} else if (ticks < 0X10000*8) {
|
||||
} else if (ticks < 0X10000 * 8) {
|
||||
// prescale 8, CTC mode
|
||||
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
|
||||
tshift = 3;
|
||||
} else if (ticks < 0X10000*64) {
|
||||
} else if (ticks < 0X10000 * 64) {
|
||||
// prescale 64, CTC mode
|
||||
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11) | (1 << CS10);
|
||||
tshift = 6;
|
||||
} else if (ticks < 0X10000*256) {
|
||||
} else if (ticks < 0X10000 * 256) {
|
||||
// prescale 256, CTC mode
|
||||
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12);
|
||||
tshift = 8;
|
||||
} else if (ticks < 0X10000*1024) {
|
||||
} else if (ticks < 0X10000 * 1024) {
|
||||
// prescale 1024, CTC mode
|
||||
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
|
||||
tshift = 10;
|
||||
|
|
@ -443,7 +445,7 @@ void adcInit(metadata_t* meta) {
|
|||
// Sample interval in CPU clock ticks.
|
||||
meta->sampleInterval = ticks;
|
||||
meta->cpuFrequency = F_CPU;
|
||||
float sampleRate = (float)meta->cpuFrequency/meta->sampleInterval;
|
||||
float sampleRate = (float)meta->cpuFrequency / meta->sampleInterval;
|
||||
Serial.print(F("Sample pins:"));
|
||||
for (uint8_t i = 0; i < meta->pinCount; i++) {
|
||||
Serial.print(' ');
|
||||
|
|
@ -453,11 +455,11 @@ void adcInit(metadata_t* meta) {
|
|||
Serial.print(F("ADC bits: "));
|
||||
Serial.println(meta->recordEightBits ? 8 : 10);
|
||||
Serial.print(F("ADC clock kHz: "));
|
||||
Serial.println(meta->adcFrequency/1000);
|
||||
Serial.println(meta->adcFrequency / 1000);
|
||||
Serial.print(F("Sample Rate: "));
|
||||
Serial.println(sampleRate);
|
||||
Serial.print(F("Sample interval usec: "));
|
||||
Serial.println(1000000.0/sampleRate);
|
||||
Serial.println(1000000.0 / sampleRate);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// enable ADC and timer1 interrupts
|
||||
|
|
@ -509,7 +511,7 @@ void binaryToCsv() {
|
|||
if (nb < 0) {
|
||||
error("read binFile failed");
|
||||
}
|
||||
size_t nd = nb/sizeof(block_t);
|
||||
size_t nd = nb / sizeof(block_t);
|
||||
if (nd < 1) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -520,7 +522,8 @@ void binaryToCsv() {
|
|||
error("Invalid pinCount");
|
||||
}
|
||||
bp.print(F("Interval,"));
|
||||
float intervalMicros = 1.0e6*pm->sampleInterval/(float)pm->cpuFrequency;
|
||||
float intervalMicros =
|
||||
1.0e6 * pm->sampleInterval / (float)pm->cpuFrequency;
|
||||
bp.print(intervalMicros, 4);
|
||||
bp.println(F(",usec"));
|
||||
for (uint8_t i = 0; i < PIN_COUNT; i++) {
|
||||
|
|
@ -542,14 +545,15 @@ void binaryToCsv() {
|
|||
}
|
||||
for (size_t j = 0; j < pd->count; j += PIN_COUNT) {
|
||||
for (size_t i = 0; i < PIN_COUNT; i++) {
|
||||
if (!bp.printField(pd->data[i + j], i == (PIN_COUNT-1) ? '\n' : ',')) {
|
||||
if (!bp.printField(pd->data[i + j],
|
||||
i == (PIN_COUNT - 1) ? '\n' : ',')) {
|
||||
error("printField failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((millis() - tPct) > 1000) {
|
||||
uint8_t pct = binFile.curPosition()/(binFile.fileSize()/100);
|
||||
uint8_t pct = binFile.curPosition() / (binFile.fileSize() / 100);
|
||||
if (pct != lastPct) {
|
||||
tPct = millis();
|
||||
lastPct = pct;
|
||||
|
|
@ -562,7 +566,7 @@ void binaryToCsv() {
|
|||
error("close csvFile failed");
|
||||
}
|
||||
Serial.print(F("Done: "));
|
||||
Serial.print(0.001*(millis() - t0));
|
||||
Serial.print(0.001 * (millis() - t0));
|
||||
Serial.println(F(" Seconds"));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -620,7 +624,7 @@ bool createCsvFile() {
|
|||
error("no dot in binName");
|
||||
}
|
||||
strcpy(dot + 1, "csv");
|
||||
if (!csvFile.open(csvName, O_WRONLY|O_CREAT|O_TRUNC)) {
|
||||
if (!csvFile.open(csvName, O_WRONLY | O_CREAT | O_TRUNC)) {
|
||||
error("open csvFile failed");
|
||||
}
|
||||
Serial.print(F("Writing: "));
|
||||
|
|
@ -633,7 +637,7 @@ bool createCsvFile() {
|
|||
void logData() {
|
||||
uint32_t t0;
|
||||
uint32_t t1;
|
||||
uint32_t overruns =0;
|
||||
uint32_t overruns = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t maxLatencyUsec = 0;
|
||||
size_t maxFifoUse = 0;
|
||||
|
|
@ -677,7 +681,7 @@ void logData() {
|
|||
if (m > maxLatencyUsec) {
|
||||
maxLatencyUsec = m;
|
||||
}
|
||||
if (tmpFifoCount >maxFifoUse) {
|
||||
if (tmpFifoCount > maxFifoUse) {
|
||||
maxFifoUse = tmpFifoCount;
|
||||
}
|
||||
count += pBlock->count;
|
||||
|
|
@ -712,7 +716,7 @@ void logData() {
|
|||
isrStop = true;
|
||||
}
|
||||
if (fifoCount == 0 && !adcActive()) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
|
|
@ -727,9 +731,9 @@ void logData() {
|
|||
Serial.print(F("Max write latency usec: "));
|
||||
Serial.println(maxLatencyUsec);
|
||||
Serial.print(F("Record time sec: "));
|
||||
Serial.println(0.001*(t1 - t0), 3);
|
||||
Serial.println(0.001 * (t1 - t0), 3);
|
||||
Serial.print(F("Sample count: "));
|
||||
Serial.println(count/PIN_COUNT);
|
||||
Serial.println(count / PIN_COUNT);
|
||||
Serial.print(F("Overruns: "));
|
||||
Serial.println(overruns);
|
||||
Serial.print(F("FIFO_DIM: "));
|
||||
|
|
@ -768,13 +772,13 @@ void printData() {
|
|||
return;
|
||||
}
|
||||
binFile.rewind();
|
||||
if (binFile.read(&buf , sizeof(buf)) != sizeof(buf)) {
|
||||
if (binFile.read(&buf, sizeof(buf)) != sizeof(buf)) {
|
||||
error("Read metadata failed");
|
||||
}
|
||||
Serial.println(F("Type any character to stop"));
|
||||
delay(1000);
|
||||
while (!Serial.available() &&
|
||||
binFile.read(&buf , sizeof(buf)) == sizeof(buf)) {
|
||||
binFile.read(&buf, sizeof(buf)) == sizeof(buf)) {
|
||||
if (buf.count == 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -784,7 +788,7 @@ void printData() {
|
|||
}
|
||||
for (size_t i = 0; i < buf.count; i++) {
|
||||
Serial.print(buf.data[i], DEC);
|
||||
if ((i+1)%PIN_COUNT) {
|
||||
if ((i + 1) % PIN_COUNT) {
|
||||
Serial.print(',');
|
||||
} else {
|
||||
Serial.println();
|
||||
|
|
@ -796,7 +800,7 @@ void printData() {
|
|||
//------------------------------------------------------------------------------
|
||||
bool serialReadLine(char* str, size_t size) {
|
||||
size_t n = 0;
|
||||
while(!Serial.available()) {
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
while (true) {
|
||||
int c = Serial.read();
|
||||
|
|
@ -807,7 +811,8 @@ bool serialReadLine(char* str, size_t size) {
|
|||
return false;
|
||||
}
|
||||
uint32_t m = millis();
|
||||
while (!Serial.available() && (millis() - m) < 100){}
|
||||
while (!Serial.available() && (millis() - m) < 100) {
|
||||
}
|
||||
if (!Serial.available()) break;
|
||||
}
|
||||
str[n] = 0;
|
||||
|
|
@ -819,9 +824,11 @@ void setup(void) {
|
|||
pinMode(ERROR_LED_PIN, OUTPUT);
|
||||
}
|
||||
Serial.begin(9600);
|
||||
while(!Serial) {}
|
||||
while (!Serial) {
|
||||
}
|
||||
Serial.println(F("Type any character to begin."));
|
||||
while(!Serial.available()) {}
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
|
||||
FillStack();
|
||||
|
||||
|
|
@ -829,9 +836,9 @@ void setup(void) {
|
|||
analogRead(PIN_LIST[0]);
|
||||
|
||||
#if !ENABLE_DEDICATED_SPI
|
||||
Serial.println(F(
|
||||
"\nFor best performance edit SdFatConfig.h\n"
|
||||
"and set ENABLE_DEDICATED_SPI nonzero"));
|
||||
Serial.println(
|
||||
F("\nFor best performance edit SdFatConfig.h\n"
|
||||
"and set ENABLE_DEDICATED_SPI nonzero"));
|
||||
#endif // !ENABLE_DEDICATED_SPI
|
||||
// Initialize SD.
|
||||
if (!sd.begin(SD_CONFIG)) {
|
||||
|
|
@ -865,7 +872,7 @@ void loop(void) {
|
|||
Serial.println(F("p - print data to Serial"));
|
||||
Serial.println(F("r - record ADC data"));
|
||||
|
||||
while(!Serial.available()) {
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
char c = tolower(Serial.read());
|
||||
|
|
|
|||
|
|
@ -28,11 +28,12 @@ File myFile;
|
|||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
while (!Serial) {
|
||||
}
|
||||
|
||||
#if USE_SD_H
|
||||
Serial.println(F("Using SD.h. Set USE_SD_H zero to use SdFat.h."));
|
||||
#else // USE_SD_H
|
||||
#else // USE_SD_H
|
||||
Serial.println(F("Using SdFat.h. Set USE_SD_H nonzero to use SD.h."));
|
||||
#endif // USE_SD_H
|
||||
Serial.println(F("\nType any character to begin."));
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// Test and benchmark of the fast bufferedPrint class.
|
||||
//
|
||||
// Mainly for AVR but may improve print performance with other CPUs.
|
||||
#include "SdFat.h"
|
||||
#include "BufferedPrint.h"
|
||||
#include "SdFat.h"
|
||||
|
||||
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
|
||||
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -30,7 +30,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -71,49 +71,48 @@ void benchmark() {
|
|||
bp.begin(&file);
|
||||
}
|
||||
uint32_t t = millis();
|
||||
switch(test) {
|
||||
case 0:
|
||||
Serial.println(F("Test of println(uint16_t)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
file.println(i);
|
||||
}
|
||||
break;
|
||||
switch (test) {
|
||||
case 0:
|
||||
Serial.println(F("Test of println(uint16_t)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
file.println(i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Serial.println(F("Test of printField(uint16_t, char)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
bp.printField(i, '\n');
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
Serial.println(F("Test of printField(uint16_t, char)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
bp.printField(i, '\n');
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Serial.println(F("Test of println(uint32_t)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
file.println(12345678UL + i);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
Serial.println(F("Test of println(uint32_t)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
file.println(12345678UL + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
Serial.println(F("Test of printField(uint32_t, char)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
bp.printField(12345678UL + i, '\n');
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
Serial.println(F("Test of printField(uint32_t, char)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
bp.printField(12345678UL + i, '\n');
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
Serial.println(F("Test of println(double)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
file.println((double)0.01*i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
Serial.println(F("Test of printField(double, char)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
bp.printField((double)0.01*i, '\n');
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
Serial.println(F("Test of println(double)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
file.println((double)0.01 * i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
Serial.println(F("Test of printField(double, char)"));
|
||||
for (uint16_t i = 0; i < N_PRINT; i++) {
|
||||
bp.printField((double)0.01 * i, '\n');
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (test & 1) {
|
||||
bp.sync();
|
||||
|
|
@ -125,13 +124,13 @@ void benchmark() {
|
|||
file.close();
|
||||
t = millis() - t;
|
||||
Serial.print(F("Time "));
|
||||
Serial.print(0.001*t, 3);
|
||||
Serial.print(0.001 * t, 3);
|
||||
Serial.println(F(" sec"));
|
||||
Serial.print(F("File size "));
|
||||
Serial.print(0.001*s);
|
||||
Serial.print(0.001 * s);
|
||||
Serial.println(F(" KB"));
|
||||
Serial.print(F("Write "));
|
||||
Serial.print(s/t);
|
||||
Serial.print(s / t);
|
||||
Serial.println(F(" KB/sec"));
|
||||
Serial.println();
|
||||
}
|
||||
|
|
@ -139,23 +138,23 @@ void benchmark() {
|
|||
//------------------------------------------------------------------------------
|
||||
void testMemberFunctions() {
|
||||
BufferedPrint<Print, 32> bp(&Serial);
|
||||
char c = 'c'; // char
|
||||
char c = 'c'; // char
|
||||
//#define BASIC_TYPES
|
||||
#ifdef BASIC_TYPES
|
||||
signed char sc = -1; // signed 8-bit
|
||||
unsigned char uc = 1; // unsiged 8-bit
|
||||
signed short ss = -2; // signed 16-bit
|
||||
unsigned short us = 2; // unsigned 16-bit
|
||||
signed long sl = -4; // signed 32-bit
|
||||
unsigned long ul = 4; // unsigned 32-bit
|
||||
#else // BASIC_TYPES
|
||||
int8_t sc = -1; // signed 8-bit
|
||||
uint8_t uc = 1; // unsiged 8-bit
|
||||
int16_t ss = -2; // signed 16-bit
|
||||
uint16_t us = 2; // unsigned 16-bit
|
||||
int32_t sl = -4; // signed 32-bit
|
||||
uint32_t ul = 4; // unsigned 32-bit
|
||||
#endif // BASIC_TYPES
|
||||
signed char sc = -1; // signed 8-bit
|
||||
unsigned char uc = 1; // unsiged 8-bit
|
||||
signed short ss = -2; // signed 16-bit
|
||||
unsigned short us = 2; // unsigned 16-bit
|
||||
signed long sl = -4; // signed 32-bit
|
||||
unsigned long ul = 4; // unsigned 32-bit
|
||||
#else // BASIC_TYPES
|
||||
int8_t sc = -1; // signed 8-bit
|
||||
uint8_t uc = 1; // unsiged 8-bit
|
||||
int16_t ss = -2; // signed 16-bit
|
||||
uint16_t us = 2; // unsigned 16-bit
|
||||
int32_t sl = -4; // signed 32-bit
|
||||
uint32_t ul = 4; // unsigned 32-bit
|
||||
#endif // BASIC_TYPES
|
||||
float f = -1.234;
|
||||
double d = -5.678;
|
||||
bp.println();
|
||||
|
|
@ -216,9 +215,11 @@ void testMemberFunctions() {
|
|||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
while (!Serial) {
|
||||
}
|
||||
Serial.println("Type any character to begin.");
|
||||
while(!Serial.available()) {}
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
if (!sd.begin(SD_CONFIG)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
|
|
@ -226,10 +227,10 @@ void setup() {
|
|||
Serial.println(F("Test member funcions:"));
|
||||
testMemberFunctions();
|
||||
Serial.println();
|
||||
Serial.println(F("Benchmark performance for uint16_t, uint32_t, and double:"));
|
||||
Serial.println(
|
||||
F("Benchmark performance for uint16_t, uint32_t, and double:"));
|
||||
benchmark();
|
||||
Serial.println("Done");
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -30,7 +30,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -78,9 +78,8 @@ void setup() {
|
|||
if (!sd.begin(SD_CONFIG)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
if (sd.exists("Folder1")
|
||||
|| sd.exists("Folder1/file1.txt")
|
||||
|| sd.exists("Folder1/File2.txt")) {
|
||||
if (sd.exists("Folder1") || sd.exists("Folder1/file1.txt") ||
|
||||
sd.exists("Folder1/File2.txt")) {
|
||||
error("Please remove existing Folder1, file1.txt, and File2.txt");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
//
|
||||
// The maximum data rate will depend on the quality of your SD,
|
||||
// the size of the FIFO, and using dedicated SPI.
|
||||
#include "SdFat.h"
|
||||
#include "FreeStack.h"
|
||||
#include "ExFatLogger.h"
|
||||
#include "FreeStack.h"
|
||||
#include "SdFat.h"
|
||||
//------------------------------------------------------------------------------
|
||||
// This example was designed for exFAT but will support FAT16/FAT32.
|
||||
// Note: Uno will not support SD_FAT_TYPE = 3.
|
||||
|
|
@ -45,7 +45,7 @@ const uint32_t LOG_INTERVAL_USEC = 2000;
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -71,7 +71,7 @@ const uint32_t PREALLOCATE_SIZE_MiB = 1024UL;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -127,11 +127,11 @@ void printRecord(Print* pr, data_t* data) {
|
|||
}
|
||||
}
|
||||
//==============================================================================
|
||||
const uint64_t PREALLOCATE_SIZE = (uint64_t)PREALLOCATE_SIZE_MiB << 20;
|
||||
const uint64_t PREALLOCATE_SIZE = (uint64_t)PREALLOCATE_SIZE_MiB << 20;
|
||||
// Max length of file name including zero byte.
|
||||
#define FILE_NAME_DIM 40
|
||||
// Max number of records to buffer while SD is busy.
|
||||
const size_t FIFO_DIM = 512*FIFO_SIZE_SECTORS/sizeof(data_t);
|
||||
const size_t FIFO_DIM = 512 * FIFO_SIZE_SECTORS / sizeof(data_t);
|
||||
|
||||
#if SD_FAT_TYPE == 0
|
||||
typedef SdFat sd_t;
|
||||
|
|
@ -191,22 +191,22 @@ void binaryToCsv() {
|
|||
data_t binData[FIFO_DIM];
|
||||
|
||||
if (!binFile.seekSet(512)) {
|
||||
error("binFile.seek failed");
|
||||
error("binFile.seek failed");
|
||||
}
|
||||
uint32_t tPct = millis();
|
||||
printRecord(&csvFile, nullptr);
|
||||
while (!Serial.available() && binFile.available()) {
|
||||
int nb = binFile.read(binData, sizeof(binData));
|
||||
if (nb <= 0 ) {
|
||||
if (nb <= 0) {
|
||||
error("read binFile failed");
|
||||
}
|
||||
size_t nr = nb/sizeof(data_t);
|
||||
size_t nr = nb / sizeof(data_t);
|
||||
for (size_t i = 0; i < nr; i++) {
|
||||
printRecord(&csvFile, &binData[i]);
|
||||
}
|
||||
|
||||
if ((millis() - tPct) > 1000) {
|
||||
uint8_t pct = binFile.curPosition()/(binFile.fileSize()/100);
|
||||
uint8_t pct = binFile.curPosition() / (binFile.fileSize() / 100);
|
||||
if (pct != lastPct) {
|
||||
tPct = millis();
|
||||
lastPct = pct;
|
||||
|
|
@ -221,7 +221,7 @@ void binaryToCsv() {
|
|||
}
|
||||
csvFile.close();
|
||||
Serial.print(F("Done: "));
|
||||
Serial.print(0.001*(millis() - t0));
|
||||
Serial.print(0.001 * (millis() - t0));
|
||||
Serial.println(F(" Seconds"));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -302,7 +302,7 @@ void logData() {
|
|||
uint16_t overrun = 0;
|
||||
uint16_t maxOverrun = 0;
|
||||
uint32_t totalOverrun = 0;
|
||||
uint32_t fifoBuf[128*FIFO_SIZE_SECTORS];
|
||||
uint32_t fifoBuf[128 * FIFO_SIZE_SECTORS];
|
||||
data_t* fifoData = (data_t*)fifoBuf;
|
||||
|
||||
// Write dummy sector to start multi-block write.
|
||||
|
|
@ -315,7 +315,8 @@ void logData() {
|
|||
Serial.println(F("Type any character to stop"));
|
||||
|
||||
// Wait until SD is not busy.
|
||||
while (sd.card()->isBusy()) {}
|
||||
while (sd.card()->isBusy()) {
|
||||
}
|
||||
|
||||
// Start time for log file.
|
||||
uint32_t m = millis();
|
||||
|
|
@ -370,9 +371,9 @@ void logData() {
|
|||
if (!sd.card()->isBusy()) {
|
||||
size_t nw = fifoHead > fifoTail ? fifoCount : FIFO_DIM - fifoTail;
|
||||
// Limit write time by not writing more than 512 bytes.
|
||||
const size_t MAX_WRITE = 512/sizeof(data_t);
|
||||
const size_t MAX_WRITE = 512 / sizeof(data_t);
|
||||
if (nw > MAX_WRITE) nw = MAX_WRITE;
|
||||
size_t nb = nw*sizeof(data_t);
|
||||
size_t nb = nw * sizeof(data_t);
|
||||
uint32_t usec = micros();
|
||||
if (nb != binFile.write(fifoData + fifoTail, nb)) {
|
||||
error("write binFile failed");
|
||||
|
|
@ -392,7 +393,7 @@ void logData() {
|
|||
}
|
||||
}
|
||||
Serial.print(F("\nLog time: "));
|
||||
Serial.print(0.001*(millis() - m));
|
||||
Serial.print(0.001 * (millis() - m));
|
||||
Serial.println(F(" Seconds"));
|
||||
binFile.truncate();
|
||||
binFile.sync();
|
||||
|
|
@ -469,7 +470,7 @@ void printUnusedStack() {
|
|||
//------------------------------------------------------------------------------
|
||||
bool serialReadLine(char* str, size_t size) {
|
||||
size_t n = 0;
|
||||
while(!Serial.available()) {
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
while (true) {
|
||||
|
|
@ -481,7 +482,8 @@ bool serialReadLine(char* str, size_t size) {
|
|||
return false;
|
||||
}
|
||||
uint32_t m = millis();
|
||||
while (!Serial.available() && (millis() - m) < 100){}
|
||||
while (!Serial.available() && (millis() - m) < 100) {
|
||||
}
|
||||
if (!Serial.available()) break;
|
||||
}
|
||||
str[n] = 0;
|
||||
|
|
@ -525,9 +527,9 @@ void setup() {
|
|||
}
|
||||
FillStack();
|
||||
#if !ENABLE_DEDICATED_SPI
|
||||
Serial.println(F(
|
||||
"\nFor best performance edit SdFatConfig.h\n"
|
||||
"and set ENABLE_DEDICATED_SPI nonzero"));
|
||||
Serial.println(
|
||||
F("\nFor best performance edit SdFatConfig.h\n"
|
||||
"and set ENABLE_DEDICATED_SPI nonzero"));
|
||||
#endif // !ENABLE_DEDICATED_SPI
|
||||
|
||||
Serial.print(FIFO_DIM);
|
||||
|
|
@ -567,7 +569,7 @@ void loop() {
|
|||
Serial.println(F("p - print data to Serial"));
|
||||
Serial.println(F("r - record data"));
|
||||
Serial.println(F("t - test without logging"));
|
||||
while(!Serial.available()) {
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
char c = tolower(Serial.read());
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ File file;
|
|||
#include "SdFat.h"
|
||||
// Setting ENABLE_DEDICATED_SPI to zero saves over 200 more bytes.
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
#warning "Set ENABLE_DEDICATED_SPI zero in SdFat/src/SdFatConfig.h for minimum size"
|
||||
#warning \
|
||||
"Set ENABLE_DEDICATED_SPI zero in SdFat/src/SdFatConfig.h for minimum size"
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
// Insure FAT16/FAT32 only.
|
||||
SdFat32 SD;
|
||||
|
|
@ -24,17 +25,19 @@ FatFile file;
|
|||
|
||||
void error(const char* msg) {
|
||||
Serial.println(msg);
|
||||
while(true);
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
int n;
|
||||
char buf[4];
|
||||
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
while (!Serial) {
|
||||
}
|
||||
Serial.println("Type any character to begin");
|
||||
while (!Serial.available()) {}
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
|
||||
if (!SD.begin(CS_PIN)) error("SD.begin");
|
||||
|
||||
|
|
@ -47,12 +50,11 @@ void setup() {
|
|||
if (!file.openExistingSFN(SFN_PATH)) error("open");
|
||||
#endif
|
||||
while ((n = file.read(buf, sizeof(buf)))) {
|
||||
Serial.write(buf, n);
|
||||
Serial.write(buf, n);
|
||||
}
|
||||
// close() is only needed if you write to the file. For example, read
|
||||
// config data, modify the data, rewind the file and write the data.
|
||||
// file.close();
|
||||
// close() is only needed if you write to the file. For example, read
|
||||
// config data, modify the data, rewind the file and write the data.
|
||||
// file.close();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -29,7 +29,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -76,7 +76,7 @@ void setup() {
|
|||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
// Open root directory
|
||||
if (!dir.open("/")){
|
||||
if (!dir.open("/")) {
|
||||
error("dir.open failed");
|
||||
}
|
||||
// Open next file in root.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Quick hardware test for SPI card access.
|
||||
//
|
||||
#include <SPI.h>
|
||||
|
||||
#include "SdFat.h"
|
||||
#include "sdios.h"
|
||||
|
||||
|
|
@ -81,17 +82,17 @@ void setup() {
|
|||
|
||||
if (DISABLE_CHIP_SELECT < 0) {
|
||||
cout << F(
|
||||
"\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
|
||||
"a second SPI device. For example, with the Ethernet\n"
|
||||
"shield, DISABLE_CHIP_SELECT should be set to 10\n"
|
||||
"to disable the Ethernet controller.\n");
|
||||
"\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
|
||||
"a second SPI device. For example, with the Ethernet\n"
|
||||
"shield, DISABLE_CHIP_SELECT should be set to 10\n"
|
||||
"to disable the Ethernet controller.\n");
|
||||
}
|
||||
cout << F(
|
||||
"\nSD chip select is the key hardware option.\n"
|
||||
"Common values are:\n"
|
||||
"Arduino Ethernet shield, pin 4\n"
|
||||
"Sparkfun SD shield, pin 8\n"
|
||||
"Adafruit SD shields and modules, pin 10\n");
|
||||
"\nSD chip select is the key hardware option.\n"
|
||||
"Common values are:\n"
|
||||
"Arduino Ethernet shield, pin 4\n"
|
||||
"Sparkfun SD shield, pin 8\n"
|
||||
"Adafruit SD shields and modules, pin 10\n");
|
||||
}
|
||||
|
||||
bool firstTry = true;
|
||||
|
|
@ -117,8 +118,8 @@ void loop() {
|
|||
}
|
||||
if (DISABLE_CHIP_SELECT < 0) {
|
||||
cout << F(
|
||||
"\nAssuming the SD is the only SPI device.\n"
|
||||
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
|
||||
"\nAssuming the SD is the only SPI device.\n"
|
||||
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
|
||||
} else {
|
||||
cout << F("\nDisabling SPI device on pin ");
|
||||
cout << int(DISABLE_CHIP_SELECT) << endl;
|
||||
|
|
@ -128,12 +129,12 @@ void loop() {
|
|||
if (!sd.begin(chipSelect, SPI_SPEED)) {
|
||||
if (sd.card()->errorCode()) {
|
||||
cout << F(
|
||||
"\nSD initialization failed.\n"
|
||||
"Do not reformat the card!\n"
|
||||
"Is the card correctly inserted?\n"
|
||||
"Is chipSelect set to the correct value?\n"
|
||||
"Does another SPI device need to be disabled?\n"
|
||||
"Is there a wiring/soldering problem?\n");
|
||||
"\nSD initialization failed.\n"
|
||||
"Do not reformat the card!\n"
|
||||
"Is the card correctly inserted?\n"
|
||||
"Is chipSelect set to the correct value?\n"
|
||||
"Does another SPI device need to be disabled?\n"
|
||||
"Is there a wiring/soldering problem?\n");
|
||||
cout << F("\nerrorCode: ") << hex << showbase;
|
||||
cout << int(sd.card()->errorCode());
|
||||
cout << F(", errorData: ") << int(sd.card()->errorData());
|
||||
|
|
@ -169,8 +170,8 @@ void loop() {
|
|||
cout << F("Files found (date time size name):\n");
|
||||
sd.ls(LS_R | LS_DATE | LS_SIZE);
|
||||
|
||||
if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64)
|
||||
|| (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
|
||||
if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64) ||
|
||||
(sizeMB < 2200 && sd.vol()->fatType() == 32)) {
|
||||
cout << F("\nThis card should be reformatted for best performance.\n");
|
||||
cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
|
||||
cout << F("Only cards larger than 2 GB should be formatted FAT32.\n");
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -26,7 +26,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -127,10 +127,10 @@ void setup() {
|
|||
error("open failed");
|
||||
}
|
||||
// Write test data.
|
||||
file.print(F(
|
||||
"abc,123,456,7.89\r\n"
|
||||
"def,-321,654,-9.87\r\n"
|
||||
"ghi,333,0xff,5.55"));
|
||||
file.print(
|
||||
F("abc,123,456,7.89\r\n"
|
||||
"def,-321,654,-9.87\r\n"
|
||||
"ghi,333,0xff,5.55"));
|
||||
|
||||
// Rewind file for read.
|
||||
file.rewind();
|
||||
|
|
@ -140,7 +140,7 @@ void setup() {
|
|||
if (n <= 0) {
|
||||
error("fgets failed");
|
||||
}
|
||||
if (line[n-1] != '\n' && n == (sizeof(line) - 1)) {
|
||||
if (line[n - 1] != '\n' && n == (sizeof(line) - 1)) {
|
||||
error("line too long");
|
||||
}
|
||||
if (!parseLine(line)) {
|
||||
|
|
@ -152,5 +152,4 @@ void setup() {
|
|||
Serial.println(F("Done"));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -37,7 +37,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -59,7 +59,6 @@ FsFile file;
|
|||
#error Invalid SD_FAT_TYPE
|
||||
#endif // SD_FAT_TYPE
|
||||
|
||||
|
||||
#if RTC_TYPE == 0
|
||||
RTC_Millis rtc;
|
||||
#elif RTC_TYPE == 1
|
||||
|
|
@ -108,12 +107,12 @@ void getLine(char* line, size_t size) {
|
|||
while (true) {
|
||||
t = millis() + 10;
|
||||
while (!Serial.available()) {
|
||||
if (millis() > t){
|
||||
if (millis() > t) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
int c = Serial.read();
|
||||
if (i >= (size - 1) || c == '\r' || c == '\n' ) {
|
||||
if (i >= (size - 1) || c == '\r' || c == '\n') {
|
||||
return;
|
||||
}
|
||||
line[i++] = c;
|
||||
|
|
@ -134,11 +133,11 @@ void printField(Print* pr, char sep, uint8_t v) {
|
|||
void printNow(Print* pr) {
|
||||
DateTime now = rtc.now();
|
||||
pr->print(now.year());
|
||||
printField(pr, '-',now.month());
|
||||
printField(pr, '-',now.day());
|
||||
printField(pr, ' ',now.hour());
|
||||
printField(pr, ':',now.minute());
|
||||
printField(pr, ':',now.second());
|
||||
printField(pr, '-', now.month());
|
||||
printField(pr, '-', now.day());
|
||||
printField(pr, ' ', now.hour());
|
||||
printField(pr, ':', now.minute());
|
||||
printField(pr, ':', now.second());
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool setRtc() {
|
||||
|
|
@ -180,7 +179,7 @@ void setup() {
|
|||
}
|
||||
#if RTC_TYPE == 0
|
||||
rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
|
||||
#else // RTC_TYPE
|
||||
#else // RTC_TYPE
|
||||
if (!rtc.begin()) {
|
||||
Serial.println(F("rtc.begin failed"));
|
||||
return;
|
||||
|
|
@ -201,7 +200,8 @@ void setup() {
|
|||
Serial.println();
|
||||
clearSerialInput();
|
||||
Serial.println(F("Type Y to set RTC, any other character to continue"));
|
||||
while (!Serial.available()) {}
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
if (Serial.read() != 'Y') break;
|
||||
if (setRtc()) break;
|
||||
}
|
||||
|
|
@ -232,5 +232,4 @@ void setup() {
|
|||
Serial.println(F("Done"));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
|
|
@ -2,7 +2,8 @@
|
|||
#include "SdFat.h"
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
while (!Serial) {
|
||||
}
|
||||
delay(1000);
|
||||
Serial.println();
|
||||
Serial.println(F("Code,Symbol - failed operation"));
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const int8_t DISABLE_CS_PIN = -1;
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -42,7 +42,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -52,14 +52,18 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
ArduinoOutStream cout(Serial);
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t cardSectorCount = 0;
|
||||
uint8_t sectorBuffer[512];
|
||||
uint8_t sectorBuffer[512];
|
||||
//------------------------------------------------------------------------------
|
||||
// SdCardFactory constructs and initializes the appropriate card.
|
||||
SdCardFactory cardFactory;
|
||||
// Pointer to generic SD card.
|
||||
SdCard* m_card = nullptr;
|
||||
//------------------------------------------------------------------------------
|
||||
#define sdError(msg) {cout << F("error: ") << F(msg) << endl; sdErrorHalt();}
|
||||
#define sdError(msg) \
|
||||
{ \
|
||||
cout << F("error: ") << F(msg) << endl; \
|
||||
sdErrorHalt(); \
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void sdErrorHalt() {
|
||||
if (!m_card) {
|
||||
|
|
@ -73,7 +77,8 @@ void sdErrorHalt() {
|
|||
cout << F(" = ") << int(m_card->errorCode()) << endl;
|
||||
cout << F("SD errorData = ") << int(m_card->errorData()) << endl;
|
||||
}
|
||||
while (true) {}
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void clearSerialInput() {
|
||||
|
|
@ -102,7 +107,7 @@ void eraseCard() {
|
|||
sdError("erase failed");
|
||||
}
|
||||
cout << '.';
|
||||
if ((n++)%64 == 63) {
|
||||
if ((n++) % 64 == 63) {
|
||||
cout << endl;
|
||||
}
|
||||
firstBlock += ERASE_SIZE;
|
||||
|
|
@ -123,9 +128,9 @@ void formatCard() {
|
|||
FatFormatter fatFormatter;
|
||||
|
||||
// Format exFAT if larger than 32GB.
|
||||
bool rtn = cardSectorCount > 67108864 ?
|
||||
exFatFormatter.format(m_card, sectorBuffer, &Serial) :
|
||||
fatFormatter.format(m_card, sectorBuffer, &Serial);
|
||||
bool rtn = cardSectorCount > 67108864
|
||||
? exFatFormatter.format(m_card, sectorBuffer, &Serial)
|
||||
: fatFormatter.format(m_card, sectorBuffer, &Serial);
|
||||
|
||||
if (!rtn) {
|
||||
sdErrorHalt();
|
||||
|
|
@ -136,8 +141,8 @@ void formatCard() {
|
|||
void printConfig(SdSpiConfig config) {
|
||||
if (DISABLE_CS_PIN < 0) {
|
||||
cout << F(
|
||||
"\nAssuming the SD is the only SPI device.\n"
|
||||
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
|
||||
"\nAssuming the SD is the only SPI device.\n"
|
||||
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
|
||||
} else {
|
||||
cout << F("\nDisabling SPI device on pin ");
|
||||
cout << int(DISABLE_CS_PIN) << endl;
|
||||
|
|
@ -169,19 +174,19 @@ void setup() {
|
|||
clearSerialInput();
|
||||
|
||||
cout << F(
|
||||
"\n"
|
||||
"This program can erase and/or format SD/SDHC/SDXC cards.\n"
|
||||
"\n"
|
||||
"Erase uses the card's fast flash erase command.\n"
|
||||
"Flash erase sets all data to 0X00 for most cards\n"
|
||||
"and 0XFF for a few vendor's cards.\n"
|
||||
"\n"
|
||||
"Cards up to 2 GiB (GiB = 2^30 bytes) will be formated FAT16.\n"
|
||||
"Cards larger than 2 GiB and up to 32 GiB will be formatted\n"
|
||||
"FAT32. Cards larger than 32 GiB will be formatted exFAT.\n"
|
||||
"\n"
|
||||
"Warning, all data on the card will be erased.\n"
|
||||
"Enter 'Y' to continue: ");
|
||||
"\n"
|
||||
"This program can erase and/or format SD/SDHC/SDXC cards.\n"
|
||||
"\n"
|
||||
"Erase uses the card's fast flash erase command.\n"
|
||||
"Flash erase sets all data to 0X00 for most cards\n"
|
||||
"and 0XFF for a few vendor's cards.\n"
|
||||
"\n"
|
||||
"Cards up to 2 GiB (GiB = 2^30 bytes) will be formated FAT16.\n"
|
||||
"Cards larger than 2 GiB and up to 32 GiB will be formatted\n"
|
||||
"FAT32. Cards larger than 32 GiB will be formatted exFAT.\n"
|
||||
"\n"
|
||||
"Warning, all data on the card will be erased.\n"
|
||||
"Enter 'Y' to continue: ");
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
|
|
@ -207,9 +212,9 @@ void setup() {
|
|||
return;
|
||||
}
|
||||
|
||||
cout << F("\nCard size: ") << cardSectorCount*5.12e-7;
|
||||
cout << F("\nCard size: ") << cardSectorCount * 5.12e-7;
|
||||
cout << F(" GB (GB = 1E9 bytes)\n");
|
||||
cout << F("Card size: ") << cardSectorCount/2097152.0;
|
||||
cout << F("Card size: ") << cardSectorCount / 2097152.0;
|
||||
cout << F(" GiB (GiB = 2^30 bytes)\n");
|
||||
|
||||
cout << F("Card will be formated ");
|
||||
|
|
@ -221,13 +226,13 @@ void setup() {
|
|||
cout << F("FAT16\n");
|
||||
}
|
||||
cout << F(
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
"E - erase the card and skip formatting.\n"
|
||||
"F - erase and then format the card. (recommended)\n"
|
||||
"Q - quick format the card without erase.\n"
|
||||
"\n"
|
||||
"Enter option: ");
|
||||
"\n"
|
||||
"Options are:\n"
|
||||
"E - erase the card and skip formatting.\n"
|
||||
"F - erase and then format the card. (recommended)\n"
|
||||
"Q - quick format the card without erase.\n"
|
||||
"\n"
|
||||
"Enter option: ");
|
||||
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
|
|
@ -245,5 +250,4 @@ void setup() {
|
|||
formatCard();
|
||||
}
|
||||
}
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
|
|
@ -20,7 +20,7 @@ const int8_t DISABLE_CS_PIN = -1;
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ void errorPrint() {
|
|||
bool mbrDmp() {
|
||||
MbrSector_t mbr;
|
||||
bool valid = true;
|
||||
if (!sd.card()->readSector(0, (uint8_t*)&mbr)) {
|
||||
if (!sd.card()->readSector(0, (uint8_t *)&mbr)) {
|
||||
cout << F("\nread MBR failed.\n");
|
||||
errorPrint();
|
||||
return false;
|
||||
|
|
@ -114,11 +114,11 @@ bool mbrDmp() {
|
|||
}
|
||||
cout << int(ip) << ',' << uppercase << showbase << hex;
|
||||
cout << int(pt->boot) << ',';
|
||||
for (int i = 0; i < 3; i++ ) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
cout << int(pt->beginCHS[i]) << ',';
|
||||
}
|
||||
cout << int(pt->type) << ',';
|
||||
for (int i = 0; i < 3; i++ ) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
cout << int(pt->endCHS[i]) << ',';
|
||||
}
|
||||
cout << dec << getLe32(pt->relativeSectors) << ',';
|
||||
|
|
@ -141,18 +141,17 @@ void dmpVol() {
|
|||
cout << F("sectorsPerCluster: ") << sd.sectorsPerCluster() << endl;
|
||||
cout << F("fatStartSector: ") << sd.fatStartSector() << endl;
|
||||
cout << F("dataStartSector: ") << sd.dataStartSector() << endl;
|
||||
cout << F("clusterCount: ") << sd.clusterCount() << endl;
|
||||
cout << F("clusterCount: ") << sd.clusterCount() << endl;
|
||||
cout << F("freeClusterCount: ");
|
||||
if (freeClusterCount >= 0) {
|
||||
cout << freeClusterCount << endl;
|
||||
} else {
|
||||
cout << F("failed\n");
|
||||
errorPrint();
|
||||
errorPrint();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void printCardType() {
|
||||
|
||||
cout << F("\nCard type: ");
|
||||
|
||||
switch (sd.card()->type()) {
|
||||
|
|
@ -180,8 +179,8 @@ void printCardType() {
|
|||
void printConfig(SdSpiConfig config) {
|
||||
if (DISABLE_CS_PIN < 0) {
|
||||
cout << F(
|
||||
"\nAssuming the SD is the only SPI device.\n"
|
||||
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
|
||||
"\nAssuming the SD is the only SPI device.\n"
|
||||
"Edit DISABLE_CS_PIN to disable an SPI device.\n");
|
||||
} else {
|
||||
cout << F("\nDisabling SPI device on pin ");
|
||||
cout << int(DISABLE_CS_PIN) << endl;
|
||||
|
|
@ -205,7 +204,6 @@ void setup() {
|
|||
}
|
||||
cout << F("SdFat version: ") << SD_FAT_VERSION_STR << endl;
|
||||
printConfig(SD_CONFIG);
|
||||
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
|
|
@ -220,15 +218,14 @@ void loop() {
|
|||
uint32_t t = millis();
|
||||
if (!sd.cardBegin(SD_CONFIG)) {
|
||||
cout << F(
|
||||
"\nSD initialization failed.\n"
|
||||
"Do not reformat the card!\n"
|
||||
"Is the card correctly inserted?\n"
|
||||
"Is there a wiring/soldering problem?\n");
|
||||
"\nSD initialization failed.\n"
|
||||
"Do not reformat the card!\n"
|
||||
"Is the card correctly inserted?\n"
|
||||
"Is there a wiring/soldering problem?\n");
|
||||
if (isSpi(SD_CONFIG)) {
|
||||
cout << F(
|
||||
"Is SD_CS_PIN set to the correct value?\n"
|
||||
"Does another SPI device need to be disabled?\n"
|
||||
);
|
||||
"Is SD_CS_PIN set to the correct value?\n"
|
||||
"Does another SPI device need to be disabled?\n");
|
||||
}
|
||||
errorPrint();
|
||||
return;
|
||||
|
|
@ -236,23 +233,21 @@ void loop() {
|
|||
t = millis() - t;
|
||||
cout << F("init time: ") << dec << t << " ms" << endl;
|
||||
|
||||
if (!sd.card()->readCID(&cid) ||
|
||||
!sd.card()->readCSD(&csd) ||
|
||||
!sd.card()->readOCR(&ocr) ||
|
||||
!sd.card()->readSCR(&scr)) {
|
||||
if (!sd.card()->readCID(&cid) || !sd.card()->readCSD(&csd) ||
|
||||
!sd.card()->readOCR(&ocr) || !sd.card()->readSCR(&scr)) {
|
||||
cout << F("readInfo failed\n");
|
||||
errorPrint();
|
||||
return;
|
||||
}
|
||||
printCardType();
|
||||
cout << F("sdSpecVer: ") << 0.01*scr.sdSpecVer() << endl;
|
||||
cout << F("sdSpecVer: ") << 0.01 * scr.sdSpecVer() << endl;
|
||||
cout << F("HighSpeedMode: ");
|
||||
if (scr.sdSpecVer() &&
|
||||
sd.card()->cardCMD6(0X00FFFFFF, cmd6Data) && (2 & cmd6Data[13])) {
|
||||
if (scr.sdSpecVer() && sd.card()->cardCMD6(0X00FFFFFF, cmd6Data) &&
|
||||
(2 & cmd6Data[13])) {
|
||||
cout << F("true\n");
|
||||
} else {
|
||||
cout << F("false\n");
|
||||
}
|
||||
}
|
||||
cidDmp();
|
||||
csdDmp();
|
||||
cout << F("\nOCR: ") << uppercase << showbase;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const uint8_t SD_CS_PIN = 10;
|
|||
// Pin numbers in templates must be constants.
|
||||
const uint8_t SOFT_MISO_PIN = 12;
|
||||
const uint8_t SOFT_MOSI_PIN = 11;
|
||||
const uint8_t SOFT_SCK_PIN = 13;
|
||||
const uint8_t SOFT_SCK_PIN = 13;
|
||||
|
||||
// SdFat software SPI template
|
||||
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
|
||||
|
|
@ -77,4 +77,4 @@ void setup() {
|
|||
void loop() {}
|
||||
#else // SPI_DRIVER_SELECT
|
||||
#error SPI_DRIVER_SELECT must be two in SdFat/SdFatConfig.h
|
||||
#endif //SPI_DRIVER_SELECT
|
||||
#endif // SPI_DRIVER_SELECT
|
||||
|
|
@ -1,14 +1,20 @@
|
|||
// Test of Teensy exFAT DMA ADC logger.
|
||||
// This is mainly to test use of RingBuf in an ISR.
|
||||
// This example only supports pins on the first ADC.
|
||||
// it has only been tested on Teensy 3.6 and 4.1.
|
||||
// You should modify it for serious use as a data logger.
|
||||
//
|
||||
#include "ADC.h"
|
||||
#include "DMAChannel.h"
|
||||
#include "SdFat.h"
|
||||
#include "FreeStack.h"
|
||||
#include "RingBuf.h"
|
||||
#include "SdFat.h"
|
||||
|
||||
// Pin must be on first ADC.
|
||||
#define ADC_PIN A0
|
||||
|
||||
// 400 sector RingBuf - could be larger on Teensy 4.1.
|
||||
const size_t RING_BUF_SIZE = 400*512;
|
||||
const size_t RING_BUF_SIZE = 400 * 512;
|
||||
|
||||
// Preallocate 8GiB file.
|
||||
const uint64_t PRE_ALLOCATE_SIZE = 8ULL << 30;
|
||||
|
|
@ -16,15 +22,19 @@ const uint64_t PRE_ALLOCATE_SIZE = 8ULL << 30;
|
|||
// Use FIFO SDIO.
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
|
||||
ADC adc;
|
||||
|
||||
DMAChannel dma(true);
|
||||
|
||||
SdFs sd;
|
||||
|
||||
FsFile file;
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Ping-pong DMA buffer.
|
||||
DMAMEM static uint16_t __attribute__((aligned(32))) dmaBuf[2][256];
|
||||
size_t dmaCount;
|
||||
|
||||
// Count of DMA interrupts.
|
||||
volatile size_t dmaCount;
|
||||
|
||||
// RingBuf for 512 byte sectors.
|
||||
RingBuf<FsFile, RING_BUF_SIZE> rb;
|
||||
|
|
@ -32,18 +42,26 @@ RingBuf<FsFile, RING_BUF_SIZE> rb;
|
|||
// Shared between ISR and background.
|
||||
volatile size_t maxBytesUsed;
|
||||
|
||||
// Overrun error for write to RingBuf.
|
||||
volatile bool overrun;
|
||||
//------------------------------------------------------------------------------
|
||||
//ISR.
|
||||
// ISR for DMA.
|
||||
static void isr() {
|
||||
if (rb.bytesFreeIsr() >= 512 && !overrun) {
|
||||
rb.memcpyIn(dmaBuf[dmaCount & 1], 512);
|
||||
dmaCount++;
|
||||
if (rb.bytesUsed() > maxBytesUsed) {
|
||||
maxBytesUsed = rb.bytesUsed();
|
||||
if (!overrun) {
|
||||
// Clear cache for buffer filled by DMA to insure read from DMA memory.
|
||||
arm_dcache_delete((void*)dmaBuf[dmaCount & 1], 512);
|
||||
// Enable RingBuf functions to be called in ISR.
|
||||
rb.beginISR();
|
||||
if (rb.write(dmaBuf[dmaCount & 1], 512) == 512) {
|
||||
dmaCount++;
|
||||
if (rb.bytesUsed() > maxBytesUsed) {
|
||||
maxBytesUsed = rb.bytesUsed();
|
||||
}
|
||||
} else {
|
||||
overrun = true;
|
||||
}
|
||||
} else {
|
||||
overrun = true;
|
||||
// End use of RingBuf functions in ISR.
|
||||
rb.endISR();
|
||||
}
|
||||
dma.clearComplete();
|
||||
dma.clearInterrupt();
|
||||
|
|
@ -53,39 +71,7 @@ static void isr() {
|
|||
#endif // defined(__IMXRT1062__)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Over-clocking will degrade quality - use only for stress testing.
|
||||
void overclock() {
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
ADC1_CFG =
|
||||
// High Speed Configuration
|
||||
ADC_CFG_ADHSC |
|
||||
// Sample period 3 clocks
|
||||
ADC_CFG_ADSTS(0) |
|
||||
// Input clock
|
||||
ADC_CFG_ADIV(0) |
|
||||
// Not selected - Long Sample Time Configuration
|
||||
// ADC_CFG_ADLSMP |
|
||||
// 12-bit
|
||||
ADC_CFG_MODE(2) |
|
||||
// Asynchronous clock
|
||||
ADC_CFG_ADICLK(3);
|
||||
#else // defined(__IMXRT1062__)
|
||||
// Set 12 bit mode and max over-clock
|
||||
ADC0_CFG1 =
|
||||
// Clock divide select, 0=direct, 1=div2, 2=div4, 3=div8
|
||||
ADC_CFG1_ADIV(0) |
|
||||
// Sample time configuration, 0=Short, 1=Long
|
||||
// ADC_CFG1_ADLSMP |
|
||||
// Conversion mode, 0=8 bit, 1=12 bit, 2=10 bit, 3=16 bit
|
||||
ADC_CFG1_MODE(1) |
|
||||
// Input clock, 0=bus, 1=bus/2, 2=OSCERCLK, 3=async
|
||||
ADC_CFG1_ADICLK(0);
|
||||
|
||||
ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(3);
|
||||
#endif // defined(__IMXRT1062__)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
#if defined(__IMXRT1062__) // Teensy 4.x
|
||||
#define SOURCE_SADDR ADC1_R0
|
||||
#define SOURCE_EVENT DMAMUX_SOURCE_ADC1
|
||||
#else
|
||||
|
|
@ -93,54 +79,26 @@ void overclock() {
|
|||
#define SOURCE_EVENT DMAMUX_SOURCE_ADC0
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
// Should replace ADC stuff with calls to Teensy ADC library.
|
||||
// https://github.com/pedvide/ADC
|
||||
static void init(uint8_t pin) {
|
||||
uint32_t adch;
|
||||
uint32_t i, sum = 0;
|
||||
// Actually, do many normal reads, to start with a nice DC level
|
||||
for (i=0; i < 1024; i++) {
|
||||
sum += analogRead(pin);
|
||||
}
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
// save channel
|
||||
adch = ADC1_HC0 & 0x1F;
|
||||
// Continuous conversion , DMA enable
|
||||
ADC1_GC = ADC_GC_ADCO | ADC_GC_DMAEN;
|
||||
// start conversion
|
||||
ADC1_HC0 = adch;
|
||||
#else // defined(__IMXRT1062__) // Teensy 4.0
|
||||
// save channel
|
||||
adch = ADC0_SC1A & 0x1F;
|
||||
// DMA enable
|
||||
ADC0_SC2 |= ADC_SC2_DMAEN;
|
||||
// Continuous conversion enable
|
||||
ADC0_SC3 = ADC_SC3_ADCO;
|
||||
// Start ADC
|
||||
ADC0_SC1A = adch;
|
||||
#endif // defined(__IMXRT1062__) // Teensy 4.0
|
||||
// set up a DMA channel to store the ADC data
|
||||
dma.attachInterrupt(isr);
|
||||
dma.begin();
|
||||
dma.source((volatile const signed short &)SOURCE_SADDR);
|
||||
dma.begin();
|
||||
dma.attachInterrupt(isr);
|
||||
dma.source((volatile const signed short&)SOURCE_SADDR);
|
||||
dma.destinationBuffer((volatile uint16_t*)dmaBuf, sizeof(dmaBuf));
|
||||
dma.interruptAtHalf();
|
||||
dma.interruptAtCompletion();
|
||||
dma.triggerAtHardwareEvent(SOURCE_EVENT);
|
||||
dma.enable();
|
||||
dma.triggerAtHardwareEvent(SOURCE_EVENT);
|
||||
dma.enable();
|
||||
adc.adc0->enableDMA();
|
||||
adc.adc0->startContinuous(pin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void stopDma() {
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
ADC1_GC = 0;
|
||||
#else // defined(__IMXRT1062__)
|
||||
ADC0_SC3 = 0;
|
||||
#endif // defined(__IMXRT1062__)
|
||||
adc.adc0->disableDMA();
|
||||
dma.disable();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void printTest(Print* pr) {
|
||||
if (file.fileSize() < 1024*2) {
|
||||
if (file.fileSize() < 1024 * 2) {
|
||||
return;
|
||||
}
|
||||
file.rewind();
|
||||
|
|
@ -153,7 +111,8 @@ void printTest(Print* pr) {
|
|||
for (size_t i = 0; i < 1024; i++) {
|
||||
pr->print(i);
|
||||
pr->print(',');
|
||||
rb.memcpyOut(&data, 2);
|
||||
// Test read with: template <typename Type>bool read(Type* data).
|
||||
rb.read(&data);
|
||||
pr->println(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -192,36 +151,42 @@ void runTest(uint8_t pin) {
|
|||
}
|
||||
}
|
||||
stopDma();
|
||||
samplingTime = (micros() - samplingTime);
|
||||
samplingTime = micros() - samplingTime;
|
||||
if (!rb.sync()) {
|
||||
Serial.println("sync() failed");
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
if (!file.truncate()) {
|
||||
sd.errorHalt("truncate failed");
|
||||
}
|
||||
if (overrun) {
|
||||
Serial.println("Overrun ERROR!!");
|
||||
}
|
||||
Serial.print("dmsCount ");
|
||||
Serial.println(dmaCount);
|
||||
Serial.print("RingBufSize ");
|
||||
Serial.println(RING_BUF_SIZE);
|
||||
Serial.print("maxBytesUsed ");
|
||||
Serial.println(maxBytesUsed);
|
||||
Serial.print("fileSize ");
|
||||
Serial.println((uint32_t)file.fileSize());
|
||||
Serial.print(0.000001*samplingTime);
|
||||
file.printFileSize(&Serial);
|
||||
Serial.println();
|
||||
Serial.print(0.000001 * samplingTime);
|
||||
Serial.println(" seconds");
|
||||
Serial.print(1.0*file.fileSize()/samplingTime, 3);
|
||||
Serial.print(1.0 * file.fileSize() / samplingTime, 3);
|
||||
Serial.println(" MB/sec\n");
|
||||
printTest(&Serial);
|
||||
file.close();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void waitSerial(const char* msg) {
|
||||
uint32_t m = micros();
|
||||
do {
|
||||
if (Serial.read() >= 0) {
|
||||
m = micros();
|
||||
}
|
||||
} while (micros() - m < 10000);
|
||||
delay(10);
|
||||
} while (Serial.read() >= 0);
|
||||
Serial.println(msg);
|
||||
while (!Serial.available()) {}
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -239,9 +204,11 @@ void loop() {
|
|||
if (!sd.begin(SD_CONFIG)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
//analogReadAveraging(1);
|
||||
//analogReadResolution(12);
|
||||
//overclock(); // 3 Msps on Teensy 3.6 - requires high quality card.
|
||||
runTest(A0);
|
||||
// Try for max speed.
|
||||
adc.adc0->setAveraging(1);
|
||||
adc.adc0->setResolution(10);
|
||||
adc.adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
|
||||
adc.adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
|
||||
runTest(ADC_PIN);
|
||||
waitSerial("Type any character to run test again");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
// Test of time-stamp callback with Teensy 3/4.
|
||||
// The upload time will be used to set the RTC.
|
||||
// You must arrange for syncing the RTC.
|
||||
#include "SdFat.h"
|
||||
#include <TimeLib.h>
|
||||
|
||||
#include "SdFat.h"
|
||||
|
||||
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
|
||||
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
|
||||
#define SD_FAT_TYPE 3
|
||||
|
|
@ -19,7 +20,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -30,7 +31,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -55,7 +56,6 @@ FsFile file;
|
|||
//------------------------------------------------------------------------------
|
||||
// Call back for file timestamps. Only called for file create and sync().
|
||||
void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
|
||||
|
||||
// Return date using FS_DATE macro to format fields.
|
||||
*date = FS_DATE(year(), month(), day());
|
||||
|
||||
|
|
@ -66,10 +66,7 @@ void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
|
|||
*ms10 = second() & 1 ? 100 : 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
time_t getTeensy3Time()
|
||||
{
|
||||
return Teensy3Clock.get();
|
||||
}
|
||||
time_t getTeensy3Time() { return Teensy3Clock.get(); }
|
||||
//------------------------------------------------------------------------------
|
||||
void printField(Print* pr, char sep, uint8_t v) {
|
||||
if (sep) {
|
||||
|
|
@ -102,7 +99,7 @@ void setup() {
|
|||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
if (timeStatus()!= timeSet) {
|
||||
if (timeStatus() != timeSet) {
|
||||
Serial.println("Unable to sync with the RTC");
|
||||
return;
|
||||
}
|
||||
|
|
@ -135,5 +132,4 @@ void setup() {
|
|||
Serial.println(F("Done"));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -20,7 +20,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
const size_t BUF_DIM = 32768;
|
||||
|
||||
// 8 MiB file.
|
||||
const uint32_t FILE_SIZE = 256UL*BUF_DIM;
|
||||
const uint32_t FILE_SIZE = 256UL * BUF_DIM;
|
||||
|
||||
#if SD_FAT_TYPE == 0
|
||||
SdFat sd;
|
||||
|
|
@ -72,13 +72,12 @@ void errorHalt(const char* msg) {
|
|||
Serial.print(", ErrorData: 0X");
|
||||
Serial.println(sd.sdErrorData(), HEX);
|
||||
}
|
||||
while (true) {}
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
bool ready = false;
|
||||
//------------------------------------------------------------------------------
|
||||
bool sdBusy() {
|
||||
return ready ? sd.card()->isBusy() : false;
|
||||
}
|
||||
bool sdBusy() { return ready ? sd.card()->isBusy() : false; }
|
||||
//------------------------------------------------------------------------------
|
||||
// Replace "weak" system yield() function.
|
||||
void yield() {
|
||||
|
|
@ -110,7 +109,7 @@ void runTest() {
|
|||
Serial.println("\nsize,write,read");
|
||||
Serial.println("bytes,KB/sec,KB/sec");
|
||||
for (size_t nb = 512; nb <= BUF_DIM; nb *= 2) {
|
||||
uint32_t nRdWr = FILE_SIZE/nb;
|
||||
uint32_t nRdWr = FILE_SIZE / nb;
|
||||
if (!file.truncate(0)) {
|
||||
errorHalt("truncate failed");
|
||||
}
|
||||
|
|
@ -121,14 +120,14 @@ void runTest() {
|
|||
for (uint32_t n = 0; n < nRdWr; n++) {
|
||||
// Set start and end of buffer.
|
||||
buf32[0] = n;
|
||||
buf32[nb/4 - 1] = n;
|
||||
buf32[nb / 4 - 1] = n;
|
||||
if (nb != file.write(buf, nb)) {
|
||||
errorHalt("write failed");
|
||||
}
|
||||
}
|
||||
t = micros() - t;
|
||||
totalMicros += t;
|
||||
Serial.print(1000.0*FILE_SIZE/t);
|
||||
Serial.print(1000.0 * FILE_SIZE / t);
|
||||
Serial.print(',');
|
||||
file.rewind();
|
||||
t = micros();
|
||||
|
|
@ -138,13 +137,13 @@ void runTest() {
|
|||
errorHalt("read failed");
|
||||
}
|
||||
// crude check of data.
|
||||
if (buf32[0] != n || buf32[nb/4 - 1] != n) {
|
||||
if (buf32[0] != n || buf32[nb / 4 - 1] != n) {
|
||||
errorHalt("data check");
|
||||
}
|
||||
}
|
||||
t = micros() - t;
|
||||
totalMicros += t;
|
||||
Serial.println(1000.0*FILE_SIZE/t);
|
||||
Serial.println(1000.0 * FILE_SIZE / t);
|
||||
}
|
||||
file.close();
|
||||
Serial.print("\ntotalMicros ");
|
||||
|
|
@ -155,8 +154,8 @@ void runTest() {
|
|||
Serial.println(yieldCalls);
|
||||
Serial.print("yieldMaxUsec ");
|
||||
Serial.println(yieldMaxUsec);
|
||||
// Serial.print("kHzSdClk ");
|
||||
// Serial.println(kHzSdClk());
|
||||
// Serial.print("kHzSdClk ");
|
||||
// Serial.println(kHzSdClk());
|
||||
Serial.println("Done");
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -171,22 +170,22 @@ void loop() {
|
|||
if (warn) {
|
||||
warn = false;
|
||||
Serial.println(
|
||||
"SD cards must be power cycled to leave\n"
|
||||
"SPI mode so do SDIO tests first.\n"
|
||||
"\nCycle power on the card if an error occurs.");
|
||||
"SD cards must be power cycled to leave\n"
|
||||
"SPI mode so do SDIO tests first.\n"
|
||||
"\nCycle power on the card if an error occurs.");
|
||||
}
|
||||
clearSerialInput();
|
||||
|
||||
Serial.println(
|
||||
"\nType '1' for FIFO SDIO"
|
||||
"\n '2' for DMA SDIO"
|
||||
"\n '3' for Dedicated SPI"
|
||||
"\n '4' for Shared SPI");
|
||||
"\nType '1' for FIFO SDIO"
|
||||
"\n '2' for DMA SDIO"
|
||||
"\n '3' for Dedicated SPI"
|
||||
"\n '4' for Shared SPI");
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
char c = Serial.read();
|
||||
|
||||
if (c =='1') {
|
||||
if (c == '1') {
|
||||
if (!sd.begin(SdioConfig(FIFO_SDIO))) {
|
||||
errorHalt("begin failed");
|
||||
}
|
||||
|
|
@ -202,7 +201,7 @@ void loop() {
|
|||
errorHalt("begin failed");
|
||||
}
|
||||
Serial.println("\nDedicated SPI mode.");
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
Serial.println("ENABLE_DEDICATED_SPI must be non-zero.");
|
||||
return;
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
|
|
|
|||
|
|
@ -6,20 +6,20 @@
|
|||
// Teensy 4.1. About 5 usec is required to write a sector when the
|
||||
// controller is in write mode.
|
||||
|
||||
#include "SdFat.h"
|
||||
#include "RingBuf.h"
|
||||
#include "SdFat.h"
|
||||
|
||||
// Use Teensy SDIO
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
|
||||
// Interval between points for 25 ksps.
|
||||
#define LOG_INTERVAL_USEC 40
|
||||
|
||||
// Size to log 10 byte lines at 25 kHz for more than ten minutes.
|
||||
#define LOG_FILE_SIZE 10*25000*600 // 150,000,000 bytes.
|
||||
#define LOG_FILE_SIZE 10 * 25000 * 600 // 150,000,000 bytes.
|
||||
|
||||
// Space to hold more than 800 ms of data for 10 byte lines at 25 ksps.
|
||||
#define RING_BUF_CAPACITY 400*512
|
||||
#define RING_BUF_CAPACITY 400 * 512
|
||||
#define LOG_FILENAME "SdioLogger.csv"
|
||||
|
||||
SdFs sd;
|
||||
|
|
@ -41,9 +41,9 @@ void logData() {
|
|||
// File must be pre-allocated to avoid huge
|
||||
// delays searching for free clusters.
|
||||
if (!file.preAllocate(LOG_FILE_SIZE)) {
|
||||
Serial.println("preAllocate failed\n");
|
||||
file.close();
|
||||
return;
|
||||
Serial.println("preAllocate failed\n");
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
// initialize the RingBuf.
|
||||
rb.begin(&file);
|
||||
|
|
@ -88,7 +88,8 @@ void logData() {
|
|||
break;
|
||||
}
|
||||
// Wait until time to log data.
|
||||
while (micros() < logTime) {}
|
||||
while (micros() < logTime) {
|
||||
}
|
||||
|
||||
// Read ADC0 - about 17 usec on Teensy 4, Teensy 3.6 is faster.
|
||||
uint16_t adc = analogRead(0);
|
||||
|
|
@ -134,7 +135,8 @@ void clearSerialInput() {
|
|||
}
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
while (!Serial) {
|
||||
}
|
||||
// Go faster or log more channels. ADC quality will suffer.
|
||||
// analogReadAveraging(1);
|
||||
}
|
||||
|
|
@ -142,7 +144,8 @@ void setup() {
|
|||
void loop() {
|
||||
clearSerialInput();
|
||||
Serial.println("Type any character to start");
|
||||
while (!Serial.available()) {};
|
||||
while (!Serial.available()) {
|
||||
}
|
||||
clearSerialInput();
|
||||
logData();
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ const char* names[] = {u8"россиянин", u8"très élégant", u8"狗.txt",
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -91,8 +91,7 @@ void setup() {
|
|||
#endif // REMOVE_UTF8_FILES
|
||||
Serial.println("Done!");
|
||||
}
|
||||
void loop() {
|
||||
}
|
||||
void loop() {}
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#error USE_UTF8_LONG_NAMES must be non-zero in SdFat/src/SdFatCongfig.h
|
||||
#endif // USE_UTF8_LONG_NAMES
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// An example of an external SPI driver.
|
||||
//
|
||||
#include "SdFat.h"
|
||||
#include "SPI.h" // Only required if you use features in the SPI library.
|
||||
#include "SdFat.h"
|
||||
|
||||
#if SPI_DRIVER_SELECT == 3 // Must be set in SdFat/SdFatConfig.h
|
||||
|
||||
|
|
@ -16,22 +16,16 @@
|
|||
class MySpiClass : public SdSpiBaseClass {
|
||||
public:
|
||||
// Activate SPI hardware with correct speed and mode.
|
||||
void activate() {
|
||||
SPI.beginTransaction(m_spiSettings);
|
||||
}
|
||||
void activate() { SPI.beginTransaction(m_spiSettings); }
|
||||
// Initialize the SPI bus.
|
||||
void begin(SdSpiConfig config) {
|
||||
(void)config;
|
||||
SPI.begin();
|
||||
}
|
||||
// Deactivate SPI hardware.
|
||||
void deactivate() {
|
||||
SPI.endTransaction();
|
||||
}
|
||||
void deactivate() { SPI.endTransaction(); }
|
||||
// Receive a byte.
|
||||
uint8_t receive() {
|
||||
return SPI.transfer(0XFF);
|
||||
}
|
||||
uint8_t receive() { return SPI.transfer(0XFF); }
|
||||
// Receive multiple bytes.
|
||||
// Replace this function if your board has multiple byte receive.
|
||||
uint8_t receive(uint8_t* buf, size_t count) {
|
||||
|
|
@ -41,9 +35,7 @@ class MySpiClass : public SdSpiBaseClass {
|
|||
return 0;
|
||||
}
|
||||
// Send a byte.
|
||||
void send(uint8_t data) {
|
||||
SPI.transfer(data);
|
||||
}
|
||||
void send(uint8_t data) { SPI.transfer(data); }
|
||||
// Send multiple bytes.
|
||||
// Replace this function if your board has multiple byte send.
|
||||
void send(const uint8_t* buf, size_t count) {
|
||||
|
|
@ -73,9 +65,11 @@ void setup() {
|
|||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
sd.ls(&Serial, LS_SIZE);
|
||||
Serial.println("Done");
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {}
|
||||
#else // SPI_DRIVER_SELECT
|
||||
#error SPI_DRIVER_SELECT must be three in SdFat/SdFatConfig.h
|
||||
#endif // SPI_DRIVER_SELECT
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* This program is a simple binary write/read benchmark.
|
||||
*/
|
||||
#include "FreeStack.h"
|
||||
#include "SdFat.h"
|
||||
#include "sdios.h"
|
||||
#include "FreeStack.h"
|
||||
|
||||
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
|
||||
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -30,7 +30,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -58,10 +58,10 @@ const uint8_t READ_COUNT = 2;
|
|||
// End of configuration constants.
|
||||
//------------------------------------------------------------------------------
|
||||
// File size in bytes.
|
||||
const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;
|
||||
const uint32_t FILE_SIZE = 1000000UL * FILE_SIZE_MB;
|
||||
|
||||
// Insure 4-byte alignment.
|
||||
uint32_t buf32[(BUF_SIZE + 3)/4];
|
||||
uint32_t buf32[(BUF_SIZE + 3) / 4];
|
||||
uint8_t* buf = (uint8_t*)buf32;
|
||||
|
||||
#if SD_FAT_TYPE == 0
|
||||
|
|
@ -125,8 +125,8 @@ void setup() {
|
|||
cout << F("\nUse a freshly formatted SD for best performance.\n");
|
||||
if (!ENABLE_DEDICATED_SPI) {
|
||||
cout << F(
|
||||
"\nSet ENABLE_DEDICATED_SPI nonzero in\n"
|
||||
"SdFatConfig.h for best SPI performance.\n");
|
||||
"\nSet ENABLE_DEDICATED_SPI nonzero in\n"
|
||||
"SdFatConfig.h for best SPI performance.\n");
|
||||
}
|
||||
// use uppercase in hex and use 0X base prefix
|
||||
cout << uppercase << showbase << endl;
|
||||
|
|
@ -161,7 +161,7 @@ void loop() {
|
|||
cout << F("Type is FAT") << int(sd.fatType()) << endl;
|
||||
}
|
||||
|
||||
cout << F("Card size: ") << sd.card()->sectorCount()*512E-9;
|
||||
cout << F("Card size: ") << sd.card()->sectorCount() * 512E-9;
|
||||
cout << F(" GB (GB = 1E9 bytes)") << endl;
|
||||
|
||||
cidDmp();
|
||||
|
|
@ -176,17 +176,17 @@ void loop() {
|
|||
for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
|
||||
buf[i] = 'A' + (i % 26);
|
||||
}
|
||||
buf[BUF_SIZE-2] = '\r';
|
||||
buf[BUF_SIZE - 2] = '\r';
|
||||
}
|
||||
buf[BUF_SIZE-1] = '\n';
|
||||
buf[BUF_SIZE - 1] = '\n';
|
||||
|
||||
cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl;
|
||||
cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
|
||||
cout << F("Starting write test, please wait.") << endl << endl;
|
||||
|
||||
// do write test
|
||||
uint32_t n = FILE_SIZE/BUF_SIZE;
|
||||
cout <<F("write speed and latency") << endl;
|
||||
uint32_t n = FILE_SIZE / BUF_SIZE;
|
||||
cout << F("write speed and latency") << endl;
|
||||
cout << F("speed,max,min,avg") << endl;
|
||||
cout << F("KB/Sec,usec,usec,usec") << endl;
|
||||
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
|
||||
|
|
@ -223,11 +223,11 @@ void loop() {
|
|||
file.sync();
|
||||
t = millis() - t;
|
||||
s = file.fileSize();
|
||||
cout << s/t <<',' << maxLatency << ',' << minLatency;
|
||||
cout << ',' << totalLatency/n << endl;
|
||||
cout << s / t << ',' << maxLatency << ',' << minLatency;
|
||||
cout << ',' << totalLatency / n << endl;
|
||||
}
|
||||
cout << endl << F("Starting read test, please wait.") << endl;
|
||||
cout << endl <<F("read speed and latency") << endl;
|
||||
cout << endl << F("read speed and latency") << endl;
|
||||
cout << F("speed,max,min,avg") << endl;
|
||||
cout << F("KB/Sec,usec,usec,usec") << endl;
|
||||
|
||||
|
|
@ -240,7 +240,7 @@ void loop() {
|
|||
skipLatency = SKIP_FIRST_LATENCY;
|
||||
t = millis();
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
buf[BUF_SIZE-1] = 0;
|
||||
buf[BUF_SIZE - 1] = 0;
|
||||
uint32_t m = micros();
|
||||
int32_t nr = file.read(buf, BUF_SIZE);
|
||||
if (nr != BUF_SIZE) {
|
||||
|
|
@ -248,8 +248,7 @@ void loop() {
|
|||
}
|
||||
m = micros() - m;
|
||||
totalLatency += m;
|
||||
if (buf[BUF_SIZE-1] != '\n') {
|
||||
|
||||
if (buf[BUF_SIZE - 1] != '\n') {
|
||||
error("data check error");
|
||||
}
|
||||
if (skipLatency) {
|
||||
|
|
@ -265,8 +264,8 @@ void loop() {
|
|||
}
|
||||
s = file.fileSize();
|
||||
t = millis() - t;
|
||||
cout << s/t <<',' << maxLatency << ',' << minLatency;
|
||||
cout << ',' << totalLatency/n << endl;
|
||||
cout << s / t << ',' << maxLatency << ',' << minLatency;
|
||||
cout << ',' << totalLatency / n << endl;
|
||||
}
|
||||
cout << endl << F("Done") << endl;
|
||||
file.close();
|
||||
|
|
|
|||
119
examples/debug/CardBusyTest/CardBusyTest.ino
Normal file
119
examples/debug/CardBusyTest/CardBusyTest.ino
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#include "SdFat.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
const uint32_t FILE_SIZE_MiB = 10UL;
|
||||
#else // __AVR__
|
||||
const uint32_t FILE_SIZE_MiB = 100UL;
|
||||
#endif
|
||||
|
||||
bool waitBusy = true;
|
||||
|
||||
#define SD_CONFIG SdSpiConfig(SS, DEDICATED_SPI)
|
||||
//#define SD_CONFIG SdSpiConfig(SS, SHARED_SPI)
|
||||
// Config for Teensy 3.5/3.6 buit-in SD.
|
||||
//#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, DEDICATED_SPI)
|
||||
//#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const uint64_t FILE_SIZE = (uint64_t)FILE_SIZE_MiB << 20;
|
||||
|
||||
SdFs sd;
|
||||
FsFile file;
|
||||
|
||||
uint8_t buf[512];
|
||||
|
||||
#define error(s) sd.errorHalt(&Serial, F(s))
|
||||
//------------------------------------------------------------------------------
|
||||
void clearSerialInput() {
|
||||
uint32_t m = micros();
|
||||
do {
|
||||
if (Serial.read() >= 0) {
|
||||
m = micros();
|
||||
}
|
||||
} while (micros() - m < 10000);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// Wait for USB Serial
|
||||
while (!Serial) {
|
||||
yield();
|
||||
}
|
||||
delay(1000);
|
||||
//------------------------------------------------------------------------------
|
||||
}
|
||||
void loop() {
|
||||
clearSerialInput();
|
||||
Serial.println(F("\nType any character to start\n"));
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
// Initialize the SD card.
|
||||
if (!sd.begin(SD_CONFIG)) {
|
||||
sd.initErrorHalt();
|
||||
}
|
||||
if (!file.open("SdBusyTest.bin", O_RDWR | O_CREAT |O_TRUNC)) {
|
||||
error("file open failed");
|
||||
}
|
||||
if (!file.preAllocate(FILE_SIZE)) {
|
||||
error("preallocate failed");
|
||||
}
|
||||
Serial.print(F("Starting write of "));
|
||||
Serial.print(FILE_SIZE_MiB);
|
||||
Serial.println(F(" MiB."));
|
||||
uint32_t maxWrite = 0;
|
||||
uint32_t minWrite = 99999999;
|
||||
uint32_t ms = millis();
|
||||
uint32_t maxBusy = 0;
|
||||
uint32_t minBusy = UINT32_MAX;
|
||||
|
||||
// Write a dummy sector to start a multi-sector write.
|
||||
if(file.write(buf, sizeof(buf)) != sizeof(buf)) {
|
||||
error("write failed for first sector");
|
||||
}
|
||||
|
||||
while (file.position() < FILE_SIZE) {
|
||||
uint32_t m = micros();
|
||||
if (waitBusy) {
|
||||
m = micros();
|
||||
while (sd.card()->isBusy()) {}
|
||||
m = micros() - m;
|
||||
if (m < minBusy) {
|
||||
minBusy = m;
|
||||
}
|
||||
if (m > maxBusy) {
|
||||
maxBusy = m;
|
||||
}
|
||||
}
|
||||
m = micros();
|
||||
if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
|
||||
error("write failed");
|
||||
}
|
||||
m = micros() - m;
|
||||
if (m < minWrite) {
|
||||
minWrite = m;
|
||||
}
|
||||
if (m > maxWrite) {
|
||||
maxWrite = m;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
ms = millis() - ms;
|
||||
Serial.println(F("\nTimes in micros"));
|
||||
if (waitBusy) {
|
||||
Serial.print(F("minBusy: "));
|
||||
Serial.println(minBusy);
|
||||
Serial.print(F("maxBusy: "));
|
||||
Serial.println(maxBusy);
|
||||
}
|
||||
Serial.print(F("minWrite: "));
|
||||
Serial.println(minWrite);
|
||||
Serial.print(F("maxWrite: "));
|
||||
Serial.println(maxWrite);
|
||||
Serial.print(1e-3*ms);
|
||||
Serial.println(F(" Seconds"));
|
||||
Serial.print(1.0*FILE_SIZE/ms);
|
||||
Serial.println(F(" KB/sec"));
|
||||
|
||||
}
|
||||
51
examples/debug/ExFatDbgDmp/ExFatDbgDmp.ino
Normal file
51
examples/debug/ExFatDbgDmp/ExFatDbgDmp.ino
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include "SdFat.h"
|
||||
#define DUMP_RAW 0
|
||||
#define DUMP_UPCASE 0
|
||||
const uint8_t CS_PIN = SS;
|
||||
//#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#define SD_CONFIG SdSpiConfig(CS_PIN)
|
||||
|
||||
SdExFat sd;
|
||||
#define error(s) sd.errorHalt(&Serial, F(s))
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {
|
||||
yield();
|
||||
}
|
||||
Serial.println(F("Type any character to begin"));
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
if (!sd.begin(SD_CONFIG)){
|
||||
error("begin failed");
|
||||
}
|
||||
#if DUMP_RAW
|
||||
sd.dmpSector(&Serial, 0);
|
||||
for (uint8_t i = 0; i < 24; i++) {
|
||||
sd.dmpSector(&Serial, 0X8000 + i);
|
||||
Serial.println();
|
||||
}
|
||||
return;
|
||||
#endif // DUMP_RAW
|
||||
ExFatFile root;
|
||||
if (!root.openRoot(&sd)) {
|
||||
error("openRoot failed");
|
||||
}
|
||||
sd.printDir(&Serial, &root);
|
||||
// startSector = 0, sectorCount = 1.
|
||||
sd.dmpFat(&Serial, 0, 1);
|
||||
sd.dmpBitmap(&Serial);
|
||||
sd.printVolInfo(&Serial);
|
||||
|
||||
sd.checkUpcase(&Serial);
|
||||
#if DUMP_UPCASE
|
||||
sd.printUpcase(&Serial);
|
||||
#endif // DUMP_UPCASE
|
||||
// sd.dmpCluster(&Serial, 8, 0, 4);
|
||||
Serial.println("Done");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
|
||||
}
|
||||
43
examples/debug/TestGetName/TestGetName.ino
Normal file
43
examples/debug/TestGetName/TestGetName.ino
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include "SdFat.h"
|
||||
SdFs sd;
|
||||
FsFile file;
|
||||
const char* name[] = {
|
||||
"SFN.TXT",
|
||||
"LongFilename.txt",
|
||||
#if USE_UTF8_LONG_NAMES
|
||||
u8"très élégant.txt",
|
||||
#endif // USE_UTF8_LONG_NAMES
|
||||
nullptr};
|
||||
char buf[32];
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
Serial.println("Type any character to begin");
|
||||
while (!Serial.available()) {}
|
||||
if (!sd.begin(SS)) {
|
||||
sd.initErrorHalt();
|
||||
}
|
||||
for (uint8_t i = 0; name[i]; i++) {
|
||||
if (!file.open(name[i], O_CREAT |O_RDWR)) {
|
||||
sd.errorHalt("open");
|
||||
}
|
||||
size_t len = strlen(name[i]);
|
||||
size_t rtn = file.getName(buf, len);
|
||||
if (rtn != 0) {
|
||||
Serial.println("fail len");
|
||||
}
|
||||
rtn = file.getName(buf, len + 1);
|
||||
if (rtn != len) {
|
||||
Serial.println("fail len + 1");
|
||||
}
|
||||
Serial.print(rtn);
|
||||
Serial.print(' ');
|
||||
Serial.println(buf);
|
||||
if (!file.remove()) {
|
||||
sd.errorHalt("remove");
|
||||
}
|
||||
}
|
||||
Serial.println("Done");
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
140
examples/debug/TestMkdir/TestMkdir.ino
Normal file
140
examples/debug/TestMkdir/TestMkdir.ino
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* This sketch is a test of subdirectory and file creation.
|
||||
* It also tests allocation of clusters to directories.
|
||||
*
|
||||
* It will create two subdirectories and create enough files
|
||||
* to force the allocation of a cluster to each directory.
|
||||
*
|
||||
* More than 3000 files may be created on a FAT32 volume.
|
||||
*
|
||||
* Note: Some cards may 'stutter' others just get slow due
|
||||
* to the number of flash erases this program causes.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
|
||||
const uint8_t SD_CHIP_SELECT = SS;
|
||||
|
||||
SdFat sd;
|
||||
typedef File file_t;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) sd.errorHalt(&Serial, F(s))
|
||||
|
||||
/*
|
||||
* create enough files to force a cluster to be allocated to dir.
|
||||
*/
|
||||
void dirAllocTest(file_t* dir) {
|
||||
char buf[32], name[32];
|
||||
file_t file;
|
||||
uint16_t n;
|
||||
uint32_t size = dir->dirSize();
|
||||
|
||||
// create files and write name to file
|
||||
for (n = 0; ; n++){
|
||||
// make file name
|
||||
sprintf(name, "%u.TXT", n);
|
||||
|
||||
// open start time
|
||||
uint32_t t0 = millis();
|
||||
if (!file.open(dir, name, O_WRONLY | O_CREAT | O_EXCL)) {
|
||||
error("open for write failed");
|
||||
}
|
||||
|
||||
// open end time and write start time
|
||||
uint32_t t1 = millis();
|
||||
// write file name to file
|
||||
file.print(name);
|
||||
if (!file.close()) error("close write");
|
||||
|
||||
// write end time
|
||||
uint32_t t2 = millis();
|
||||
Serial.print(F("WR "));
|
||||
Serial.print(n);
|
||||
Serial.write(' ');
|
||||
|
||||
// print time to create file
|
||||
Serial.print(t1 - t0);
|
||||
Serial.write(' ');
|
||||
|
||||
// print time to write file
|
||||
Serial.println(t2 - t1);
|
||||
|
||||
// directory size will change when a cluster is added
|
||||
if (dir->curPosition() > size) break;
|
||||
}
|
||||
|
||||
// read files and check content
|
||||
for (uint16_t i = 0; i <= n; i++) {
|
||||
sprintf(name, "%u.TXT", i);
|
||||
|
||||
// open start time
|
||||
uint32_t t0 = millis();
|
||||
if (!file.open(dir, name, O_RDONLY)) {
|
||||
error("open for read failed");
|
||||
}
|
||||
|
||||
// open end time and read start time
|
||||
uint32_t t1 = millis();
|
||||
int16_t nr = file.read(buf, sizeof(buf));
|
||||
if (nr < 5) error("file.read failed");
|
||||
|
||||
// read end time
|
||||
uint32_t t2 = millis();
|
||||
|
||||
// check file content
|
||||
if (strlen(name) != (size_t)nr || strncmp(name, buf, nr)) {
|
||||
error("content compare failed");
|
||||
}
|
||||
if (!file.close()) error("close read failed");
|
||||
|
||||
Serial.print(F("RD "));
|
||||
Serial.print(i);
|
||||
Serial.write(' ');
|
||||
|
||||
// print open time
|
||||
Serial.print(t1 - t0);
|
||||
Serial.write(' ');
|
||||
|
||||
// print read time
|
||||
Serial.println(t2 - t1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
file_t root;
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {} // wait for Leonardo
|
||||
Serial.println(F("Type any character to start"));
|
||||
while (Serial.read() <= 0) {}
|
||||
delay(200); // Catch Due reset problem
|
||||
|
||||
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||
// try lower speed if bus errors occur.
|
||||
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
root.openRoot(&sd);
|
||||
uint32_t m = millis();
|
||||
// write files to root if not FAT16
|
||||
if (sd.fatType() != 16) {
|
||||
Serial.println(F("Writing files to root"));
|
||||
dirAllocTest(&root);
|
||||
}
|
||||
|
||||
// create sub1 and write files
|
||||
file_t sub1;
|
||||
if (!sub1.mkdir(&root, "SUB1")) error("makdeDir SUB1 failed");
|
||||
Serial.println(F("Writing files to SUB1"));
|
||||
dirAllocTest(&sub1);
|
||||
|
||||
// create sub2 and write files
|
||||
file_t sub2;
|
||||
if (!sub2.mkdir(&sub1, "SUB2")) error("mkdir SUB2 failed");
|
||||
Serial.println(F("Writing files to SUB2"));
|
||||
dirAllocTest(&sub2);
|
||||
m = millis() - m;
|
||||
Serial.print(F("Done millis: "));
|
||||
Serial.println(m);
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
99
examples/debug/TestRmdir/TestRmdir.ino
Normal file
99
examples/debug/TestRmdir/TestRmdir.ino
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* This sketch will remove the files and directories
|
||||
* created by the SdFatMakeDir.pde sketch.
|
||||
*
|
||||
* Performance is erratic due to the large number
|
||||
* of flash erase operations caused by many random
|
||||
* writes to file structures.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
|
||||
const uint8_t SD_CHIP_SELECT = SS;
|
||||
|
||||
SdFat sd;
|
||||
typedef File file_t;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) sd.errorHalt(&Serial, F(s))
|
||||
|
||||
/*
|
||||
* remove all files in dir.
|
||||
*/
|
||||
void deleteFiles(FatFile* dir) {
|
||||
char name[32];
|
||||
file_t file;
|
||||
|
||||
// open and delete files
|
||||
for (uint16_t n = 0; ; n++){
|
||||
sprintf(name, "%u.TXT", n);
|
||||
|
||||
// open start time
|
||||
uint32_t t0 = millis();
|
||||
|
||||
// assume done if open fails
|
||||
if (!file.open(dir, name, O_WRONLY)) return;
|
||||
|
||||
// open end time and remove start time
|
||||
uint32_t t1 = millis();
|
||||
if (!file.remove()) error("file.remove failed");
|
||||
|
||||
// remove end time
|
||||
uint32_t t2 = millis();
|
||||
|
||||
Serial.print(F("RM "));
|
||||
Serial.print(n);
|
||||
Serial.write(' ');
|
||||
|
||||
// open time
|
||||
Serial.print(t1 - t0);
|
||||
Serial.write(' ');
|
||||
|
||||
// remove time
|
||||
Serial.println(t2 - t1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
file_t root;
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {} // wait for Leonardo
|
||||
Serial.println(F("Type any character to start"));
|
||||
while (Serial.read() <= 0) {}
|
||||
delay(200); // Catch Due reset problem
|
||||
|
||||
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||
// try lower speed if bus errors occur.
|
||||
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
root.openRoot(&sd);
|
||||
// delete files in root if not FAT16.
|
||||
if (sd.fatType() != 16) {
|
||||
Serial.println(F("Remove files in root"));
|
||||
deleteFiles(&root);
|
||||
}
|
||||
|
||||
// open SUB1 and delete files
|
||||
file_t sub1;
|
||||
if (!sub1.open("SUB1", O_RDONLY)) error("open SUB1 failed");
|
||||
Serial.println(F("Remove files in SUB1"));
|
||||
deleteFiles(&sub1);
|
||||
|
||||
// open SUB2 and delete files
|
||||
file_t sub2;
|
||||
if (!sub2.open(&sub1, "SUB2", O_RDONLY)) error("open SUB2 failed");
|
||||
Serial.println(F("Remove files in SUB2"));
|
||||
deleteFiles(&sub2);
|
||||
|
||||
// remove SUB2
|
||||
if (!sub2.rmdir()) error("sub2.rmdir failed");
|
||||
Serial.println(F("SUB2 removed"));
|
||||
|
||||
// remove SUB1
|
||||
if (!sub1.rmdir()) error("sub1.rmdir failed");
|
||||
Serial.println(F("SUB1 removed"));
|
||||
|
||||
Serial.println(F("Done"));
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
162
examples/debug/TimestampTest/TimestampTest.ino
Normal file
162
examples/debug/TimestampTest/TimestampTest.ino
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* This program tests the dateTimeCallback() function
|
||||
* and the timestamp() function.
|
||||
*/
|
||||
#include <SPI.h>
|
||||
#include "SdFat.h"
|
||||
#include "sdios.h"
|
||||
SdFs sd;
|
||||
|
||||
FsFile file;
|
||||
|
||||
// Default SD chip select is SS pin
|
||||
const uint8_t chipSelect = SS;
|
||||
|
||||
// create Serial stream
|
||||
ArduinoOutStream cout(Serial);
|
||||
//------------------------------------------------------------------------------
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) sd.errorHalt(F(s))
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* date/time values for debug
|
||||
* normally supplied by a real-time clock or GPS
|
||||
*/
|
||||
// date 1-Oct-21
|
||||
uint16_t year = 2021;
|
||||
uint8_t month = 10;
|
||||
uint8_t day = 1;
|
||||
|
||||
// time 20:30:40
|
||||
uint8_t hour = 20;
|
||||
uint8_t minute = 30;
|
||||
uint8_t second = 40;
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* User provided date time callback function.
|
||||
* See SdFile::dateTimeCallback() for usage.
|
||||
*/
|
||||
void dateTime(uint16_t* date, uint16_t* time) {
|
||||
// User gets date and time from GPS or real-time
|
||||
// clock in real callback function
|
||||
|
||||
// return date using FAT_DATE macro to format fields
|
||||
*date = FAT_DATE(year, month, day);
|
||||
|
||||
// return time using FAT_TIME macro to format fields
|
||||
*time = FAT_TIME(hour, minute, second);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* Function to print all timestamps.
|
||||
*/
|
||||
void printTimestamps(FsFile& f) {
|
||||
cout << F("Creation: ");
|
||||
f.printCreateDateTime(&Serial);
|
||||
cout << endl << F("Modify: ");
|
||||
f.printModifyDateTime(&Serial);
|
||||
cout << endl << F("Access: ");
|
||||
f.printAccessDateTime(&Serial);
|
||||
cout << endl;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
// Wait for USB Serial
|
||||
while (!Serial) {
|
||||
yield();
|
||||
}
|
||||
cout << F("Type any character to start\n");
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
// Initialize at the highest speed supported by the board that is
|
||||
// not over 50 MHz. Try a lower speed if SPI errors occur.
|
||||
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
|
||||
sd.initErrorHalt();
|
||||
}
|
||||
|
||||
// remove files if they exist
|
||||
sd.remove("callback.txt");
|
||||
sd.remove("default.txt");
|
||||
sd.remove("stamp.txt");
|
||||
|
||||
// create a new file with default timestamps
|
||||
if (!file.open("default.txt", O_WRONLY | O_CREAT)) {
|
||||
error("open default.txt failed");
|
||||
}
|
||||
cout << F("\nOpen with default times\n");
|
||||
printTimestamps(file);
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
/*
|
||||
* Test the date time callback function.
|
||||
*
|
||||
* dateTimeCallback() sets the function
|
||||
* that is called when a file is created
|
||||
* or when a file's directory entry is
|
||||
* modified by sync().
|
||||
*
|
||||
* The callback can be disabled by the call
|
||||
* SdFile::dateTimeCallbackCancel()
|
||||
*/
|
||||
// set date time callback function
|
||||
SdFile::dateTimeCallback(dateTime);
|
||||
|
||||
// create a new file with callback timestamps
|
||||
if (!file.open("callback.txt", O_WRONLY | O_CREAT)) {
|
||||
error("open callback.txt failed");
|
||||
}
|
||||
cout << ("\nOpen with callback times\n");
|
||||
printTimestamps(file);
|
||||
|
||||
// change call back date
|
||||
day += 1;
|
||||
|
||||
// must add two to see change since FAT second field is 5-bits
|
||||
second += 2;
|
||||
|
||||
// modify file by writing a byte
|
||||
file.write('t');
|
||||
|
||||
// force dir update
|
||||
file.sync();
|
||||
|
||||
cout << F("\nTimes after write\n");
|
||||
printTimestamps(file);
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
/*
|
||||
* Test timestamp() function
|
||||
*
|
||||
* Cancel callback so sync will not
|
||||
* change access/modify timestamp
|
||||
*/
|
||||
SdFile::dateTimeCallbackCancel();
|
||||
|
||||
// create a new file with default timestamps
|
||||
if (!file.open("stamp.txt", O_WRONLY | O_CREAT)) {
|
||||
error("open stamp.txt failed");
|
||||
}
|
||||
// set creation date time
|
||||
if (!file.timestamp(T_CREATE, 2021, 11, 10, 1, 2, 3)) {
|
||||
error("set create time failed");
|
||||
}
|
||||
// set write/modification date time
|
||||
if (!file.timestamp(T_WRITE, 2021, 11, 11, 4, 5, 6)) {
|
||||
error("set write time failed");
|
||||
}
|
||||
// set access date
|
||||
if (!file.timestamp(T_ACCESS, 2021, 11, 12, 7, 8, 9)) {
|
||||
error("set access time failed");
|
||||
}
|
||||
cout << F("\nTimes after timestamp() calls\n");
|
||||
printTimestamps(file);
|
||||
|
||||
file.close();
|
||||
cout << F("\nDone\n");
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#ifdef __AVR__
|
||||
#include <SPI.h>
|
||||
#include "SdFat.h"
|
||||
#include "sdios.h"
|
||||
#include "FreeStack.h"
|
||||
#include "AnalogBinLogger.h"
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -648,7 +649,7 @@ void logData() {
|
|||
bgnErase = endErase + 1;
|
||||
}
|
||||
// Start a multiple block write.
|
||||
if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
|
||||
if (!sd.card()->writeStart(bgnBlock)) {
|
||||
error("writeBegin failed");
|
||||
}
|
||||
// Write metadata.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
|
@ -31,7 +31,7 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
|||
// Try to select the best SD card configuration.
|
||||
#if HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
|
||||
|
|
@ -80,8 +80,7 @@ void setup() {
|
|||
// Remove file/dirs from previous run.
|
||||
if (sd.exists("dir2/DIR3/NAME3.txt")) {
|
||||
cout << F("Removing /dir2/DIR3/NAME3.txt") << endl;
|
||||
if (!sd.remove("dir2/DIR3/NAME3.txt") ||
|
||||
!sd.rmdir("dir2/DIR3/") ||
|
||||
if (!sd.remove("dir2/DIR3/NAME3.txt") || !sd.rmdir("dir2/DIR3/") ||
|
||||
!sd.rmdir("dir2/")) {
|
||||
error("remove/rmdir failed");
|
||||
}
|
||||
|
|
|
|||
567
extras/AvrPrintStimmer.cpp
Normal file
567
extras/AvrPrintStimmer.cpp
Normal file
|
|
@ -0,0 +1,567 @@
|
|||
/*
|
||||
Print.cpp - Base class that provides print() and println()
|
||||
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||
many modifications, by Paul Stoffregen <paul@pjrc.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Modified 23 November 2006 by David A. Mellis
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "Arduino.h" // (was wiring.h)
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#else
|
||||
void Print::write(const char *str)
|
||||
{
|
||||
write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (size--) count += write(*buffer++);
|
||||
return count;
|
||||
}
|
||||
#else
|
||||
void Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
while (size--) write(*buffer++);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::print(const String &s)
|
||||
{
|
||||
uint8_t buffer[33];
|
||||
size_t count = 0;
|
||||
unsigned int index = 0;
|
||||
unsigned int len = s.length();
|
||||
while (len > 0) {
|
||||
s.getBytes(buffer, sizeof(buffer), index);
|
||||
unsigned int nbytes = len;
|
||||
if (nbytes > sizeof(buffer)-1) nbytes = sizeof(buffer)-1;
|
||||
index += nbytes;
|
||||
len -= nbytes;
|
||||
count += write(buffer, nbytes);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#else
|
||||
void Print::print(const String &s)
|
||||
{
|
||||
unsigned int len = s.length();
|
||||
for (unsigned int i=0; i < len; i++) {
|
||||
write(s[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::print(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
uint8_t buffer[32];
|
||||
size_t count = 0;
|
||||
const char PROGMEM *p = (const char PROGMEM *)ifsh;
|
||||
unsigned int len = strlen_P(p);
|
||||
while (len > 0) {
|
||||
unsigned int nbytes = len;
|
||||
if (nbytes > sizeof(buffer)) nbytes = sizeof(buffer);
|
||||
memcpy_P(buffer, p, nbytes);
|
||||
p += nbytes;
|
||||
len -= nbytes;
|
||||
count += write(buffer, nbytes);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#else
|
||||
void Print::print(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
const char PROGMEM *p = (const char PROGMEM *)ifsh;
|
||||
while (1) {
|
||||
unsigned char c = pgm_read_byte(p++);
|
||||
if (c == 0) return;
|
||||
write(c);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::print(long n)
|
||||
{
|
||||
uint8_t sign=0;
|
||||
|
||||
if (n < 0) {
|
||||
sign = 1;
|
||||
n = -n;
|
||||
}
|
||||
return printNumber(n, sign, 10);
|
||||
}
|
||||
#else
|
||||
void Print::print(long n)
|
||||
{
|
||||
uint8_t sign=0;
|
||||
|
||||
if (n < 0) {
|
||||
sign = 1;
|
||||
n = -n;
|
||||
}
|
||||
printNumber(n, sign, 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::println(void)
|
||||
{
|
||||
uint8_t buf[2]={'\r', '\n'};
|
||||
return write(buf, 2);
|
||||
}
|
||||
#else
|
||||
void Print::println(void)
|
||||
{
|
||||
uint8_t buf[2]={'\r', '\n'};
|
||||
write(buf, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//#define USE_HACKER_DELIGHT_OPTIMIZATION
|
||||
#define USE_STIMMER_OPTIMIZATION
|
||||
#define USE_BENCHMARK_CODE
|
||||
|
||||
|
||||
#ifdef USE_HACKER_DELIGHT_OPTIMIZATION
|
||||
// Adapted from Hacker's Delight (Henry Warren, ISBN 0321842685) www.hackersdelight.org
|
||||
// by Rob Tillaart, Tom Carpenter, "genom2" with input from others...
|
||||
// http://forum.arduino.cc/index.php?topic=167414.0
|
||||
//
|
||||
#define divmod10_asm(in32, tmp32, mod8) \
|
||||
asm volatile ( \
|
||||
"mov %2, %A0 \n\t" /* mod = in */ \
|
||||
"ori %A0, 1 \n\t" /* q = in | 1 */ \
|
||||
"movw %A1, %A0 \n\t" /* x = q */ \
|
||||
"movw %C1, %C0 \n\t" \
|
||||
"lsr %D1 \n\t" /* x = x >> 2 */ \
|
||||
"ror %C1 \n\t" \
|
||||
"ror %B1 \n\t" \
|
||||
"ror %A1 \n\t" \
|
||||
"lsr %D1 \n\t" \
|
||||
"ror %C1 \n\t" \
|
||||
"ror %B1 \n\t" \
|
||||
"ror %A1 \n\t" \
|
||||
"sub %A0, %A1 \n\t" /* q = q - x */ \
|
||||
"sbc %B0, %B1 \n\t" \
|
||||
"sbc %C0, %C1 \n\t" \
|
||||
"sbc %D0, %D1 \n\t" \
|
||||
"movw %A1, %A0 \n\t" /* x = q */ \
|
||||
"movw %C1, %C0 \n\t" \
|
||||
"lsr %D1 \n\t" /* x = x >> 4 */ \
|
||||
"ror %C1 \n\t" \
|
||||
"ror %B1 \n\t" \
|
||||
"ror %A1 \n\t" \
|
||||
"lsr %D1 \n\t" \
|
||||
"ror %C1 \n\t" \
|
||||
"ror %B1 \n\t" \
|
||||
"ror %A1 \n\t" \
|
||||
"lsr %D1 \n\t" \
|
||||
"ror %C1 \n\t" \
|
||||
"ror %B1 \n\t" \
|
||||
"ror %A1 \n\t" \
|
||||
"lsr %D1 \n\t" \
|
||||
"ror %C1 \n\t" \
|
||||
"ror %B1 \n\t" \
|
||||
"ror %A1 \n\t" \
|
||||
"add %A1, %A0 \n\t" /* x = x + q */ \
|
||||
"adc %B1, %B0 \n\t" \
|
||||
"adc %C1, %C0 \n\t" \
|
||||
"adc %D1, %D0 \n\t" \
|
||||
"movw %A0, %A1 \n\t" /* q = x */ \
|
||||
"movw %C0, %C1 \n\t" \
|
||||
"add %A0, %B1 \n\t" /* q = q + (x >> 8) */ \
|
||||
"adc %B0, %C1 \n\t" \
|
||||
"adc %C0, %D1 \n\t" \
|
||||
"adc %D0, r1 \n\t" \
|
||||
"mov %A0, %B0 \n\t" /* q = q >> 8 */ \
|
||||
"mov %B0, %C0 \n\t" \
|
||||
"mov %C0, %D0 \n\t" \
|
||||
"eor %D0, %D0 \n\t" \
|
||||
"add %A0, %A1 \n\t" /* q = q + x */ \
|
||||
"adc %B0, %B1 \n\t" \
|
||||
"adc %C0, %C1 \n\t" \
|
||||
"adc %D0, %D1 \n\t" \
|
||||
"mov %A0, %B0 \n\t" /* q = q >> 8 */ \
|
||||
"mov %B0, %C0 \n\t" \
|
||||
"mov %C0, %D0 \n\t" \
|
||||
"eor %D0, %D0 \n\t" \
|
||||
"add %A0, %A1 \n\t" /* q = q + x */ \
|
||||
"adc %B0, %B1 \n\t" \
|
||||
"adc %C0, %C1 \n\t" \
|
||||
"adc %D0, %D1 \n\t" \
|
||||
"mov %A0, %B0 \n\t" /* q = q >> 8 */ \
|
||||
"mov %B0, %C0 \n\t" \
|
||||
"mov %C0, %D0 \n\t" \
|
||||
"eor %D0, %D0 \n\t" \
|
||||
"add %A0, %A1 \n\t" /* q = q + x */ \
|
||||
"adc %B0, %B1 \n\t" \
|
||||
"adc %C0, %C1 \n\t" \
|
||||
"adc %D0, %D1 \n\t" \
|
||||
"andi %A0, 0xF8 \n\t" /* q = q & ~0x7 */ \
|
||||
"sub %2, %A0 \n\t" /* mod = mod - q */ \
|
||||
"lsr %D0 \n\t" /* q = q >> 2 */ \
|
||||
"ror %C0 \n\t" \
|
||||
"ror %B0 \n\t" \
|
||||
"ror %A0 \n\t" \
|
||||
"lsr %D0 \n\t" \
|
||||
"ror %C0 \n\t" \
|
||||
"ror %B0 \n\t" \
|
||||
"ror %A0 \n\t" \
|
||||
"sub %2, %A0 \n\t" /* mod = mod - q */ \
|
||||
"lsr %D0 \n\t" /* q = q >> 1 */ \
|
||||
"ror %C0 \n\t" \
|
||||
"ror %B0 \n\t" \
|
||||
"ror %A0 \n\t" \
|
||||
: "+d" (in32), "=r" (tmp32), "=r" (mod8) : : "r0" \
|
||||
)
|
||||
#endif // USE_HACKER_DELIGHT_OPTIMIZATION
|
||||
|
||||
#ifdef USE_STIMMER_OPTIMIZATION
|
||||
// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
|
||||
#define divmod10_asm32(in32, mod8, tmp8) \
|
||||
asm volatile ( \
|
||||
" ldi %2,51 \n\t" \
|
||||
" mul %A0,%2 \n\t" \
|
||||
" clr %A0 \n\t" \
|
||||
" add r0,%2 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" mov %1,r0 \n\t" \
|
||||
" mul %B0,%2 \n\t" \
|
||||
" clr %B0 \n\t" \
|
||||
" add %A0,r0 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" mul %C0,%2 \n\t" \
|
||||
" clr %C0 \n\t" \
|
||||
" add %B0,r0 \n\t" \
|
||||
" adc %C0,r1 \n\t" \
|
||||
" mul %D0,%2 \n\t" \
|
||||
" clr %D0 \n\t" \
|
||||
" add %C0,r0 \n\t" \
|
||||
" adc %D0,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
" add %1,%A0 \n\t" \
|
||||
" adc %A0,%B0 \n\t" \
|
||||
" adc %B0,%C0 \n\t" \
|
||||
" adc %C0,%D0 \n\t" \
|
||||
" adc %D0,r1 \n\t" \
|
||||
" add %1,%B0 \n\t" \
|
||||
" adc %A0,%C0 \n\t" \
|
||||
" adc %B0,%D0 \n\t" \
|
||||
" adc %C0,r1 \n\t" \
|
||||
" adc %D0,r1 \n\t" \
|
||||
" add %1,%D0 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" adc %C0,r1 \n\t" \
|
||||
" adc %D0,r1 \n\t" \
|
||||
" lsr %D0 \n\t" \
|
||||
" ror %C0 \n\t" \
|
||||
" ror %B0 \n\t" \
|
||||
" ror %A0 \n\t" \
|
||||
" ror %1 \n\t" \
|
||||
" ldi %2,10 \n\t" \
|
||||
" mul %1,%2 \n\t" \
|
||||
" mov %1,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
:"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
|
||||
|
||||
#define divmod10_asm24(in32, mod8, tmp8) \
|
||||
asm volatile ( \
|
||||
" ldi %2,51 \n\t" \
|
||||
" mul %A0,%2 \n\t" \
|
||||
" clr %A0 \n\t" \
|
||||
" add r0,%2 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" mov %1,r0 \n\t" \
|
||||
" mul %B0,%2 \n\t" \
|
||||
" clr %B0 \n\t" \
|
||||
" add %A0,r0 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" mul %C0,%2 \n\t" \
|
||||
" clr %C0 \n\t" \
|
||||
" add %B0,r0 \n\t" \
|
||||
" adc %C0,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
" add %1,%A0 \n\t" \
|
||||
" adc %A0,%B0 \n\t" \
|
||||
" adc %B0,%C0 \n\t" \
|
||||
" adc %C0,r1 \n\t" \
|
||||
" add %1,%B0 \n\t" \
|
||||
" adc %A0,%C0 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" adc %C0,r1 \n\t" \
|
||||
" lsr %C0 \n\t" \
|
||||
" ror %B0 \n\t" \
|
||||
" ror %A0 \n\t" \
|
||||
" ror %1 \n\t" \
|
||||
" ldi %2,10 \n\t" \
|
||||
" mul %1,%2 \n\t" \
|
||||
" mov %1,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
:"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
|
||||
|
||||
#define divmod10_asm16(in32, mod8, tmp8) \
|
||||
asm volatile ( \
|
||||
" ldi %2,51 \n\t" \
|
||||
" mul %A0,%2 \n\t" \
|
||||
" clr %A0 \n\t" \
|
||||
" add r0,%2 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" mov %1,r0 \n\t" \
|
||||
" mul %B0,%2 \n\t" \
|
||||
" clr %B0 \n\t" \
|
||||
" add %A0,r0 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
" add %1,%A0 \n\t" \
|
||||
" adc %A0,%B0 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" add %1,%B0 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" adc %B0,r1 \n\t" \
|
||||
" lsr %B0 \n\t" \
|
||||
" ror %A0 \n\t" \
|
||||
" ror %1 \n\t" \
|
||||
" ldi %2,10 \n\t" \
|
||||
" mul %1,%2 \n\t" \
|
||||
" mov %1,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
:"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
|
||||
|
||||
#define divmod10_asm8(in32, mod8, tmp8) \
|
||||
asm volatile ( \
|
||||
" ldi %2,51 \n\t" \
|
||||
" mul %A0,%2 \n\t" \
|
||||
" clr %A0 \n\t" \
|
||||
" add r0,%2 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" mov %1,r0 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
" add %1,%A0 \n\t" \
|
||||
" adc %A0,r1 \n\t" \
|
||||
" lsr %A0 \n\t" \
|
||||
" ror %1 \n\t" \
|
||||
" ldi %2,10 \n\t" \
|
||||
" mul %1,%2 \n\t" \
|
||||
" mov %1,r1 \n\t" \
|
||||
" clr r1 \n\t" \
|
||||
:"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
|
||||
#endif // USE_STIMMER_OPTIMIZATION
|
||||
|
||||
|
||||
|
||||
#ifdef USE_BENCHMARK_CODE
|
||||
uint32_t usec_print = 0;
|
||||
#endif
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::printNumberDec(unsigned long n, uint8_t sign)
|
||||
#else
|
||||
void Print::printNumberDec(unsigned long n, uint8_t sign)
|
||||
#endif
|
||||
{
|
||||
uint8_t digit, buf[11], *p;
|
||||
uint32_t tmp32;
|
||||
uint8_t tmp8;
|
||||
|
||||
#ifdef USE_BENCHMARK_CODE
|
||||
uint32_t usec = micros();
|
||||
#endif
|
||||
p = buf + (sizeof(buf)-1);
|
||||
|
||||
#if defined(USE_STIMMER_OPTIMIZATION)
|
||||
|
||||
while(n & 0xff000000){divmod10_asm32(n, digit, tmp8);*--p = digit + '0';}
|
||||
while(n & 0xff0000){divmod10_asm24(n, digit, tmp8);*--p = digit + '0';}
|
||||
while(n & 0xff00){divmod10_asm16(n, digit, tmp8);*--p = digit + '0';}
|
||||
while((n & 0xff)>9){divmod10_asm8(n, digit, tmp8);*--p = digit + '0';}
|
||||
*--p = n + '0';
|
||||
|
||||
#else
|
||||
do {
|
||||
#if defined(USE_HACKER_DELIGHT_OPTIMIZATION)
|
||||
divmod10_asm(n, tmp32, digit);
|
||||
#else
|
||||
tmp32 = n;
|
||||
n = n / 10;
|
||||
digit = tmp32 - n * 10;
|
||||
#endif
|
||||
*--p = digit + '0';
|
||||
} while (n);
|
||||
#endif
|
||||
if (sign) *--p = '-';
|
||||
#ifdef USE_BENCHMARK_CODE
|
||||
usec_print += micros() - usec;
|
||||
#endif
|
||||
#if ARDUINO >= 100
|
||||
return write(p, sizeof(buf)-1 - (p - buf));
|
||||
#else
|
||||
write(p, sizeof(buf)-1 - (p - buf));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::printNumberHex(unsigned long n)
|
||||
#else
|
||||
void Print::printNumberHex(unsigned long n)
|
||||
#endif
|
||||
{
|
||||
uint8_t digit, buf[8], *p;
|
||||
|
||||
p = buf + (sizeof(buf)-1);
|
||||
do {
|
||||
digit = n & 15;
|
||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
|
||||
n >>= 4;
|
||||
} while (n);
|
||||
#if ARDUINO >= 100
|
||||
return write(p, sizeof(buf)-1 - (p - buf));
|
||||
#else
|
||||
write(p, sizeof(buf)-1 - (p - buf));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::printNumberBin(unsigned long n)
|
||||
#else
|
||||
void Print::printNumberBin(unsigned long n)
|
||||
#endif
|
||||
{
|
||||
uint8_t buf[32], *p;
|
||||
|
||||
p = buf + (sizeof(buf)-1);
|
||||
do {
|
||||
*--p = '0' + ((uint8_t)n & 1);
|
||||
n >>= 1;
|
||||
} while (n);
|
||||
#if ARDUINO >= 100
|
||||
return write(p, sizeof(buf)-1 - (p - buf));
|
||||
#else
|
||||
write(p, sizeof(buf)-1 - (p - buf));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::printNumberAny(unsigned long n, uint8_t base)
|
||||
#else
|
||||
void Print::printNumberAny(unsigned long n, uint8_t base)
|
||||
#endif
|
||||
{
|
||||
uint8_t digit, buf[21], *p;
|
||||
uint32_t tmp;
|
||||
//uint32_t usec;
|
||||
|
||||
//usec = micros();
|
||||
p = buf + (sizeof(buf)-1);
|
||||
do {
|
||||
tmp = n;
|
||||
n = n / base;
|
||||
digit = tmp - n * base;
|
||||
*--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
|
||||
} while (n);
|
||||
//usec_print += micros() - usec;
|
||||
#if ARDUINO >= 100
|
||||
return write(p, sizeof(buf)-1 - (p - buf));
|
||||
#else
|
||||
write(p, sizeof(buf)-1 - (p - buf));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#if ARDUINO >= 100
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
#else
|
||||
void Print::printFloat(double number, uint8_t digits)
|
||||
#endif
|
||||
{
|
||||
uint8_t sign=0;
|
||||
#if ARDUINO >= 100
|
||||
size_t count=0;
|
||||
#endif
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0) {
|
||||
sign = 1;
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i) {
|
||||
rounding *= 0.1;
|
||||
}
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
#if ARDUINO >= 100
|
||||
count += printNumber(int_part, sign, 10);
|
||||
#else
|
||||
printNumber(int_part, sign, 10);
|
||||
#endif
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0) {
|
||||
uint8_t n, buf[8], count=1;
|
||||
buf[0] = '.';
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
if (digits > sizeof(buf) - 1) digits = sizeof(buf) - 1;
|
||||
|
||||
while (digits-- > 0) {
|
||||
remainder *= 10.0;
|
||||
n = (uint8_t)(remainder);
|
||||
buf[count++] = '0' + n;
|
||||
remainder -= n;
|
||||
}
|
||||
#if ARDUINO >= 100
|
||||
count += write(buf, count);
|
||||
#else
|
||||
write(buf, count);
|
||||
#endif
|
||||
}
|
||||
#if ARDUINO >= 100
|
||||
return count;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
|
||||
+++ "C:\\Users\\bill\\Documents\\ArduinoSdFat\\libraries\\USB_Host_Shield_2.0/masstorage.cpp" 2020-02-20 06:02:48.567008200 -0800
|
||||
master/masstorage.cpp" 2022-10-18 08:48:03.639503200 -0700
|
||||
@@ -796,6 +796,7 @@
|
||||
buf[i] = 0x00;
|
||||
}
|
||||
|
|
@ -9,3 +7,4 @@
|
|||
uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
|
||||
if(!rc) {
|
||||
WriteOk[lun] = ((buf[2] & 0x80) == 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
This zip file was downloaded on 2/20/2020 from
|
||||
This zip file was downloaded on 10/18/2022 from
|
||||
|
||||
https://github.com/felis/USB_Host_Shield_2.0
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "PrintBasic.h"
|
||||
#if ENABLE_ARDUINO_FEATURES == 0
|
||||
#include <math.h>
|
||||
|
||||
size_t PrintBasic::print(long n, uint8_t base) {
|
||||
|
|
@ -32,14 +33,14 @@ size_t PrintBasic::print(long n, uint8_t base) {
|
|||
return printNum(n, base);
|
||||
}
|
||||
size_t PrintBasic::printNum(unsigned long n, uint8_t base) {
|
||||
const uint8_t DIM = 8*sizeof(long);
|
||||
const uint8_t DIM = 8 * sizeof(long);
|
||||
char buf[DIM];
|
||||
char *str = &buf[DIM];
|
||||
|
||||
if (base < 2) return 0;
|
||||
|
||||
do {
|
||||
char c = n%base;
|
||||
char c = n % base;
|
||||
n /= base;
|
||||
*--str = c + (c < 10 ? '0' : 'A' - 10);
|
||||
} while (n);
|
||||
|
|
@ -66,7 +67,7 @@ size_t PrintBasic::printDouble(double n, uint8_t prec) {
|
|||
}
|
||||
|
||||
double round = 0.5;
|
||||
for (uint8_t i = 0; i < prec; ++i) {
|
||||
for (uint8_t i = 0; i < prec; ++i) {
|
||||
round *= 0.1;
|
||||
}
|
||||
|
||||
|
|
@ -87,3 +88,4 @@ size_t PrintBasic::printDouble(double n, uint8_t prec) {
|
|||
}
|
||||
return rtn;
|
||||
}
|
||||
#endif // ENABLE_ARDUINO_FEATURES == 0
|
||||
|
|
|
|||
|
|
@ -28,18 +28,21 @@
|
|||
* \file
|
||||
* \brief Stream/Print like replacement for non-Arduino systems.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef F
|
||||
#warning F() macro defined for non Arduino System
|
||||
#elif defined(__AVR__)
|
||||
#include "../SdFatConfig.h"
|
||||
|
||||
#ifndef F
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
class __FlashStringHelper;
|
||||
#define F(str) (reinterpret_cast<const __FlashStringHelper *>(PSTR(str)))
|
||||
#else // F
|
||||
#define F(string_literal) \
|
||||
(reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
|
||||
#else // defined(__AVR__)
|
||||
#define F(str) (str)
|
||||
#endif // defined(__AVR__)
|
||||
#endif // F
|
||||
|
||||
#ifdef BIN
|
||||
|
|
@ -54,63 +57,44 @@ class PrintBasic {
|
|||
public:
|
||||
PrintBasic() : m_error(0) {}
|
||||
|
||||
void clearWriteError() {
|
||||
setWriteError(0);
|
||||
}
|
||||
int getWriteError() {
|
||||
return m_error;
|
||||
}
|
||||
size_t print(char c) {
|
||||
return write(c);
|
||||
}
|
||||
size_t print(const char* str) {
|
||||
return write(str);
|
||||
}
|
||||
void clearWriteError() { setWriteError(0); }
|
||||
int getWriteError() { return m_error; }
|
||||
size_t print(char c) { return write(c); }
|
||||
size_t print(const char *str) { return write(str); }
|
||||
size_t print(const __FlashStringHelper *str) {
|
||||
#ifdef __AVR__
|
||||
PGM_P p = reinterpret_cast<PGM_P>(str);
|
||||
size_t n = 0;
|
||||
for (uint8_t c; (c = pgm_read_byte(p + n)) && write(c); n++) {}
|
||||
return n;
|
||||
#else // __AVR__
|
||||
return print(reinterpret_cast<const char *>(str));
|
||||
PGM_P p = reinterpret_cast<PGM_P>(str);
|
||||
size_t n = 0;
|
||||
for (uint8_t c; (c = pgm_read_byte(p + n)) && write(c); n++) {
|
||||
}
|
||||
return n;
|
||||
#else // __AVR__
|
||||
return print(reinterpret_cast<const char *>(str));
|
||||
#endif // __AVR__
|
||||
}
|
||||
size_t println(const __FlashStringHelper *str) {
|
||||
#ifdef __AVR__
|
||||
return print(str) + println();
|
||||
#else // __AVR__
|
||||
#else // __AVR__
|
||||
return println(reinterpret_cast<const char *>(str));
|
||||
#endif // __AVR__
|
||||
}
|
||||
size_t print(double n, uint8_t prec = 2) {
|
||||
return printDouble(n, prec);
|
||||
}
|
||||
size_t print(double n, uint8_t prec = 2) { return printDouble(n, prec); }
|
||||
size_t print(signed char n, uint8_t base = 10) {
|
||||
return print((long)n, base);
|
||||
}
|
||||
size_t print(unsigned char n, uint8_t base = 10) {
|
||||
return print((unsigned long)n, base);
|
||||
}
|
||||
size_t print(int n, uint8_t base = 10) {
|
||||
return print((long)n, base);
|
||||
}
|
||||
size_t print(int n, uint8_t base = 10) { return print((long)n, base); }
|
||||
size_t print(unsigned int n, uint8_t base = 10) {
|
||||
return print((unsigned long)n, base);
|
||||
}
|
||||
size_t print(long n, uint8_t base = 10);
|
||||
size_t print(unsigned long n, uint8_t base = 10) {
|
||||
return printNum(n, base);
|
||||
}
|
||||
size_t println() {
|
||||
return write("\r\n");
|
||||
}
|
||||
size_t println(char c) {
|
||||
return write(c) + println();
|
||||
}
|
||||
size_t println(const char* str) {
|
||||
return print(str) + println();
|
||||
}
|
||||
size_t print(unsigned long n, uint8_t base = 10) { return printNum(n, base); }
|
||||
size_t println() { return write("\r\n"); }
|
||||
size_t println(char c) { return write(c) + println(); }
|
||||
size_t println(const char *str) { return print(str) + println(); }
|
||||
size_t println(double n, uint8_t prec = 2) {
|
||||
return print(n, prec) + println();
|
||||
}
|
||||
|
|
@ -132,12 +116,10 @@ class PrintBasic {
|
|||
size_t println(unsigned long n, uint8_t base = 10) {
|
||||
return print(n, base) + println();
|
||||
}
|
||||
size_t write(const char *str) {
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
size_t write(const char *str) { return write(str, strlen(str)); }
|
||||
virtual size_t write(uint8_t b) = 0;
|
||||
|
||||
virtual size_t write(const uint8_t* buffer, size_t size) {
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (!write(buffer[i])) break;
|
||||
|
|
@ -145,13 +127,11 @@ class PrintBasic {
|
|||
return i;
|
||||
}
|
||||
size_t write(const char *buffer, size_t size) {
|
||||
return write((const uint8_t*)buffer, size);
|
||||
return write(reinterpret_cast<const uint8_t *>(buffer), size);
|
||||
}
|
||||
|
||||
protected:
|
||||
void setWriteError(int err = 1) {
|
||||
m_error = err;
|
||||
}
|
||||
void setWriteError(int err = 1) { m_error = err; }
|
||||
|
||||
private:
|
||||
size_t printDouble(double n, uint8_t prec);
|
||||
|
|
|
|||
2
extras/cpplint.py
vendored
2
extras/cpplint.py
vendored
|
|
@ -67,7 +67,7 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
|
|||
<file> [file] ...
|
||||
|
||||
The style guidelines this tries to follow are those in
|
||||
https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
|
||||
https://google.github.io/styleguide/cppguide.html
|
||||
|
||||
Every problem is given a confidence score from 1-5, with 5 meaning we are
|
||||
certain of the problem, and 1 meaning it could be a legitimate construct.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name=SdFat
|
||||
version=2.2.0
|
||||
version=2.2.2
|
||||
license=MIT
|
||||
author=Bill Greiman <fat16lib@sbcglobal.net>
|
||||
maintainer=Bill Greiman <fat16lib@sbcglobal.net>
|
||||
|
|
|
|||
|
|
@ -28,12 +28,15 @@
|
|||
* \file
|
||||
* \brief Fast buffered print.
|
||||
*/
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#endif // __AVR__
|
||||
#include "common/FmtNumber.h"
|
||||
/**
|
||||
* \class BufferedPrint
|
||||
* \brief Fast buffered print template.
|
||||
*/
|
||||
template<typename WriteClass, uint8_t BUF_DIM>
|
||||
template <typename WriteClass, uint8_t BUF_DIM>
|
||||
class BufferedPrint {
|
||||
public:
|
||||
BufferedPrint() : m_wr(nullptr), m_in(0) {}
|
||||
|
|
@ -49,7 +52,7 @@ class BufferedPrint {
|
|||
m_in = 0;
|
||||
}
|
||||
/** Flush the buffer - same as sync() with no status return. */
|
||||
void flush() {sync();}
|
||||
void flush() { sync(); }
|
||||
/** Print a character followed by a field terminator.
|
||||
* \param[in] c character to print.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
|
|
@ -72,7 +75,7 @@ class BufferedPrint {
|
|||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \return true for success or false if an error occurs.
|
||||
*/
|
||||
size_t printField(const __FlashStringHelper *fsh, char term) {
|
||||
size_t printField(const __FlashStringHelper* fsh, char term) {
|
||||
#ifdef __AVR__
|
||||
size_t rtn = 0;
|
||||
PGM_P p = reinterpret_cast<PGM_P>(fsh);
|
||||
|
|
@ -93,8 +96,8 @@ class BufferedPrint {
|
|||
rtn += write(str, buf + sizeof(buf) - str);
|
||||
}
|
||||
return rtn;
|
||||
#else // __AVR__
|
||||
return printField(reinterpret_cast<const char *>(fsh), term);
|
||||
#else // __AVR__
|
||||
return printField(reinterpret_cast<const char*>(fsh), term);
|
||||
#endif // __AVR__
|
||||
}
|
||||
/** Print a string followed by a field terminator.
|
||||
|
|
@ -139,7 +142,7 @@ class BufferedPrint {
|
|||
* \param[in] prec Number of digits after decimal point.
|
||||
* \return true for success or false if an error occurs.
|
||||
*/
|
||||
size_t printField(float f, char term, uint8_t prec = 2) {
|
||||
size_t printField(float f, char term, uint8_t prec = 2) {
|
||||
return printField(static_cast<double>(f), term, prec);
|
||||
}
|
||||
/** Print an integer value for 8, 16, and 32 bit signed and unsigned types.
|
||||
|
|
@ -147,7 +150,7 @@ class BufferedPrint {
|
|||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \return true for success or false if an error occurs.
|
||||
*/
|
||||
template<typename Type>
|
||||
template <typename Type>
|
||||
size_t printField(Type n, char term) {
|
||||
const uint8_t DIM = sizeof(Type) <= 2 ? 8 : 13;
|
||||
char buf[DIM];
|
||||
|
|
@ -184,9 +187,7 @@ class BufferedPrint {
|
|||
* \param[in] prec Number of digits after decimal point.
|
||||
* \return true for success or false if an error occurs.
|
||||
*/
|
||||
size_t print(double d, uint8_t prec = 2) {
|
||||
return printField(d, 0, prec);
|
||||
}
|
||||
size_t print(double d, uint8_t prec = 2) { return printField(d, 0, prec); }
|
||||
/** Print a double followed by CR LF.
|
||||
* \param[in] d The number to be printed.
|
||||
* \param[in] prec Number of digits after decimal point.
|
||||
|
|
@ -215,7 +216,7 @@ class BufferedPrint {
|
|||
* \param[in] v item to print.
|
||||
* \return true for success or false if an error occurs.
|
||||
*/
|
||||
template<typename Type>
|
||||
template <typename Type>
|
||||
size_t print(Type v) {
|
||||
return printField(v, 0);
|
||||
}
|
||||
|
|
@ -223,7 +224,7 @@ class BufferedPrint {
|
|||
* \param[in] v item to print.
|
||||
* \return true for success or false if an error occurs.
|
||||
*/
|
||||
template<typename Type>
|
||||
template <typename Type>
|
||||
size_t println(Type v) {
|
||||
return printField(v, '\n');
|
||||
}
|
||||
|
|
@ -238,7 +239,7 @@ class BufferedPrint {
|
|||
m_in = 0;
|
||||
return true;
|
||||
}
|
||||
/** Write data to an open file.
|
||||
/** Write data to an open file.
|
||||
* \param[in] src Pointer to the location of the data to be written.
|
||||
*
|
||||
* \param[in] n Number of bytes to write.
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ExFatVolume.h"
|
||||
#include "../common/upcase.h"
|
||||
#include "ExFatLib.h"
|
||||
#include "ExFatVolume.h"
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
//------------------------------------------------------------------------------
|
||||
static void printHex(print_t* pr, uint8_t h);
|
||||
|
|
@ -59,15 +59,15 @@ static uint16_t hashDir(DirName_t* dir, uint16_t hash) {
|
|||
if (!u) {
|
||||
break;
|
||||
}
|
||||
uint16_t c = toUpcase(u);
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF);
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
|
||||
uint16_t c = toUpcase(u);
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF);
|
||||
hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static void printDateTime(print_t* pr,
|
||||
uint32_t timeDate, uint8_t ms, int8_t tz) {
|
||||
static void printDateTime(print_t* pr, uint32_t timeDate, uint8_t ms,
|
||||
int8_t tz) {
|
||||
fsPrintDateTime(pr, timeDate, ms, tz);
|
||||
pr->println();
|
||||
}
|
||||
|
|
@ -93,11 +93,11 @@ static void printDirFile(print_t* pr, DirFile_t* dir) {
|
|||
pr->print(F("attributes: 0x"));
|
||||
pr->println(getLe16(dir->attributes), HEX);
|
||||
pr->print(F("createTime: "));
|
||||
printDateTime(pr, getLe32(dir->createTime),
|
||||
dir->createTimeMs, dir->createTimezone);
|
||||
printDateTime(pr, getLe32(dir->createTime), dir->createTimeMs,
|
||||
dir->createTimezone);
|
||||
pr->print(F("modifyTime: "));
|
||||
printDateTime(pr, getLe32(dir->modifyTime),
|
||||
dir->modifyTimeMs, dir->modifyTimezone);
|
||||
printDateTime(pr, getLe32(dir->modifyTime), dir->modifyTimeMs,
|
||||
dir->modifyTimezone);
|
||||
pr->print(F("accessTime: "));
|
||||
printDateTime(pr, getLe32(dir->accessTime), 0, dir->accessTimezone);
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ static void printDirLabel(print_t* pr, DirLabel_t* dir) {
|
|||
pr->println(dir->labelLength);
|
||||
pr->print(F("unicode: "));
|
||||
for (size_t i = 0; i < dir->labelLength; i++) {
|
||||
pr->write(dir->unicode[2*i]);
|
||||
pr->write(dir->unicode[2 * i]);
|
||||
}
|
||||
pr->println();
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ static void printDirStream(print_t* pr, DirStream_t* dir) {
|
|||
static void printDirUpcase(print_t* pr, DirUpcase_t* dir) {
|
||||
pr->print(F("dirUpcase: 0x"));
|
||||
pr->println(dir->type, HEX);
|
||||
pr->print(F("checksum: 0x"));
|
||||
pr->print(F("checksum: 0x"));
|
||||
pr->println(getLe32(dir->checksum), HEX);
|
||||
pr->print(F("firstCluster: "));
|
||||
pr->println(getLe32(dir->firstCluster));
|
||||
|
|
@ -192,7 +192,7 @@ static void printExFatBoot(print_t* pr, pbs_t* pbs) {
|
|||
pr->print(F("FileSystemRevision: 0x"));
|
||||
pr->println(getLe32(ebs->fileSystemRevision), HEX);
|
||||
pr->print(F("VolumeFlags: 0x"));
|
||||
pr->println(getLe16(ebs->volumeFlags) , HEX);
|
||||
pr->println(getLe16(ebs->volumeFlags), HEX);
|
||||
pr->print(F("BytesPerSectorShift: "));
|
||||
pr->println(ebs->bytesPerSectorShift);
|
||||
pr->print(F("SectorsPerClusterShift: "));
|
||||
|
|
@ -215,7 +215,7 @@ static void printHex(print_t* pr, uint8_t h) {
|
|||
static void printHex(print_t* pr, uint16_t val) {
|
||||
bool space = true;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
uint8_t h = (val >> (12 - 4*i)) & 15;
|
||||
uint8_t h = (val >> (12 - 4 * i)) & 15;
|
||||
if (h || i == 3) {
|
||||
space = false;
|
||||
}
|
||||
|
|
@ -230,7 +230,7 @@ static void printHex(print_t* pr, uint16_t val) {
|
|||
static void printHex(print_t* pr, uint32_t val) {
|
||||
bool space = true;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
uint8_t h = (val >> (28 - 4*i)) & 15;
|
||||
uint8_t h = (val >> (28 - 4 * i)) & 15;
|
||||
if (h || i == 7) {
|
||||
space = false;
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@ static void printHex(print_t* pr, uint32_t val) {
|
|||
//------------------------------------------------------------------------------
|
||||
static void printHex64(print_t* pr, uint64_t n) {
|
||||
char buf[17];
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
char* str = &buf[sizeof(buf) - 1];
|
||||
*str = '\0';
|
||||
do {
|
||||
uint8_t h = n & 15;
|
||||
|
|
@ -256,12 +256,12 @@ static void printHex64(print_t* pr, uint64_t n) {
|
|||
//------------------------------------------------------------------------------
|
||||
static void println64(print_t* pr, uint64_t n) {
|
||||
char buf[21];
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
char* str = &buf[sizeof(buf) - 1];
|
||||
*str = '\0';
|
||||
do {
|
||||
uint64_t m = n;
|
||||
n /= 10;
|
||||
*--str = m - 10*n + '0';
|
||||
*--str = m - 10 * n + '0';
|
||||
} while (n);
|
||||
pr->println(str);
|
||||
}
|
||||
|
|
@ -313,15 +313,15 @@ void ExFatPartition::checkUpcase(print_t* pr) {
|
|||
pr->println(F("upcase not found"));
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < size/2; i++) {
|
||||
if ((i%256) == 0) {
|
||||
for (size_t i = 0; i < size / 2; i++) {
|
||||
if ((i % 256) == 0) {
|
||||
upcase = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
|
||||
if (!upcase) {
|
||||
pr->println(F("read upcase failed"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint16_t v = getLe16(&upcase[2*(i & 0XFF)]);
|
||||
uint16_t v = getLe16(&upcase[2 * (i & 0XFF)]);
|
||||
if (skip) {
|
||||
pr->print("skip ");
|
||||
pr->print(u);
|
||||
|
|
@ -334,7 +334,7 @@ void ExFatPartition::checkUpcase(print_t* pr) {
|
|||
for (uint16_t k = 0; k < v; k++) {
|
||||
uint16_t x = toUpcase(u + k);
|
||||
if (x != (u + k)) {
|
||||
printHex(pr, (uint16_t)(u+k));
|
||||
printHex(pr, (uint16_t)(u + k));
|
||||
pr->write(',');
|
||||
printHex(pr, x);
|
||||
pr->println("<<<<<<<<<<<<<<<<<<<<");
|
||||
|
|
@ -363,8 +363,8 @@ void ExFatPartition::dmpBitmap(print_t* pr) {
|
|||
dmpSector(pr, m_clusterHeapStartSector);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster,
|
||||
uint32_t offset, uint32_t count) {
|
||||
void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster, uint32_t offset,
|
||||
uint32_t count) {
|
||||
uint32_t sector = clusterStartSector(cluster) + offset;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
pr->print(F("\nSector: "));
|
||||
|
|
@ -375,7 +375,7 @@ void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster,
|
|||
//------------------------------------------------------------------------------
|
||||
void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
|
||||
uint32_t sector = m_fatStartSector + start;
|
||||
uint32_t cluster = 128*start;
|
||||
uint32_t cluster = 128 * start;
|
||||
pr->println(F("FAT:"));
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
uint8_t* cache = dataCachePrepare(sector + i, FsCache::CACHE_FOR_READ);
|
||||
|
|
@ -385,7 +385,7 @@ void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
|
|||
}
|
||||
uint32_t* fat = reinterpret_cast<uint32_t*>(cache);
|
||||
for (size_t k = 0; k < 128; k++) {
|
||||
if (0 == cluster%8) {
|
||||
if (0 == cluster % 8) {
|
||||
if (k) {
|
||||
pr->println();
|
||||
}
|
||||
|
|
@ -406,7 +406,7 @@ void ExFatPartition::dmpSector(print_t* pr, uint32_t sector) {
|
|||
return;
|
||||
}
|
||||
for (uint16_t i = 0; i < m_bytesPerSector; i++) {
|
||||
if (i%32 == 0) {
|
||||
if (i % 32 == 0) {
|
||||
if (i) {
|
||||
pr->println();
|
||||
}
|
||||
|
|
@ -427,9 +427,9 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
|
|||
uint16_t nameHash = 0;
|
||||
uint16_t setChecksum = 0;
|
||||
uint16_t calcChecksum = 0;
|
||||
uint8_t nameLength = 0;
|
||||
uint8_t setCount = 0;
|
||||
uint8_t nUnicode;
|
||||
uint8_t nameLength = 0;
|
||||
uint8_t setCount = 0;
|
||||
uint8_t nUnicode;
|
||||
|
||||
#define RAW_ROOT
|
||||
#ifndef RAW_ROOT
|
||||
|
|
@ -439,12 +439,12 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
|
|||
break;
|
||||
}
|
||||
dir = reinterpret_cast<DirGeneric_t*>(buf);
|
||||
#else // RAW_ROOT
|
||||
#else // RAW_ROOT
|
||||
(void)file;
|
||||
uint32_t nDir = 1UL << (m_sectorsPerClusterShift + 4);
|
||||
uint32_t sector = clusterStartSector(m_rootDirectoryCluster);
|
||||
for (uint32_t iDir = 0; iDir < nDir; iDir++) {
|
||||
size_t i = iDir%16;
|
||||
size_t i = iDir % 16;
|
||||
if (i == 0) {
|
||||
uint8_t* cache = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
|
||||
if (!cache) {
|
||||
|
|
@ -491,7 +491,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
|
|||
calcHash = 0;
|
||||
break;
|
||||
|
||||
case EXFAT_TYPE_NAME:
|
||||
case EXFAT_TYPE_NAME:
|
||||
dirName = reinterpret_cast<DirName_t*>(dir);
|
||||
printDirName(pr, dirName);
|
||||
calcChecksum = exFatDirChecksum(dir, calcChecksum);
|
||||
|
|
@ -499,7 +499,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
|
|||
calcHash = hashDir(dirName, calcHash);
|
||||
nameLength -= nUnicode;
|
||||
setCount--;
|
||||
if (nameLength == 0 || setCount == 0) {
|
||||
if (nameLength == 0 || setCount == 0) {
|
||||
pr->print(F("setChecksum: 0x"));
|
||||
pr->print(setChecksum, HEX);
|
||||
if (setChecksum != calcChecksum) {
|
||||
|
|
@ -536,10 +536,9 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
|
|||
//------------------------------------------------------------------------------
|
||||
void ExFatPartition::printFat(print_t* pr) {
|
||||
uint32_t next;
|
||||
int8_t status;
|
||||
pr->println(F("FAT:"));
|
||||
for (uint32_t cluster = 0; cluster < 16; cluster++) {
|
||||
status = fatGet(cluster, &next);
|
||||
int8_t status = fatGet(cluster, &next);
|
||||
pr->print(cluster, HEX);
|
||||
pr->write(' ');
|
||||
if (status == 0) {
|
||||
|
|
@ -573,20 +572,20 @@ void ExFatPartition::printUpcase(print_t* pr) {
|
|||
pr->println(F("upcase not found"));
|
||||
return;
|
||||
}
|
||||
for (uint16_t i = 0; i < size/2; i++) {
|
||||
if ((i%256) == 0) {
|
||||
for (uint16_t i = 0; i < size / 2; i++) {
|
||||
if ((i % 256) == 0) {
|
||||
upcase = dataCachePrepare(sector++, FsCache::CACHE_FOR_READ);
|
||||
if (!upcase) {
|
||||
pr->println(F("read upcase failed"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i%16 == 0) {
|
||||
if (i % 16 == 0) {
|
||||
pr->println();
|
||||
printHex(pr, i);
|
||||
}
|
||||
pr->write(' ');
|
||||
uint16_t uc = getLe16(&upcase[2*(i & 0XFF)]);
|
||||
uint16_t uc = getLe16(&upcase[2 * (i & 0XFF)]);
|
||||
printHex(pr, uc);
|
||||
checksum = upcaseChecksum(uc, checksum);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
inline bool lfnLegalChar(uint8_t c) {
|
||||
#if USE_UTF8_LONG_NAMES
|
||||
return !lfnReservedChar(c);
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
return !(lfnReservedChar(c) || c & 0X80);
|
||||
#endif // USE_UTF8_LONG_NAMES
|
||||
}
|
||||
|
|
@ -60,13 +60,13 @@ bool ExFatFile::attrib(uint8_t bits) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t* ExFatFile::dirCache(uint8_t set, uint8_t options) {
|
||||
DirPos_t pos = m_dirPos;
|
||||
if (m_vol->dirSeek(&pos, FS_DIR_SIZE*set) != 1) {
|
||||
if (m_vol->dirSeek(&pos, FS_DIR_SIZE * set) != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_vol->dirCache(&pos, options);
|
||||
|
|
@ -87,8 +87,8 @@ bool ExFatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
|
|||
*bgnSector = firstSector();
|
||||
}
|
||||
if (endSector) {
|
||||
*endSector = firstSector() +
|
||||
((m_validLength - 1) >> m_vol->bytesPerSectorShift());
|
||||
*endSector =
|
||||
firstSector() + ((m_validLength - 1) >> m_vol->bytesPerSectorShift());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -136,8 +136,8 @@ void ExFatFile::fsetpos(const fspos_t* pos) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
|
||||
DirFile_t* df = reinterpret_cast<DirFile_t*>
|
||||
(m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
|
||||
DirFile_t* df = reinterpret_cast<DirFile_t*>(
|
||||
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
|
||||
if (!df) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -146,13 +146,13 @@ bool ExFatFile::getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
|
|||
*ptime = getLe16(df->accessTime);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
|
||||
DirFile_t* df = reinterpret_cast<DirFile_t*>
|
||||
(m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
|
||||
DirFile_t* df = reinterpret_cast<DirFile_t*>(
|
||||
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
|
||||
if (!df) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -161,13 +161,13 @@ bool ExFatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
|
|||
*ptime = getLe16(df->createTime);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
|
||||
DirFile_t* df = reinterpret_cast<DirFile_t*>
|
||||
(m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
|
||||
DirFile_t* df = reinterpret_cast<DirFile_t*>(
|
||||
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
|
||||
if (!df) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -176,13 +176,11 @@ bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
|
|||
*ptime = getLe16(df->modifyTime);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::isBusy() {
|
||||
return m_vol->isBusy();
|
||||
}
|
||||
bool ExFatFile::isBusy() { return m_vol->isBusy(); }
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::open(const char* path, oflag_t oflag) {
|
||||
return open(ExFatVolume::cwv(), path, oflag);
|
||||
|
|
@ -231,7 +229,7 @@ bool ExFatFile::open(ExFatFile* dirFile, const char* path, oflag_t oflag) {
|
|||
}
|
||||
return openPrivate(dirFile, &fname, oflag);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -241,7 +239,7 @@ bool ExFatFile::open(uint32_t index, oflag_t oflag) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::open(ExFatFile* dirFile, uint32_t index, oflag_t oflag) {
|
||||
if (dirFile->seekSet(FS_DIR_SIZE*index) && openNext(dirFile, oflag)) {
|
||||
if (dirFile->seekSet(FS_DIR_SIZE * index) && openNext(dirFile, oflag)) {
|
||||
if (dirIndex() == index) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -260,7 +258,7 @@ bool ExFatFile::openCwd() {
|
|||
rewind();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -271,20 +269,18 @@ bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) {
|
|||
}
|
||||
return openPrivate(dir, nullptr, oflag);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
||||
int n;
|
||||
uint8_t modeFlags;
|
||||
uint32_t curCluster __attribute__((unused));
|
||||
uint8_t* cache __attribute__((unused));
|
||||
DirPos_t freePos __attribute__((unused));
|
||||
|
||||
DirFile_t* dirFile;
|
||||
DirFile_t* dirFile;
|
||||
DirStream_t* dirStream;
|
||||
DirName_t* dirName;
|
||||
DirName_t* dirName;
|
||||
uint8_t buf[FS_DIR_SIZE];
|
||||
uint8_t freeCount = 0;
|
||||
uint8_t freeNeed = 3;
|
||||
|
|
@ -313,7 +309,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
modeFlags |= oflag & O_APPEND ? FILE_FLAG_APPEND : 0;
|
||||
|
||||
if (fname) {
|
||||
freeNeed = 2 + (fname->nameLength + 14)/15;
|
||||
freeNeed = 2 + (fname->nameLength + 14) / 15;
|
||||
dir->rewind();
|
||||
}
|
||||
|
||||
|
|
@ -394,7 +390,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
}
|
||||
}
|
||||
|
||||
found:
|
||||
found:
|
||||
// Don't open if create only.
|
||||
if (oflag & O_EXCL) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -428,11 +424,11 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
#endif // !EXFAT_READ_ONLY
|
||||
return true;
|
||||
|
||||
create:
|
||||
create:
|
||||
#if EXFAT_READ_ONLY
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
#else // EXFAT_READ_ONLY
|
||||
#else // EXFAT_READ_ONLY
|
||||
// don't create unless O_CREAT and write
|
||||
if (!(oflag & O_CREAT) || !(modeFlags & FILE_FLAG_WRITE) || !fname) {
|
||||
DBG_WARN_MACRO;
|
||||
|
|
@ -441,12 +437,12 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
while (freeCount < freeNeed) {
|
||||
n = dir->read(buf, FS_DIR_SIZE);
|
||||
if (n == 0) {
|
||||
curCluster = dir->m_curCluster;
|
||||
uint32_t saveCurCluster = dir->m_curCluster;
|
||||
if (!dir->addDirCluster()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
dir->m_curCluster = curCluster;
|
||||
dir->m_curCluster = saveCurCluster;
|
||||
continue;
|
||||
}
|
||||
if (n != FS_DIR_SIZE) {
|
||||
|
|
@ -471,7 +467,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
memset(cache, 0 , FS_DIR_SIZE);
|
||||
memset(cache, 0, FS_DIR_SIZE);
|
||||
if (i == 0) {
|
||||
dirFile = reinterpret_cast<DirFile_t*>(cache);
|
||||
dirFile->type = EXFAT_TYPE_FILE;
|
||||
|
|
@ -489,11 +485,11 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
setLe16(dirFile->createDate, FS_DEFAULT_DATE);
|
||||
setLe16(dirFile->modifyDate, FS_DEFAULT_DATE);
|
||||
setLe16(dirFile->accessDate, FS_DEFAULT_DATE);
|
||||
if (FS_DEFAULT_TIME) {
|
||||
setLe16(dirFile->createTime, FS_DEFAULT_TIME);
|
||||
setLe16(dirFile->modifyTime, FS_DEFAULT_TIME);
|
||||
setLe16(dirFile->accessTime, FS_DEFAULT_TIME);
|
||||
}
|
||||
if (FS_DEFAULT_TIME) {
|
||||
setLe16(dirFile->createTime, FS_DEFAULT_TIME);
|
||||
setLe16(dirFile->modifyTime, FS_DEFAULT_TIME);
|
||||
setLe16(dirFile->accessTime, FS_DEFAULT_TIME);
|
||||
}
|
||||
}
|
||||
} else if (i == 1) {
|
||||
dirStream = reinterpret_cast<DirStream_t*>(cache);
|
||||
|
|
@ -510,14 +506,14 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
|
|||
break;
|
||||
}
|
||||
uint16_t u = fname->get16();
|
||||
setLe16(dirName->unicode + 2*k, u);
|
||||
setLe16(dirName->unicode + 2 * k, u);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sync();
|
||||
#endif // EXFAT_READ_ONLY
|
||||
|
||||
fail:
|
||||
fail:
|
||||
// close file
|
||||
m_attributes = FILE_ATTR_CLOSED;
|
||||
m_flags = 0;
|
||||
|
|
@ -535,12 +531,12 @@ bool ExFatFile::openRoot(ExFatVolume* vol) {
|
|||
m_flags = FILE_FLAG_READ;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::parsePathName(const char* path,
|
||||
ExName_t* fname, const char** ptr) {
|
||||
bool ExFatFile::parsePathName(const char* path, ExName_t* fname,
|
||||
const char** ptr) {
|
||||
// Skip leading spaces.
|
||||
while (*path == ' ') {
|
||||
path++;
|
||||
|
|
@ -559,20 +555,21 @@ bool ExFatFile::parsePathName(const char* path,
|
|||
}
|
||||
}
|
||||
// Advance to next path component.
|
||||
for (; *path == ' ' || isDirSeparator(*path); path++) {}
|
||||
for (; *path == ' ' || isDirSeparator(*path); path++) {
|
||||
}
|
||||
*ptr = path;
|
||||
return hashName(fname);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
int ExFatFile::peek() {
|
||||
uint64_t curPosition = m_curPosition;
|
||||
uint32_t curCluster = m_curCluster;
|
||||
uint64_t saveCurPosition = m_curPosition;
|
||||
uint32_t saveCurCluster = m_curCluster;
|
||||
int c = read();
|
||||
m_curPosition = curPosition;
|
||||
m_curCluster = curCluster;
|
||||
m_curPosition = saveCurPosition;
|
||||
m_curCluster = saveCurCluster;
|
||||
return c;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -600,8 +597,8 @@ int ExFatFile::read(void* buf, size_t count) {
|
|||
sectorOffset = clusterOffset & m_vol->sectorMask();
|
||||
if (clusterOffset == 0) {
|
||||
if (m_curPosition == 0) {
|
||||
m_curCluster = isRoot()
|
||||
? m_vol->rootDirectoryCluster() : m_firstCluster;
|
||||
m_curCluster =
|
||||
isRoot() ? m_vol->rootDirectoryCluster() : m_firstCluster;
|
||||
} else if (isContiguous()) {
|
||||
m_curCluster++;
|
||||
} else {
|
||||
|
|
@ -622,8 +619,8 @@ int ExFatFile::read(void* buf, size_t count) {
|
|||
}
|
||||
sector = m_vol->clusterStartSector(m_curCluster) +
|
||||
(clusterOffset >> m_vol->bytesPerSectorShift());
|
||||
if (sectorOffset != 0 || toRead < m_vol->bytesPerSector()
|
||||
|| sector == m_vol->dataCacheSector()) {
|
||||
if (sectorOffset != 0 || toRead < m_vol->bytesPerSector() ||
|
||||
sector == m_vol->dataCacheSector()) {
|
||||
n = m_vol->bytesPerSector() - sectorOffset;
|
||||
if (n > toRead) {
|
||||
n = toRead;
|
||||
|
|
@ -637,16 +634,16 @@ int ExFatFile::read(void* buf, size_t count) {
|
|||
uint8_t* src = cache + sectorOffset;
|
||||
memcpy(dst, src, n);
|
||||
#if USE_MULTI_SECTOR_IO
|
||||
} else if (toRead >= 2*m_vol->bytesPerSector()) {
|
||||
} else if (toRead >= 2 * m_vol->bytesPerSector()) {
|
||||
uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
|
||||
// Limit reads to current cluster.
|
||||
uint32_t maxNs = m_vol->sectorsPerCluster()
|
||||
- (clusterOffset >> m_vol->bytesPerSectorShift());
|
||||
uint32_t maxNs = m_vol->sectorsPerCluster() -
|
||||
(clusterOffset >> m_vol->bytesPerSectorShift());
|
||||
if (ns > maxNs) {
|
||||
ns = maxNs;
|
||||
}
|
||||
n = ns << m_vol->bytesPerSectorShift();
|
||||
if (!m_vol->cacheSafeRead(sector, dst, ns)) {
|
||||
if (!m_vol->cacheSafeRead(sector, dst, ns)) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -665,7 +662,7 @@ int ExFatFile::read(void* buf, size_t count) {
|
|||
}
|
||||
return count - toRead;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_error |= READ_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -678,7 +675,7 @@ bool ExFatFile::remove(const char* path) {
|
|||
}
|
||||
return file.remove();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -728,11 +725,11 @@ bool ExFatFile::seekSet(uint64_t pos) {
|
|||
}
|
||||
}
|
||||
|
||||
done:
|
||||
done:
|
||||
m_curPosition = pos;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_curCluster = tmp;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,10 @@
|
|||
*/
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "../common/FsDateTime.h"
|
||||
#include "../common/FsApiConstants.h"
|
||||
|
||||
#include "../common/FmtNumber.h"
|
||||
#include "../common/FsApiConstants.h"
|
||||
#include "../common/FsDateTime.h"
|
||||
#include "../common/FsName.h"
|
||||
#include "ExFatPartition.h"
|
||||
|
||||
|
|
@ -68,9 +69,7 @@ class ExFatFile {
|
|||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
|
||||
*/
|
||||
ExFatFile(const char* path, oflag_t oflag) {
|
||||
open(path, oflag);
|
||||
}
|
||||
ExFatFile(const char* path, oflag_t oflag) { open(path, oflag); }
|
||||
|
||||
#if DESTRUCTOR_CLOSES_FILE
|
||||
~ExFatFile() {
|
||||
|
|
@ -81,18 +80,14 @@ class ExFatFile {
|
|||
#endif // DESTRUCTOR_CLOSES_FILE
|
||||
|
||||
/** The parenthesis operator.
|
||||
*
|
||||
* \return true if a file is open.
|
||||
*/
|
||||
operator bool() {
|
||||
return isOpen();
|
||||
}
|
||||
*
|
||||
* \return true if a file is open.
|
||||
*/
|
||||
operator bool() { return isOpen(); }
|
||||
/**
|
||||
* \return user settable file attributes for success else -1.
|
||||
*/
|
||||
int attrib() {
|
||||
return isFileOrSubDir() ? m_attributes & FS_ATTRIB_COPY : -1;
|
||||
}
|
||||
int attrib() { return isFileOrSubDir() ? m_attributes & FS_ATTRIB_COPY : -1; }
|
||||
/** Set file attributes
|
||||
*
|
||||
* \param[in] bits bit-wise or of selected attributes: FS_ATTRIB_READ_ONLY,
|
||||
|
|
@ -117,17 +112,11 @@ class ExFatFile {
|
|||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint64_t available64() {
|
||||
return isFile() ? fileSize() - curPosition() : 0;
|
||||
}
|
||||
uint64_t available64() { return isFile() ? fileSize() - curPosition() : 0; }
|
||||
/** Clear all error bits. */
|
||||
void clearError() {
|
||||
m_error = 0;
|
||||
}
|
||||
void clearError() { m_error = 0; }
|
||||
/** Clear writeError. */
|
||||
void clearWriteError() {
|
||||
m_error &= ~WRITE_ERROR;
|
||||
}
|
||||
void clearWriteError() { m_error &= ~WRITE_ERROR; }
|
||||
/** Close a file and force cached data and directory information
|
||||
* to be written to the storage device.
|
||||
*
|
||||
|
|
@ -145,13 +134,13 @@ class ExFatFile {
|
|||
*/
|
||||
bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster() const {return m_curCluster;}
|
||||
uint32_t curCluster() const { return m_curCluster; }
|
||||
/** \return The current position for a file or directory. */
|
||||
uint64_t curPosition() const {return m_curPosition;}
|
||||
uint64_t curPosition() const { return m_curPosition; }
|
||||
/** \return Total data length for file. */
|
||||
uint64_t dataLength() const {return m_dataLength;}
|
||||
uint64_t dataLength() const { return m_dataLength; }
|
||||
/** \return Directory entry index. */
|
||||
uint32_t dirIndex() const {return m_dirPos.position/FS_DIR_SIZE;}
|
||||
uint32_t dirIndex() const { return m_dirPos.position / FS_DIR_SIZE; }
|
||||
/** Test for the existence of a file in a directory
|
||||
*
|
||||
* \param[in] path Path of the file to be tested for.
|
||||
|
|
@ -163,15 +152,15 @@ class ExFatFile {
|
|||
*
|
||||
* \return true if the file exists else false.
|
||||
*/
|
||||
bool exists(const char* path) {
|
||||
ExFatFile file;
|
||||
return file.open(this, path, O_RDONLY);
|
||||
}
|
||||
bool exists(const char* path) {
|
||||
ExFatFile file;
|
||||
return file.open(this, path, O_RDONLY);
|
||||
}
|
||||
/** get position for streams
|
||||
* \param[out] pos struct to receive position
|
||||
*/
|
||||
void fgetpos(fspos_t* pos) const;
|
||||
/**
|
||||
/**
|
||||
* Get a string from a file.
|
||||
*
|
||||
* fgets() reads bytes from a file into the array pointed to by \a str, until
|
||||
|
|
@ -194,7 +183,7 @@ class ExFatFile {
|
|||
*/
|
||||
int fgets(char* str, int num, char* delim = nullptr);
|
||||
/** \return The total number of bytes in a file. */
|
||||
uint64_t fileSize() const {return m_validLength;}
|
||||
uint64_t fileSize() const { return m_validLength; }
|
||||
/** \return Address of first sector or zero for empty file. */
|
||||
uint32_t firstSector() const;
|
||||
/** Set position for streams
|
||||
|
|
@ -202,7 +191,7 @@ class ExFatFile {
|
|||
*/
|
||||
void fsetpos(const fspos_t* pos);
|
||||
/** Arduino name for sync() */
|
||||
void flush() {sync();}
|
||||
void flush() { sync(); }
|
||||
/** Get a file's access date and time.
|
||||
*
|
||||
* \param[out] pdate Packed date for directory entry.
|
||||
|
|
@ -220,9 +209,7 @@ class ExFatFile {
|
|||
*/
|
||||
bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime);
|
||||
/** \return All error bits. */
|
||||
uint8_t getError() const {
|
||||
return isOpen() ? m_error : 0XFF;
|
||||
}
|
||||
uint8_t getError() const { return isOpen() ? m_error : 0XFF; }
|
||||
/** Get a file's modify date and time.
|
||||
*
|
||||
* \param[out] pdate Packed date for directory entry.
|
||||
|
|
@ -241,7 +228,7 @@ class ExFatFile {
|
|||
size_t getName(char* name, size_t size) {
|
||||
#if USE_UTF8_LONG_NAMES
|
||||
return getName8(name, size);
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
return getName7(name, size);
|
||||
#endif // USE_UTF8_LONG_NAMES
|
||||
}
|
||||
|
|
@ -262,9 +249,7 @@ class ExFatFile {
|
|||
*/
|
||||
size_t getName8(char* name, size_t size);
|
||||
/** \return value of writeError */
|
||||
bool getWriteError() const {
|
||||
return isOpen() ? m_error & WRITE_ERROR : true;
|
||||
}
|
||||
bool getWriteError() const { return isOpen() ? m_error & WRITE_ERROR : true; }
|
||||
/**
|
||||
* Check for FsBlockDevice busy.
|
||||
*
|
||||
|
|
@ -272,29 +257,29 @@ class ExFatFile {
|
|||
*/
|
||||
bool isBusy();
|
||||
/** \return True if the file is contiguous. */
|
||||
bool isContiguous() const {return m_flags & FILE_FLAG_CONTIGUOUS;}
|
||||
bool isContiguous() const { return m_flags & FILE_FLAG_CONTIGUOUS; }
|
||||
/** \return True if this is a directory. */
|
||||
bool isDir() const {return m_attributes & FILE_ATTR_DIR;}
|
||||
bool isDir() const { return m_attributes & FILE_ATTR_DIR; }
|
||||
/** \return True if this is a normal file. */
|
||||
bool isFile() const {return m_attributes & FILE_ATTR_FILE;}
|
||||
bool isFile() const { return m_attributes & FILE_ATTR_FILE; }
|
||||
/** \return True if this is a normal file or sub-directory. */
|
||||
bool isFileOrSubDir() const {return isFile() || isSubDir();}
|
||||
bool isFileOrSubDir() const { return isFile() || isSubDir(); }
|
||||
/** \return True if this is a hidden. */
|
||||
bool isHidden() const {return m_attributes & FS_ATTRIB_HIDDEN;}
|
||||
bool isHidden() const { return m_attributes & FS_ATTRIB_HIDDEN; }
|
||||
/** \return true if the file is open. */
|
||||
bool isOpen() const {return m_attributes;}
|
||||
bool isOpen() const { return m_attributes; }
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {return m_attributes & FS_ATTRIB_READ_ONLY;}
|
||||
bool isReadOnly() const { return m_attributes & FS_ATTRIB_READ_ONLY; }
|
||||
/** \return True if this is the root directory. */
|
||||
bool isRoot() const {return m_attributes & FILE_ATTR_ROOT;}
|
||||
bool isRoot() const { return m_attributes & FILE_ATTR_ROOT; }
|
||||
/** \return True file is readable. */
|
||||
bool isReadable() const {return m_flags & FILE_FLAG_READ;}
|
||||
bool isReadable() const { return m_flags & FILE_FLAG_READ; }
|
||||
/** \return True if this is a sub-directory. */
|
||||
bool isSubDir() const {return m_attributes & FILE_ATTR_SUBDIR;}
|
||||
bool isSubDir() const { return m_attributes & FILE_ATTR_SUBDIR; }
|
||||
/** \return True if this is a system file. */
|
||||
bool isSystem() const {return m_attributes & FS_ATTRIB_SYSTEM;}
|
||||
bool isSystem() const { return m_attributes & FS_ATTRIB_SYSTEM; }
|
||||
/** \return True file is writable. */
|
||||
bool isWritable() const {return m_flags & FILE_FLAG_WRITE;}
|
||||
bool isWritable() const { return m_flags & FILE_FLAG_WRITE; }
|
||||
/** List directory contents.
|
||||
*
|
||||
* \param[in] pr Print stream for list.
|
||||
|
|
@ -424,7 +409,7 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(const char* path, oflag_t oflag = O_RDONLY);
|
||||
/** Open the current working directory.
|
||||
/** Open the current working directory.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
|
|
@ -463,14 +448,14 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool preAllocate(uint64_t length);
|
||||
/** Print a file's access date and time
|
||||
/** Print a file's access date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr);
|
||||
/** Print a file's creation date and time
|
||||
/** Print a file's creation date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
|
|
@ -512,7 +497,7 @@ class ExFatFile {
|
|||
template <typename Type>
|
||||
size_t printField(Type value, char term) {
|
||||
char sign = 0;
|
||||
char buf[3*sizeof(Type) + 3];
|
||||
char buf[3 * sizeof(Type) + 3];
|
||||
char* str = buf + sizeof(buf);
|
||||
|
||||
if (term) {
|
||||
|
|
@ -556,7 +541,7 @@ class ExFatFile {
|
|||
size_t printName(print_t* pr) {
|
||||
#if USE_UTF8_LONG_NAMES
|
||||
return printName8(pr);
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
return printName7(pr);
|
||||
#endif // USE_UTF8_LONG_NAMES
|
||||
}
|
||||
|
|
@ -621,14 +606,14 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const char* path);
|
||||
/** Rename a file or subdirectory.
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
* \param[in] newPath New path name for the file/directory.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rename(const char* newPath);
|
||||
/** Rename a file or subdirectory.
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
* \param[in] dirFile Directory for the new path.
|
||||
* \param[in] newPath New path name for the file/directory.
|
||||
|
|
@ -637,9 +622,7 @@ class ExFatFile {
|
|||
*/
|
||||
bool rename(ExFatFile* dirFile, const char* newPath);
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind() {
|
||||
seekSet(0);
|
||||
}
|
||||
void rewind() { seekSet(0); }
|
||||
/** Remove a directory file.
|
||||
*
|
||||
* The directory file will be removed only if it is empty and is not the
|
||||
|
|
@ -657,9 +640,7 @@ class ExFatFile {
|
|||
* \param[in] offset The new position in bytes from the current position.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekCur(int64_t offset) {
|
||||
return seekSet(m_curPosition + offset);
|
||||
}
|
||||
bool seekCur(int64_t offset) { return seekSet(m_curPosition + offset); }
|
||||
/** Set the files position to end-of-file + \a offset. See seekSet().
|
||||
* Can't be used for directory files since file size is not defined.
|
||||
* \param[in] offset The new position in bytes from end-of-file.
|
||||
|
|
@ -676,7 +657,7 @@ class ExFatFile {
|
|||
*/
|
||||
bool seekSet(uint64_t pos);
|
||||
/** \return directory set count */
|
||||
uint8_t setCount() const {return m_setCount;}
|
||||
uint8_t setCount() const { return m_setCount; }
|
||||
/** The sync() call causes all modified data and directory fields
|
||||
* to be written to the storage device.
|
||||
*
|
||||
|
|
@ -728,32 +709,28 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool truncate();
|
||||
/** Truncate a file to a specified length. The current file position
|
||||
/** Truncate a file to a specified length. The current file position
|
||||
* will be set to end of file.
|
||||
*
|
||||
* \param[in] length The desired length for the file.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool truncate(uint64_t length) {
|
||||
return seekSet(length) && truncate();
|
||||
}
|
||||
bool truncate(uint64_t length) { return seekSet(length) && truncate(); }
|
||||
|
||||
/** \return The valid number of bytes in a file. */
|
||||
uint64_t validLength() const {return m_validLength;}
|
||||
uint64_t validLength() const { return m_validLength; }
|
||||
/** Write a string to a file. Used by the Arduino Print class.
|
||||
* \param[in] str Pointer to the string.
|
||||
* Use getWriteError to check for errors.
|
||||
* \return count of characters written for success or -1 for failure.
|
||||
*/
|
||||
size_t write(const char* str) {
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
size_t write(const char* str) { return write(str, strlen(str)); }
|
||||
/** Write a single byte.
|
||||
* \param[in] b The byte to be written.
|
||||
* \return +1 for success or zero for failure.
|
||||
*/
|
||||
size_t write(uint8_t b) {return write(&b, 1);}
|
||||
size_t write(uint8_t b) { return write(&b, 1); }
|
||||
/** Write data to an open file.
|
||||
*
|
||||
* \note Data is moved to the cache but may not be written to the
|
||||
|
|
@ -781,16 +758,12 @@ class ExFatFile {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(uint8_t flags = 0) {
|
||||
return ls(&Serial, flags);
|
||||
}
|
||||
bool ls(uint8_t flags = 0) { return ls(&Serial, flags); }
|
||||
/** Print a file's name.
|
||||
*
|
||||
* \return length for success or zero for failure.
|
||||
*/
|
||||
size_t printName() {
|
||||
return ExFatFile::printName(&Serial);
|
||||
}
|
||||
size_t printName() { return ExFatFile::printName(&Serial); }
|
||||
#endif // ENABLE_ARDUINO_SERIAL
|
||||
|
||||
private:
|
||||
|
|
@ -804,13 +777,12 @@ class ExFatFile {
|
|||
bool mkdir(ExFatFile* parent, ExName_t* fname);
|
||||
|
||||
bool openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag);
|
||||
bool parsePathName(const char* path,
|
||||
ExName_t* fname, const char** ptr);
|
||||
ExFatVolume* volume() const {return m_vol;}
|
||||
bool parsePathName(const char* path, ExName_t* fname, const char** ptr);
|
||||
ExFatVolume* volume() const { return m_vol; }
|
||||
bool syncDir();
|
||||
//----------------------------------------------------------------------------
|
||||
static const uint8_t WRITE_ERROR = 0X1;
|
||||
static const uint8_t READ_ERROR = 0X2;
|
||||
static const uint8_t READ_ERROR = 0X2;
|
||||
|
||||
/** This file has not been opened. */
|
||||
static const uint8_t FILE_ATTR_CLOSED = 0;
|
||||
|
|
@ -826,21 +798,20 @@ class ExFatFile {
|
|||
static const uint8_t FILE_FLAG_READ = 0X01;
|
||||
static const uint8_t FILE_FLAG_WRITE = 0X02;
|
||||
static const uint8_t FILE_FLAG_APPEND = 0X08;
|
||||
static const uint8_t FILE_FLAG_CONTIGUOUS = 0X40;
|
||||
static const uint8_t FILE_FLAG_CONTIGUOUS = 0X40;
|
||||
static const uint8_t FILE_FLAG_DIR_DIRTY = 0X80;
|
||||
|
||||
|
||||
uint64_t m_curPosition;
|
||||
uint64_t m_dataLength;
|
||||
uint64_t m_validLength;
|
||||
uint32_t m_curCluster;
|
||||
uint32_t m_firstCluster;
|
||||
ExFatVolume* m_vol;
|
||||
DirPos_t m_dirPos;
|
||||
uint8_t m_setCount;
|
||||
uint8_t m_attributes = FILE_ATTR_CLOSED;
|
||||
uint8_t m_error = 0;
|
||||
uint8_t m_flags = 0;
|
||||
uint64_t m_curPosition;
|
||||
uint64_t m_dataLength;
|
||||
uint64_t m_validLength;
|
||||
uint32_t m_curCluster;
|
||||
uint32_t m_firstCluster;
|
||||
ExFatVolume* m_vol;
|
||||
DirPos_t m_dirPos;
|
||||
uint8_t m_setCount;
|
||||
uint8_t m_attributes = FILE_ATTR_CLOSED;
|
||||
uint8_t m_error = 0;
|
||||
uint8_t m_flags = 0;
|
||||
};
|
||||
|
||||
#include "../common/ArduinoFiles.h"
|
||||
|
|
@ -850,7 +821,7 @@ class ExFatFile {
|
|||
*/
|
||||
class ExFile : public StreamFile<ExFatFile, uint64_t> {
|
||||
public:
|
||||
/** Opens the next file or folder in a directory.
|
||||
/** Opens the next file or folder in a directory.
|
||||
*
|
||||
* \param[in] oflag open flags.
|
||||
* \return a FatStream object.
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
*/
|
||||
#define DBG_FILE "ExFatFilePrint.cpp"
|
||||
#include "../common/DebugMacros.h"
|
||||
#include "ExFatLib.h"
|
||||
#include "../common/FsUtf.h"
|
||||
#include "ExFatLib.h"
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::ls(print_t* pr) {
|
||||
ExFatFile file;
|
||||
|
|
@ -51,7 +51,7 @@ bool ExFatFile::ls(print_t* pr) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -94,7 +94,7 @@ bool ExFatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -119,13 +119,13 @@ size_t ExFatFile::printCreateDateTime(print_t* pr) {
|
|||
size_t ExFatFile::printFileSize(print_t* pr) {
|
||||
uint64_t n = m_validLength;
|
||||
char buf[21];
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
char *bgn = str - 12;
|
||||
char* str = &buf[sizeof(buf) - 1];
|
||||
char* bgn = str - 12;
|
||||
*str = '\0';
|
||||
do {
|
||||
uint64_t m = n;
|
||||
n /= 10;
|
||||
*--str = m - 10*n + '0';
|
||||
*--str = m - 10 * n + '0';
|
||||
} while (n);
|
||||
while (str > bgn) {
|
||||
*--str = ' ';
|
||||
|
|
@ -148,18 +148,17 @@ size_t ExFatFile::printName7(print_t* pr) {
|
|||
uint8_t in;
|
||||
uint8_t buf[15];
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t is = 2; is <= m_setCount; is++) {
|
||||
dn = reinterpret_cast<DirName_t*>
|
||||
(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
dn = reinterpret_cast<DirName_t*>(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
if (!dn || dn->type != EXFAT_TYPE_NAME) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (in = 0; in < 15; in++) {
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
uint16_t c = getLe16(dn->unicode + 2 * in);
|
||||
if (!c) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -170,11 +169,11 @@ size_t ExFatFile::printName7(print_t* pr) {
|
|||
}
|
||||
return n;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
size_t ExFatFile::printName8(print_t *pr) {
|
||||
size_t ExFatFile::printName8(print_t* pr) {
|
||||
DirName_t* dn;
|
||||
uint16_t hs = 0;
|
||||
uint32_t cp;
|
||||
|
|
@ -182,18 +181,17 @@ size_t ExFatFile::printName8(print_t *pr) {
|
|||
uint8_t in;
|
||||
char buf[5];
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t is = 2; is <= m_setCount; is++) {
|
||||
dn = reinterpret_cast<DirName_t*>
|
||||
(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
dn = reinterpret_cast<DirName_t*>(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
if (!dn || dn->type != EXFAT_TYPE_NAME) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (in = 0; in < 15; in++) {
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
uint16_t c = getLe16(dn->unicode + 2 * in);
|
||||
if (hs) {
|
||||
if (!FsUtf::isLowSurrogate(c)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -218,11 +216,11 @@ size_t ExFatFile::printName8(print_t *pr) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
n += pr->write(buf, str - buf);
|
||||
n += pr->write(reinterpret_cast<uint8_t*>(buf), str - buf);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
//==============================================================================
|
||||
#if EXFAT_READ_ONLY
|
||||
bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
|
||||
(void) parent;
|
||||
(void)parent;
|
||||
(void)path;
|
||||
(void)pFlag;
|
||||
return false;
|
||||
|
|
@ -46,12 +46,8 @@ bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) {
|
|||
(void)newPath;
|
||||
return false;
|
||||
}
|
||||
bool ExFatFile::sync() {
|
||||
return false;
|
||||
}
|
||||
bool ExFatFile::truncate() {
|
||||
return false;
|
||||
}
|
||||
bool ExFatFile::sync() { return false; }
|
||||
bool ExFatFile::truncate() { return false; }
|
||||
size_t ExFatFile::write(const void* buf, size_t nbyte) {
|
||||
(void)buf;
|
||||
(void)nbyte;
|
||||
|
|
@ -69,7 +65,7 @@ static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::addCluster() {
|
||||
uint32_t find = m_vol->bitmapFind(m_curCluster ? m_curCluster + 1 : 0, 1);
|
||||
uint32_t find = m_vol->bitmapFind(m_curCluster ? m_curCluster + 1 : 0, 1);
|
||||
if (find < 2) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -109,11 +105,11 @@ bool ExFatFile::addCluster() {
|
|||
}
|
||||
}
|
||||
|
||||
done:
|
||||
done:
|
||||
m_curCluster = find;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -131,9 +127,9 @@ bool ExFatFile::addDirCluster() {
|
|||
goto fail;
|
||||
}
|
||||
sector = m_vol->clusterStartSector(m_curCluster);
|
||||
for (uint32_t i = 0; i < m_vol->sectorsPerCluster(); i++) {
|
||||
cache = m_vol->dataCachePrepare(sector + i,
|
||||
FsCache::CACHE_RESERVE_FOR_WRITE);
|
||||
for (uint32_t i = 0; i < m_vol->sectorsPerCluster(); i++) {
|
||||
cache =
|
||||
m_vol->dataCachePrepare(sector + i, FsCache::CACHE_RESERVE_FOR_WRITE);
|
||||
if (!cache) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -142,12 +138,12 @@ bool ExFatFile::addDirCluster() {
|
|||
}
|
||||
if (!isRoot()) {
|
||||
m_flags |= FILE_FLAG_DIR_DIRTY;
|
||||
m_dataLength += m_vol->bytesPerCluster();
|
||||
m_dataLength += m_vol->bytesPerCluster();
|
||||
m_validLength += m_vol->bytesPerCluster();
|
||||
}
|
||||
return sync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -189,7 +185,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
|
|||
}
|
||||
return mkdir(parent, &fname);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -218,7 +214,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, ExName_t* fname) {
|
|||
m_flags = FILE_FLAG_READ | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
|
||||
return sync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -248,7 +244,7 @@ bool ExFatFile::preAllocate(uint64_t length) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -290,7 +286,7 @@ bool ExFatFile::remove() {
|
|||
// Write entry to device.
|
||||
return m_vol->cacheSync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -330,7 +326,7 @@ bool ExFatFile::rename(ExFatFile* dirFile, const char* newPath) {
|
|||
oldFile.m_attributes = FILE_ATTR_FILE;
|
||||
return oldFile.remove();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -363,7 +359,7 @@ bool ExFatFile::rmdir() {
|
|||
m_flags |= FILE_FLAG_WRITE;
|
||||
return remove();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -382,7 +378,7 @@ bool ExFatFile::sync() {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_error |= WRITE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -393,7 +389,7 @@ bool ExFatFile::syncDir() {
|
|||
uint8_t* cache;
|
||||
uint16_t checksum = 0;
|
||||
|
||||
for (uint8_t is = 0; is <= m_setCount ; is++) {
|
||||
for (uint8_t is = 0; is <= m_setCount; is++) {
|
||||
cache = dirCache(is, FsCache::CACHE_FOR_READ);
|
||||
if (!cache) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -439,8 +435,8 @@ bool ExFatFile::syncDir() {
|
|||
}
|
||||
checksum = exFatDirChecksum(cache, checksum);
|
||||
}
|
||||
df = reinterpret_cast<DirFile_t*>
|
||||
(m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
|
||||
df = reinterpret_cast<DirFile_t*>(
|
||||
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
|
||||
if (!df) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -452,13 +448,14 @@ bool ExFatFile::syncDir() {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_error |= WRITE_ERROR;
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
|
||||
uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
uint8_t day, uint8_t hour, uint8_t minute,
|
||||
uint8_t second) {
|
||||
DirFile_t* df;
|
||||
uint8_t* cache;
|
||||
uint16_t checksum = 0;
|
||||
|
|
@ -466,16 +463,8 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
|
|||
uint16_t time;
|
||||
uint8_t ms10;
|
||||
|
||||
if (!isFile()
|
||||
|| year < 1980
|
||||
|| year > 2107
|
||||
|| month < 1
|
||||
|| month > 12
|
||||
|| day < 1
|
||||
|| day > 31
|
||||
|| hour > 23
|
||||
|| minute > 59
|
||||
|| second > 59) {
|
||||
if (!isFile() || year < 1980 || year > 2107 || month < 1 || month > 12 ||
|
||||
day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -529,8 +518,8 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
|
|||
}
|
||||
checksum = exFatDirChecksum(cache, checksum);
|
||||
}
|
||||
df = reinterpret_cast<DirFile_t*>
|
||||
(m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
|
||||
df = reinterpret_cast<DirFile_t*>(
|
||||
m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
|
||||
if (!df) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -542,7 +531,7 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -554,7 +543,7 @@ bool ExFatFile::truncate() {
|
|||
goto fail;
|
||||
}
|
||||
if (m_firstCluster == 0) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
if (isContiguous()) {
|
||||
uint32_t nc = 1 + ((m_dataLength - 1) >> m_vol->bytesPerClusterShift());
|
||||
|
|
@ -601,7 +590,7 @@ bool ExFatFile::truncate() {
|
|||
m_flags |= FILE_FLAG_DIR_DIRTY;
|
||||
return sync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -708,18 +697,18 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
|
|||
}
|
||||
}
|
||||
#if USE_MULTI_SECTOR_IO
|
||||
} else if (toWrite >= 2*m_vol->bytesPerSector()) {
|
||||
} else if (toWrite >= 2 * m_vol->bytesPerSector()) {
|
||||
// use multiple sector write command
|
||||
uint32_t ns = toWrite >> m_vol->bytesPerSectorShift();
|
||||
// Limit writes to current cluster.
|
||||
uint32_t maxNs = m_vol->sectorsPerCluster()
|
||||
- (clusterOffset >> m_vol->bytesPerSectorShift());
|
||||
uint32_t maxNs = m_vol->sectorsPerCluster() -
|
||||
(clusterOffset >> m_vol->bytesPerSectorShift());
|
||||
if (ns > maxNs) {
|
||||
ns = maxNs;
|
||||
}
|
||||
n = ns << m_vol->bytesPerSectorShift();
|
||||
if (!m_vol->cacheSafeWrite(sector, src, ns)) {
|
||||
DBG_FAIL_MACRO;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
#endif // USE_MULTI_SECTOR_IO
|
||||
|
|
@ -748,7 +737,7 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
|
|||
}
|
||||
return nbyte;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
// return for write error
|
||||
m_error |= WRITE_ERROR;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
const uint32_t BOOT_BACKUP_OFFSET = 12;
|
||||
const uint16_t BYTES_PER_SECTOR = 512;
|
||||
const uint16_t SECTOR_MASK = BYTES_PER_SECTOR - 1;
|
||||
const uint8_t BYTES_PER_SECTOR_SHIFT = 9;
|
||||
const uint8_t BYTES_PER_SECTOR_SHIFT = 9;
|
||||
const uint16_t MINIMUM_UPCASE_SKIP = 512;
|
||||
const uint32_t BITMAP_CLUSTER = 2;
|
||||
const uint32_t UPCASE_CLUSTER = 3;
|
||||
|
|
@ -41,14 +41,16 @@ const uint32_t ROOT_CLUSTER = 4;
|
|||
#if !PRINT_FORMAT_PROGRESS
|
||||
#define writeMsg(pr, str)
|
||||
#elif defined(__AVR__)
|
||||
#define writeMsg(pr, str) if (pr) pr->print(F(str))
|
||||
#define writeMsg(pr, str) \
|
||||
if (pr) pr->print(F(str))
|
||||
#else // PRINT_FORMAT_PROGRESS
|
||||
#define writeMsg(pr, str) if (pr) pr->write(str)
|
||||
#define writeMsg(pr, str) \
|
||||
if (pr) pr->write(str)
|
||||
#endif // PRINT_FORMAT_PROGRESS
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
||||
#if !PRINT_FORMAT_PROGRESS
|
||||
(void)pr;
|
||||
(void)pr;
|
||||
#endif // !PRINT_FORMAT_PROGRESS
|
||||
MbrSector_t* mbr;
|
||||
ExFatPbs_t* pbs;
|
||||
|
|
@ -81,14 +83,15 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
goto fail;
|
||||
}
|
||||
// Determine partition layout.
|
||||
for (m = 1, vs = 0; m && sectorCount > m; m <<= 1, vs++) {}
|
||||
sectorsPerClusterShift = vs < 29 ? 8 : (vs - 11)/2;
|
||||
for (m = 1, vs = 0; m && sectorCount > m; m <<= 1, vs++) {
|
||||
}
|
||||
sectorsPerClusterShift = vs < 29 ? 8 : (vs - 11) / 2;
|
||||
sectorsPerCluster = 1UL << sectorsPerClusterShift;
|
||||
fatLength = 1UL << (vs < 27 ? 13 : (vs + 1)/2);
|
||||
fatLength = 1UL << (vs < 27 ? 13 : (vs + 1) / 2);
|
||||
fatOffset = fatLength;
|
||||
partitionOffset = 2*fatLength;
|
||||
clusterHeapOffset = 2*fatLength;
|
||||
clusterCount = (sectorCount - 4*fatLength) >> sectorsPerClusterShift;
|
||||
partitionOffset = 2 * fatLength;
|
||||
clusterHeapOffset = 2 * fatLength;
|
||||
clusterCount = (sectorCount - 4 * fatLength) >> sectorsPerClusterShift;
|
||||
volumeLength = clusterHeapOffset + (clusterCount << sectorsPerClusterShift);
|
||||
|
||||
// make Master Boot Record. Use fake CHS.
|
||||
|
|
@ -152,8 +155,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
checksum = exFatChecksum(checksum, secBuf[i]);
|
||||
}
|
||||
sector = partitionOffset;
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET, secBuf)) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -165,8 +168,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
for (size_t i = 0; i < BYTES_PER_SECTOR; i++) {
|
||||
checksum = exFatChecksum(checksum, secBuf[i]);
|
||||
}
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET, secBuf)) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -178,8 +181,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
for (size_t i = 0; i < BYTES_PER_SECTOR; i++) {
|
||||
checksum = exFatChecksum(checksum, secBuf[i]);
|
||||
}
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET, secBuf)) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -189,15 +192,15 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
for (size_t i = 0; i < BYTES_PER_SECTOR; i += 4) {
|
||||
setLe32(secBuf + i, checksum);
|
||||
}
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
|
||||
if (!dev->writeSector(sector, secBuf) ||
|
||||
!dev->writeSector(sector + BOOT_BACKUP_OFFSET, secBuf)) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
// Initialize FAT.
|
||||
writeMsg(pr, "Writing FAT ");
|
||||
sector = partitionOffset + fatOffset;
|
||||
ns = ((clusterCount + 2)*4 + BYTES_PER_SECTOR - 1)/BYTES_PER_SECTOR;
|
||||
ns = ((clusterCount + 2) * 4 + BYTES_PER_SECTOR - 1) / BYTES_PER_SECTOR;
|
||||
|
||||
memset(secBuf, 0, BYTES_PER_SECTOR);
|
||||
// Allocate two reserved clusters, bitmap, upcase, and root clusters.
|
||||
|
|
@ -206,7 +209,7 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
secBuf[i] = 0XFF;
|
||||
}
|
||||
for (uint32_t i = 0; i < ns; i++) {
|
||||
if (i%(ns/32) == 0) {
|
||||
if (i % (ns / 32) == 0) {
|
||||
writeMsg(pr, ".");
|
||||
}
|
||||
if (!dev->writeSector(sector + i, secBuf)) {
|
||||
|
|
@ -220,8 +223,8 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
writeMsg(pr, "\r\n");
|
||||
// Write cluster two, bitmap.
|
||||
sector = partitionOffset + clusterHeapOffset;
|
||||
bitmapSize = (clusterCount + 7)/8;
|
||||
ns = (bitmapSize + BYTES_PER_SECTOR - 1)/BYTES_PER_SECTOR;
|
||||
bitmapSize = (clusterCount + 7) / 8;
|
||||
ns = (bitmapSize + BYTES_PER_SECTOR - 1) / BYTES_PER_SECTOR;
|
||||
if (ns > sectorsPerCluster) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -244,14 +247,14 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
if (m_upcaseSize > BYTES_PER_SECTOR*sectorsPerCluster) {
|
||||
if (m_upcaseSize > BYTES_PER_SECTOR * sectorsPerCluster) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
// Initialize first sector of root.
|
||||
writeMsg(pr, "Writing root\r\n");
|
||||
ns = sectorsPerCluster;
|
||||
sector = partitionOffset + clusterHeapOffset + 2*sectorsPerCluster;
|
||||
sector = partitionOffset + clusterHeapOffset + 2 * sectorsPerCluster;
|
||||
memset(secBuf, 0, BYTES_PER_SECTOR);
|
||||
|
||||
// Unused Label entry.
|
||||
|
|
@ -284,7 +287,7 @@ bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
writeMsg(pr, "Format done\r\n");
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
writeMsg(pr, "Format failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -334,7 +337,8 @@ bool ExFatFormatter::writeUpcase(uint32_t sector) {
|
|||
}
|
||||
ch++;
|
||||
} else {
|
||||
for (n = ch + 1; n < 0X10000 && n == toUpcase(n); n++) {}
|
||||
for (n = ch + 1; n < 0X10000 && n == toUpcase(n); n++) {
|
||||
}
|
||||
ns = n - ch;
|
||||
if (ns >= MINIMUM_UPCASE_SKIP) {
|
||||
if (!writeUpcaseUnicode(0XFFFF) || !writeUpcaseUnicode(ns)) {
|
||||
|
|
@ -358,6 +362,6 @@ bool ExFatFormatter::writeUpcase(uint32_t sector) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
*/
|
||||
class ExFatFormatter {
|
||||
public:
|
||||
/** Constructor. */
|
||||
ExFatFormatter() = default;
|
||||
/**
|
||||
* Format an exFAT volume.
|
||||
*
|
||||
|
|
@ -41,6 +43,7 @@ class ExFatFormatter {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr = nullptr);
|
||||
|
||||
private:
|
||||
bool syncUpcase();
|
||||
bool writeUpcase(uint32_t sector);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,6 @@
|
|||
*/
|
||||
#ifndef ExFatLib_h
|
||||
#define ExFatLib_h
|
||||
#include "ExFatVolume.h"
|
||||
#include "ExFatFormatter.h"
|
||||
#include "ExFatVolume.h"
|
||||
#endif // ExFatLib_h
|
||||
|
|
|
|||
|
|
@ -24,13 +24,11 @@
|
|||
*/
|
||||
#define DBG_FILE "ExFatName.cpp"
|
||||
#include "../common/DebugMacros.h"
|
||||
#include "../common/upcase.h"
|
||||
#include "../common/FsUtf.h"
|
||||
#include "../common/upcase.h"
|
||||
#include "ExFatLib.h"
|
||||
//------------------------------------------------------------------------------
|
||||
static char toUpper(char c) {
|
||||
return 'a' <= c && c <= 'z' ? c - 'a' + 'A' : c;
|
||||
}
|
||||
static char toUpper(char c) { return 'a' <= c && c <= 'z' ? c - 'a' + 'A' : c; }
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint16_t exFatHash(char c, uint16_t hash) {
|
||||
uint8_t u = toUpper(c);
|
||||
|
|
@ -48,16 +46,16 @@ inline uint16_t exFatHash(uint16_t u, uint16_t hash) {
|
|||
//------------------------------------------------------------------------------
|
||||
bool ExFatFile::cmpName(const DirName_t* dirName, ExName_t* fname) {
|
||||
for (uint8_t i = 0; i < 15; i++) {
|
||||
uint16_t u = getLe16(dirName->unicode + 2*i);
|
||||
uint16_t u = getLe16(dirName->unicode + 2 * i);
|
||||
if (fname->atEnd()) {
|
||||
return u == 0;
|
||||
}
|
||||
#if USE_UTF8_LONG_NAMES
|
||||
uint16_t cp = fname->get16();
|
||||
if (toUpcase(cp) != toUpcase(u)) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
char c = fname->getch();
|
||||
if (u >= 0x7F || toUpper(c) != toUpper(u)) {
|
||||
return false;
|
||||
|
|
@ -71,18 +69,17 @@ size_t ExFatFile::getName7(char* name, size_t count) {
|
|||
DirName_t* dn;
|
||||
size_t n = 0;
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t is = 2; is <= m_setCount; is++) {
|
||||
dn = reinterpret_cast<DirName_t*>
|
||||
(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
dn = reinterpret_cast<DirName_t*>(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
if (!dn || dn->type != EXFAT_TYPE_NAME) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t in = 0; in < 15; in++) {
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
uint16_t c = getLe16(dn->unicode + 2 * in);
|
||||
if (c == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -93,11 +90,11 @@ size_t ExFatFile::getName7(char* name, size_t count) {
|
|||
name[n++] = c < 0X7F ? c : '?';
|
||||
}
|
||||
}
|
||||
done:
|
||||
done:
|
||||
name[n] = 0;
|
||||
return n;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
*name = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -110,18 +107,17 @@ size_t ExFatFile::getName8(char* name, size_t count) {
|
|||
uint16_t hs = 0;
|
||||
uint32_t cp;
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t is = 2; is <= m_setCount; is++) {
|
||||
dn = reinterpret_cast<DirName_t*>
|
||||
(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
dn = reinterpret_cast<DirName_t*>(dirCache(is, FsCache::CACHE_FOR_READ));
|
||||
if (!dn || dn->type != EXFAT_TYPE_NAME) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint8_t in = 0; in < 15; in++) {
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
uint16_t c = getLe16(dn->unicode + 2 * in);
|
||||
if (hs) {
|
||||
if (!FsUtf::isLowSurrogate(c)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -150,11 +146,11 @@ size_t ExFatFile::getName8(char* name, size_t count) {
|
|||
str = ptr;
|
||||
}
|
||||
}
|
||||
done:
|
||||
done:
|
||||
*str = '\0';
|
||||
return str - name;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
*name = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -167,13 +163,13 @@ bool ExFatFile::hashName(ExName_t* fname) {
|
|||
while (!fname->atEnd()) {
|
||||
uint16_t u = fname->get16();
|
||||
if (u == 0XFFFF) {
|
||||
DBG_FAIL_MACRO;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
hash = exFatHash(u, hash);
|
||||
fname->nameLength++;
|
||||
}
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
while (!fname->atEnd()) {
|
||||
// Convert to byte for smaller exFatHash.
|
||||
char c = fname->getch();
|
||||
|
|
@ -188,7 +184,6 @@ bool ExFatFile::hashName(ExName_t* fname) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
|
|||
uint8_t* cache;
|
||||
uint8_t mask = 1 << (start & 7);
|
||||
while (true) {
|
||||
uint32_t sector = m_clusterHeapStartSector +
|
||||
(endAlloc >> (m_bytesPerSectorShift + 3));
|
||||
uint32_t sector =
|
||||
m_clusterHeapStartSector + (endAlloc >> (m_bytesPerSectorShift + 3));
|
||||
cache = bitmapCachePrepare(sector, FsCache::CACHE_FOR_READ);
|
||||
if (!cache) {
|
||||
return 0;
|
||||
|
|
@ -75,8 +75,8 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
|
|||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool ExFatPartition::bitmapModify(uint32_t cluster,
|
||||
uint32_t count, bool value) {
|
||||
bool ExFatPartition::bitmapModify(uint32_t cluster, uint32_t count,
|
||||
bool value) {
|
||||
uint32_t sector;
|
||||
uint32_t start = cluster - 2;
|
||||
size_t i;
|
||||
|
|
@ -88,7 +88,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
|
|||
goto fail;
|
||||
}
|
||||
if (value) {
|
||||
if (start <= m_bitmapStart && m_bitmapStart < (start + count)) {
|
||||
if (start <= m_bitmapStart && m_bitmapStart < (start + count)) {
|
||||
m_bitmapStart = (start + count) < m_clusterCount ? start + count : 0;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -97,8 +97,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
|
|||
}
|
||||
}
|
||||
mask = 1 << (start & 7);
|
||||
sector = m_clusterHeapStartSector +
|
||||
(start >> (m_bytesPerSectorShift + 3));
|
||||
sector = m_clusterHeapStartSector + (start >> (m_bytesPerSectorShift + 3));
|
||||
i = (start >> 3) & m_sectorMask;
|
||||
while (true) {
|
||||
cache = bitmapCachePrepare(sector++, FsCache::CACHE_FOR_WRITE);
|
||||
|
|
@ -122,7 +121,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
|
|||
i = 0;
|
||||
}
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -130,7 +129,7 @@ uint32_t ExFatPartition::chainSize(uint32_t cluster) {
|
|||
uint32_t n = 0;
|
||||
int8_t status;
|
||||
do {
|
||||
status = fatGet(cluster, & cluster);
|
||||
status = fatGet(cluster, &cluster);
|
||||
if (status < 0) return 0;
|
||||
n++;
|
||||
} while (status);
|
||||
|
|
@ -203,7 +202,7 @@ bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
|
|||
setLe32(cache + ((cluster << 2) & m_sectorMask), value);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -233,7 +232,7 @@ bool ExFatPartition::freeChain(uint32_t cluster) {
|
|||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -250,9 +249,9 @@ int32_t ExFatPartition::freeClusterCount() {
|
|||
}
|
||||
for (size_t i = 0; i < m_bytesPerSector; i++) {
|
||||
if (cache[i] == 0XFF) {
|
||||
usedCount+= 8;
|
||||
usedCount += 8;
|
||||
} else if (cache[i]) {
|
||||
for (uint8_t mask = 1; mask ; mask <<=1) {
|
||||
for (uint8_t mask = 1; mask; mask <<= 1) {
|
||||
if ((mask & cache[i])) {
|
||||
usedCount++;
|
||||
}
|
||||
|
|
@ -280,8 +279,8 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
mbr = reinterpret_cast<MbrSector_t*>
|
||||
(dataCachePrepare(0, FsCache::CACHE_FOR_READ));
|
||||
mbr = reinterpret_cast<MbrSector_t*>(
|
||||
dataCachePrepare(0, FsCache::CACHE_FOR_READ));
|
||||
if (!mbr) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -293,8 +292,8 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
}
|
||||
volStart = getLe32(mp->relativeSectors);
|
||||
}
|
||||
pbs = reinterpret_cast<pbs_t*>
|
||||
(dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
|
||||
pbs = reinterpret_cast<pbs_t*>(
|
||||
dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
|
||||
if (!pbs) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -322,7 +321,7 @@ bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
m_fatType = FAT_TYPE_EXFAT;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@
|
|||
* \file
|
||||
* \brief ExFatPartition include file.
|
||||
*/
|
||||
#include "../common/SysCall.h"
|
||||
#include "../common/FsBlockDevice.h"
|
||||
#include "../common/FsCache.h"
|
||||
#include "../common/FsStructs.h"
|
||||
#include "../common/SysCall.h"
|
||||
/** Set EXFAT_READ_ONLY non-zero for read only */
|
||||
#ifndef EXFAT_READ_ONLY
|
||||
#define EXFAT_READ_ONLY 0
|
||||
|
|
@ -51,7 +51,7 @@ struct DirPos_t {
|
|||
/** offset */
|
||||
uint32_t position;
|
||||
/** directory is contiguous */
|
||||
bool isContiguous;
|
||||
bool isContiguous;
|
||||
};
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -60,28 +60,26 @@ struct DirPos_t {
|
|||
*/
|
||||
class ExFatPartition {
|
||||
public:
|
||||
ExFatPartition() {}
|
||||
ExFatPartition() = default;
|
||||
/** \return the number of bytes in a cluster. */
|
||||
uint32_t bytesPerCluster() const {return m_bytesPerCluster;}
|
||||
uint32_t bytesPerCluster() const { return m_bytesPerCluster; }
|
||||
/** \return the power of two for bytesPerCluster. */
|
||||
uint8_t bytesPerClusterShift() const {
|
||||
return m_bytesPerSectorShift + m_sectorsPerClusterShift;
|
||||
}
|
||||
/** \return the number of bytes in a sector. */
|
||||
uint16_t bytesPerSector() const {return m_bytesPerSector;}
|
||||
uint16_t bytesPerSector() const { return m_bytesPerSector; }
|
||||
/** \return the power of two for bytesPerSector. */
|
||||
uint8_t bytesPerSectorShift() const {return m_bytesPerSectorShift;}
|
||||
uint8_t bytesPerSectorShift() const { return m_bytesPerSectorShift; }
|
||||
|
||||
/** Clear the cache and returns a pointer to the cache. Not for normal apps.
|
||||
* \return A pointer to the cache buffer or zero if an error occurs.
|
||||
*/
|
||||
uint8_t* cacheClear() {
|
||||
return m_dataCache.clear();
|
||||
}
|
||||
uint8_t* cacheClear() { return m_dataCache.clear(); }
|
||||
/** \return the cluster count for the partition. */
|
||||
uint32_t clusterCount() const {return m_clusterCount;}
|
||||
uint32_t clusterCount() const { return m_clusterCount; }
|
||||
/** \return the cluster heap start sector. */
|
||||
uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;}
|
||||
uint32_t clusterHeapStartSector() const { return m_clusterHeapStartSector; }
|
||||
/** End access to volume
|
||||
* \return pointer to sector size buffer for format.
|
||||
*/
|
||||
|
|
@ -90,11 +88,11 @@ class ExFatPartition {
|
|||
return cacheClear();
|
||||
}
|
||||
/** \return the FAT length in sectors */
|
||||
uint32_t fatLength() const {return m_fatLength;}
|
||||
uint32_t fatLength() const { return m_fatLength; }
|
||||
/** \return the FAT start sector number. */
|
||||
uint32_t fatStartSector() const {return m_fatStartSector;}
|
||||
uint32_t fatStartSector() const { return m_fatStartSector; }
|
||||
/** \return Type FAT_TYPE_EXFAT for exFAT partition or zero for error. */
|
||||
uint8_t fatType() const {return m_fatType;}
|
||||
uint8_t fatType() const { return m_fatType; }
|
||||
/** \return free cluster count or -1 if an error occurs. */
|
||||
int32_t freeClusterCount();
|
||||
/** Initialize a exFAT partition.
|
||||
|
|
@ -113,25 +111,25 @@ class ExFatPartition {
|
|||
*
|
||||
* \return true if busy else false.
|
||||
*/
|
||||
bool isBusy() {return m_blockDev->isBusy();}
|
||||
bool isBusy() { return m_blockDev->isBusy(); }
|
||||
/** \return the root directory start cluster number. */
|
||||
uint32_t rootDirectoryCluster() const {return m_rootDirectoryCluster;}
|
||||
uint32_t rootDirectoryCluster() const { return m_rootDirectoryCluster; }
|
||||
/** \return the root directory length. */
|
||||
uint32_t rootLength();
|
||||
/** \return the number of sectors in a cluster. */
|
||||
uint32_t sectorsPerCluster() const {return 1UL << m_sectorsPerClusterShift;}
|
||||
uint32_t sectorsPerCluster() const { return 1UL << m_sectorsPerClusterShift; }
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/** \return the power of two for sectors per cluster. */
|
||||
uint8_t sectorsPerClusterShift() const {return m_sectorsPerClusterShift;}
|
||||
uint8_t sectorsPerClusterShift() const { return m_sectorsPerClusterShift; }
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
void checkUpcase(print_t* pr);
|
||||
bool printDir(print_t* pr, ExFatFile* file);
|
||||
void dmpBitmap(print_t* pr);
|
||||
void dmpCluster(print_t* pr, uint32_t cluster,
|
||||
uint32_t offset, uint32_t count);
|
||||
void dmpCluster(print_t* pr, uint32_t cluster, uint32_t offset,
|
||||
uint32_t count);
|
||||
void dmpFat(print_t* pr, uint32_t start, uint32_t count);
|
||||
void dmpSector(print_t* pr, uint32_t sector);
|
||||
bool printVolInfo(print_t* pr);
|
||||
|
|
@ -149,7 +147,7 @@ class ExFatPartition {
|
|||
uint8_t* bitmapCachePrepare(uint32_t sector, uint8_t option) {
|
||||
#if USE_EXFAT_BITMAP_CACHE
|
||||
return m_bitmapCache.prepare(sector, option);
|
||||
#else // USE_EXFAT_BITMAP_CACHE
|
||||
#else // USE_EXFAT_BITMAP_CACHE
|
||||
return m_dataCache.prepare(sector, option);
|
||||
#endif // USE_EXFAT_BITMAP_CACHE
|
||||
}
|
||||
|
|
@ -162,19 +160,19 @@ class ExFatPartition {
|
|||
bool cacheSync() {
|
||||
#if USE_EXFAT_BITMAP_CACHE
|
||||
return m_bitmapCache.sync() && m_dataCache.sync() && syncDevice();
|
||||
#else // USE_EXFAT_BITMAP_CACHE
|
||||
#else // USE_EXFAT_BITMAP_CACHE
|
||||
return m_dataCache.sync() && syncDevice();
|
||||
#endif // USE_EXFAT_BITMAP_CACHE
|
||||
}
|
||||
void dataCacheDirty() {m_dataCache.dirty();}
|
||||
void dataCacheInvalidate() {m_dataCache.invalidate();}
|
||||
void dataCacheDirty() { m_dataCache.dirty(); }
|
||||
void dataCacheInvalidate() { m_dataCache.invalidate(); }
|
||||
uint8_t* dataCachePrepare(uint32_t sector, uint8_t option) {
|
||||
return m_dataCache.prepare(sector, option);
|
||||
}
|
||||
uint32_t dataCacheSector() {return m_dataCache.sector();}
|
||||
bool dataCacheSync() {return m_dataCache.sync();}
|
||||
uint32_t dataCacheSector() { return m_dataCache.sector(); }
|
||||
bool dataCacheSync() { return m_dataCache.sync(); }
|
||||
//----------------------------------------------------------------------------
|
||||
uint32_t clusterMask() const {return m_clusterMask;}
|
||||
uint32_t clusterMask() const { return m_clusterMask; }
|
||||
uint32_t clusterStartSector(uint32_t cluster) {
|
||||
return m_clusterHeapStartSector +
|
||||
((cluster - 2) << m_sectorsPerClusterShift);
|
||||
|
|
@ -185,10 +183,8 @@ class ExFatPartition {
|
|||
bool fatPut(uint32_t cluster, uint32_t value);
|
||||
uint32_t chainSize(uint32_t cluster);
|
||||
bool freeChain(uint32_t cluster);
|
||||
uint16_t sectorMask() const {return m_sectorMask;}
|
||||
bool syncDevice() {
|
||||
return m_blockDev->syncDevice();
|
||||
}
|
||||
uint16_t sectorMask() const { return m_sectorMask; }
|
||||
bool syncDevice() { return m_blockDev->syncDevice(); }
|
||||
bool cacheSafeRead(uint32_t sector, uint8_t* dst) {
|
||||
return m_dataCache.cacheSafeRead(sector, dst);
|
||||
}
|
||||
|
|
@ -199,7 +195,7 @@ class ExFatPartition {
|
|||
return m_dataCache.cacheSafeRead(sector, dst, count);
|
||||
}
|
||||
bool cacheSafeWrite(uint32_t sector, const uint8_t* src, size_t count) {
|
||||
return m_dataCache.cacheSafeWrite(sector, src, count);
|
||||
return m_dataCache.cacheSafeWrite(sector, src, count);
|
||||
}
|
||||
bool readSector(uint32_t sector, uint8_t* dst) {
|
||||
return m_blockDev->readSector(sector, dst);
|
||||
|
|
@ -208,14 +204,14 @@ class ExFatPartition {
|
|||
return m_blockDev->writeSector(sector, src);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
static const uint8_t m_bytesPerSectorShift = 9;
|
||||
static const uint8_t m_bytesPerSectorShift = 9;
|
||||
static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift;
|
||||
static const uint16_t m_sectorMask = m_bytesPerSector - 1;
|
||||
//----------------------------------------------------------------------------
|
||||
#if USE_EXFAT_BITMAP_CACHE
|
||||
FsCache m_bitmapCache;
|
||||
FsCache m_bitmapCache;
|
||||
#endif // USE_EXFAT_BITMAP_CACHE
|
||||
FsCache m_dataCache;
|
||||
FsCache m_dataCache;
|
||||
uint32_t m_bitmapStart;
|
||||
uint32_t m_fatStartSector;
|
||||
uint32_t m_fatLength;
|
||||
|
|
@ -225,7 +221,7 @@ class ExFatPartition {
|
|||
uint32_t m_clusterMask;
|
||||
uint32_t m_bytesPerCluster;
|
||||
FsBlockDevice* m_blockDev;
|
||||
uint8_t m_fatType = 0;
|
||||
uint8_t m_sectorsPerClusterShift;
|
||||
uint8_t m_fatType = 0;
|
||||
uint8_t m_sectorsPerClusterShift;
|
||||
};
|
||||
#endif // ExFatPartition_h
|
||||
|
|
|
|||
|
|
@ -40,6 +40,6 @@ bool ExFatVolume::chdir(const char* path) {
|
|||
m_vwd = dir;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ class ExFatVolume : public ExFatPartition {
|
|||
* \param[in] volStart Start sector of volume if part is zero.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool begin(FsBlockDevice* dev, bool setCwv = true,
|
||||
uint8_t part = 1, uint32_t volStart = 0) {
|
||||
bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1,
|
||||
uint32_t volStart = 0) {
|
||||
if (!init(dev, part, volStart)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
bool chdir(const char* path);
|
||||
|
||||
/** Change global working volume to this volume. */
|
||||
void chvol() {m_cwv = this;}
|
||||
void chvol() { m_cwv = this; }
|
||||
|
||||
/**
|
||||
* Test for the existence of a file.
|
||||
|
|
@ -117,9 +117,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr, uint8_t flags = 0) {
|
||||
return m_vwd.ls(pr, flags);
|
||||
}
|
||||
bool ls(print_t* pr, uint8_t flags = 0) { return m_vwd.ls(pr, flags); }
|
||||
/** List the contents of a directory.
|
||||
*
|
||||
* \param[in] pr Print stream for list.
|
||||
|
|
@ -223,10 +221,8 @@ class ExFatVolume : public ExFatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls() {
|
||||
return ls(&Serial);
|
||||
}
|
||||
/** List the directory contents of the volume root to Serial.
|
||||
bool ls() { return ls(&Serial); }
|
||||
/** List the directory contents of the volume root to Serial.
|
||||
*
|
||||
* \param[in] flags The inclusive OR of
|
||||
*
|
||||
|
|
@ -238,9 +234,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(uint8_t flags) {
|
||||
return ls(&Serial, flags);
|
||||
}
|
||||
bool ls(uint8_t flags) { return ls(&Serial, flags); }
|
||||
/** List the directory contents of a directory to Serial.
|
||||
*
|
||||
* \param[in] path directory to list.
|
||||
|
|
@ -265,18 +259,14 @@ class ExFatVolume : public ExFatPartition {
|
|||
* \param[in] path Path for volume working directory.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool chdir(const String& path) {
|
||||
return chdir(path.c_str());
|
||||
}
|
||||
bool chdir(const String& path) { return chdir(path.c_str()); }
|
||||
/** Test for the existence of a file in a directory
|
||||
*
|
||||
* \param[in] path Path of the file to be tested for.
|
||||
*
|
||||
* \return true if the file exists else false.
|
||||
*/
|
||||
bool exists(const String &path) {
|
||||
return exists(path.c_str());
|
||||
}
|
||||
bool exists(const String& path) { return exists(path.c_str()); }
|
||||
/** Make a subdirectory in the volume root directory.
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
|
||||
|
|
@ -285,7 +275,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool mkdir(const String &path, bool pFlag = true) {
|
||||
bool mkdir(const String& path, bool pFlag = true) {
|
||||
return mkdir(path.c_str(), pFlag);
|
||||
}
|
||||
/** open a file
|
||||
|
|
@ -294,7 +284,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
* \param[in] oflag open oflag flags.
|
||||
* \return a ExFile object.
|
||||
*/
|
||||
ExFile open(const String &path, oflag_t oflag = O_RDONLY) {
|
||||
ExFile open(const String& path, oflag_t oflag = O_RDONLY) {
|
||||
return open(path.c_str(), oflag);
|
||||
}
|
||||
/** Remove a file from the volume root directory.
|
||||
|
|
@ -303,9 +293,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const String& path) {
|
||||
return remove(path.c_str());
|
||||
}
|
||||
bool remove(const String& path) { return remove(path.c_str()); }
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
|
||||
|
|
@ -331,9 +319,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rmdir(const String& path) {
|
||||
return rmdir(path.c_str());
|
||||
}
|
||||
bool rmdir(const String& path) { return rmdir(path.c_str()); }
|
||||
/** Truncate a file to a specified length. The current file position
|
||||
* will be at the new EOF.
|
||||
*
|
||||
|
|
@ -349,8 +335,8 @@ class ExFatVolume : public ExFatPartition {
|
|||
|
||||
private:
|
||||
friend ExFatFile;
|
||||
static ExFatVolume* cwv() {return m_cwv;}
|
||||
ExFatFile* vwd() {return &m_vwd;}
|
||||
static ExFatVolume* cwv() { return m_cwv; }
|
||||
ExFatFile* vwd() { return &m_vwd; }
|
||||
static ExFatVolume* m_cwv;
|
||||
ExFatFile m_vwd;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@
|
|||
//------------------------------------------------------------------------------
|
||||
static uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i) {
|
||||
if (i < 5) {
|
||||
return getLe16(ldir->unicode1 + 2*i);
|
||||
return getLe16(ldir->unicode1 + 2 * i);
|
||||
} else if (i < 11) {
|
||||
return getLe16(ldir->unicode2 + 2*i - 10);
|
||||
return getLe16(ldir->unicode2 + 2 * (i - 5));
|
||||
} else if (i < 13) {
|
||||
return getLe16(ldir->unicode3 + 2*i - 22);
|
||||
return getLe16(ldir->unicode3 + 2 * (i - 11));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ static void printHex(print_t* pr, uint8_t w, uint16_t h) {
|
|||
static void printHex(print_t* pr, uint16_t val) {
|
||||
bool space = true;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
uint8_t h = (val >> (12 - 4*i)) & 15;
|
||||
uint8_t h = (val >> (12 - 4 * i)) & 15;
|
||||
if (h || i == 3) {
|
||||
space = false;
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@ static void printHex(print_t* pr, uint16_t val) {
|
|||
static void printHex(print_t* pr, uint32_t val) {
|
||||
bool space = true;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
uint8_t h = (val >> (28 - 4*i)) & 15;
|
||||
uint8_t h = (val >> (28 - 4 * i)) & 15;
|
||||
if (h || i == 7) {
|
||||
space = false;
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ static void printHex(print_t* pr, uint32_t val) {
|
|||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename Uint>
|
||||
template <typename Uint>
|
||||
static void printHexLn(print_t* pr, Uint val) {
|
||||
printHex(pr, val);
|
||||
pr->println();
|
||||
|
|
@ -111,8 +111,8 @@ static bool printFatDir(print_t* pr, DirFat_t* dir) {
|
|||
printHexLn(pr, dir->attributes);
|
||||
pr->print(F("caseFlags: 0X"));
|
||||
printHexLn(pr, dir->caseFlags);
|
||||
uint32_t fc = ((uint32_t)getLe16(dir->firstClusterHigh) << 16)
|
||||
| getLe16(dir->firstClusterLow);
|
||||
uint32_t fc = ((uint32_t)getLe16(dir->firstClusterHigh) << 16) |
|
||||
getLe16(dir->firstClusterLow);
|
||||
pr->print(F("firstCluster: "));
|
||||
pr->println(fc, HEX);
|
||||
pr->print(F("fileSize: "));
|
||||
|
|
@ -175,7 +175,7 @@ void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) {
|
|||
}
|
||||
pr->write(' ');
|
||||
printHex(pr, 2, h);
|
||||
text[i&15] = ' ' <= h && h < 0X7F ? h : '.';
|
||||
text[i & 15] = ' ' <= h && h < 0X7F ? h : '.';
|
||||
}
|
||||
pr->write('\r');
|
||||
pr->write('\n');
|
||||
|
|
@ -215,7 +215,7 @@ void FatPartition::dmpSector(print_t* pr, uint32_t sector, uint8_t bits) {
|
|||
return;
|
||||
}
|
||||
for (uint16_t i = 0; i < m_bytesPerSector;) {
|
||||
if (i%32 == 0) {
|
||||
if (i % 32 == 0) {
|
||||
if (i) {
|
||||
pr->println();
|
||||
}
|
||||
|
|
@ -243,7 +243,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
|
|||
}
|
||||
pr->println(F("FAT:"));
|
||||
uint32_t sector = m_fatStartSector + start;
|
||||
uint32_t cluster = nf*start;
|
||||
uint32_t cluster = nf * start;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
uint8_t* pc = fatCachePrepare(sector + i, FsCache::CACHE_FOR_READ);
|
||||
if (!pc) {
|
||||
|
|
@ -251,7 +251,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
|
|||
return;
|
||||
}
|
||||
for (size_t k = 0; k < nf; k++) {
|
||||
if (0 == cluster%8) {
|
||||
if (0 == cluster % 8) {
|
||||
if (k) {
|
||||
pr->println();
|
||||
}
|
||||
|
|
@ -259,7 +259,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
|
|||
}
|
||||
cluster++;
|
||||
pr->write(' ');
|
||||
uint32_t v = fatType() == 32 ? getLe32(pc + 4*k) : getLe16(pc + 2*k);
|
||||
uint32_t v = fatType() == 32 ? getLe32(pc + 4 * k) : getLe16(pc + 2 * k);
|
||||
printHex(pr, v);
|
||||
}
|
||||
pr->println();
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ bool FatFile::addCluster() {
|
|||
m_flags |= FILE_FLAG_DIR_DIRTY;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
m_flags |= FILE_FLAG_DIR_DIRTY;
|
||||
return m_vol->allocateCluster(m_curCluster, &m_curCluster);
|
||||
#endif // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
|
|
@ -61,7 +61,7 @@ bool FatFile::addDirCluster() {
|
|||
goto fail;
|
||||
}
|
||||
// max folder size
|
||||
if (m_curPosition >= 512UL*4095) {
|
||||
if (m_curPosition >= 512UL * 4095) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ bool FatFile::addDirCluster() {
|
|||
m_curPosition += m_vol->bytesPerCluster();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -105,7 +105,7 @@ bool FatFile::attrib(uint8_t bits) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -120,7 +120,7 @@ DirFat_t* FatFile::cacheDirEntry(uint8_t action) {
|
|||
}
|
||||
return dir + (m_dirIndex & 0XF);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return nullptr;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -137,7 +137,7 @@ bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
for (uint32_t c = m_firstCluster; ; c++) {
|
||||
for (uint32_t c = m_firstCluster;; c++) {
|
||||
uint32_t next;
|
||||
int8_t fg = m_vol->fatGet(c, &next);
|
||||
if (fg < 0) {
|
||||
|
|
@ -158,14 +158,14 @@ bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
|
|||
*bgnSector = m_vol->clusterStartSector(m_firstCluster);
|
||||
}
|
||||
if (endSector) {
|
||||
*endSector = m_vol->clusterStartSector(c)
|
||||
+ m_vol->sectorsPerCluster() - 1;
|
||||
*endSector =
|
||||
m_vol->clusterStartSector(c) + m_vol->sectorsPerCluster() - 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -178,12 +178,12 @@ bool FatFile::createContiguous(const char* path, uint32_t size) {
|
|||
return true;
|
||||
}
|
||||
close();
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::createContiguous(FatFile* dirFile,
|
||||
const char* path, uint32_t size) {
|
||||
bool FatFile::createContiguous(FatFile* dirFile, const char* path,
|
||||
uint32_t size) {
|
||||
if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -192,7 +192,7 @@ bool FatFile::createContiguous(FatFile* dirFile,
|
|||
return true;
|
||||
}
|
||||
close();
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -213,7 +213,7 @@ bool FatFile::dirEntry(DirFat_t* dst) {
|
|||
memcpy(dst, dir, sizeof(DirFat_t));
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -223,7 +223,7 @@ uint32_t FatFile::dirSize() {
|
|||
return 0;
|
||||
}
|
||||
if (isRootFixed()) {
|
||||
return FS_DIR_SIZE*m_vol->rootDirEntryCount();
|
||||
return FS_DIR_SIZE * m_vol->rootDirEntryCount();
|
||||
}
|
||||
uint16_t n = 0;
|
||||
uint32_t c = isRoot32() ? m_vol->rootDirStart() : m_firstCluster;
|
||||
|
|
@ -234,7 +234,7 @@ uint32_t FatFile::dirSize() {
|
|||
}
|
||||
n += m_vol->sectorsPerCluster();
|
||||
} while (fg);
|
||||
return 512UL*n;
|
||||
return 512UL * n;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
int FatFile::fgets(char* str, int num, char* delim) {
|
||||
|
|
@ -288,7 +288,7 @@ bool FatFile::getAccessDate(uint16_t* pdate) {
|
|||
*pdate = getLe16(dir.accessDate);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -302,7 +302,7 @@ bool FatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
|
|||
*ptime = getLe16(dir.createTime);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -316,13 +316,11 @@ bool FatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
|
|||
*ptime = getLe16(dir.modifyTime);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::isBusy() {
|
||||
return m_vol->isBusy();
|
||||
}
|
||||
bool FatFile::isBusy() { return m_vol->isBusy(); }
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
|
||||
FatName_t fname;
|
||||
|
|
@ -362,7 +360,7 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
|
|||
}
|
||||
return mkdir(parent, &fname);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -433,7 +431,7 @@ bool FatFile::mkdir(FatFile* parent, FatName_t* fname) {
|
|||
// write first sector
|
||||
return m_vol->cacheSync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -485,7 +483,7 @@ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) {
|
|||
}
|
||||
return open(dirFile, &fname, oflag);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -509,7 +507,7 @@ bool FatFile::open(FatFile* dirFile, uint16_t index, oflag_t oflag) {
|
|||
break;
|
||||
}
|
||||
if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) {
|
||||
if (!dirFile->seekSet(32UL*(index - i))) {
|
||||
if (!dirFile->seekSet(32UL * (index - i))) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -530,7 +528,7 @@ bool FatFile::open(FatFile* dirFile, uint16_t index, oflag_t oflag) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -591,8 +589,8 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex,
|
|||
m_dirSector = m_vol->cacheSectorNumber();
|
||||
|
||||
// copy first cluster number for directory fields
|
||||
firstCluster = ((uint32_t)getLe16(dir->firstClusterHigh) << 16)
|
||||
| getLe16(dir->firstClusterLow);
|
||||
firstCluster = ((uint32_t)getLe16(dir->firstClusterHigh) << 16) |
|
||||
getLe16(dir->firstClusterLow);
|
||||
|
||||
if (oflag & O_TRUNC) {
|
||||
if (firstCluster && !m_vol->freeChain(firstCluster)) {
|
||||
|
|
@ -611,7 +609,7 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex,
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_attributes = FILE_ATTR_CLOSED;
|
||||
m_flags = 0;
|
||||
return false;
|
||||
|
|
@ -638,7 +636,7 @@ bool FatFile::openCwd() {
|
|||
rewind();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -655,7 +653,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
|
|||
}
|
||||
while (1) {
|
||||
// read entry into cache
|
||||
index = dirFile->curPosition()/FS_DIR_SIZE;
|
||||
index = dirFile->curPosition() / FS_DIR_SIZE;
|
||||
DirFat_t* dir = dirFile->readDirCache();
|
||||
if (!dir) {
|
||||
if (dirFile->getError()) {
|
||||
|
|
@ -691,7 +689,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
|
|||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -706,34 +704,34 @@ bool FatFile::openRoot(FatVolume* vol) {
|
|||
m_vol = vol;
|
||||
switch (vol->fatType()) {
|
||||
#if FAT12_SUPPORT
|
||||
case 12:
|
||||
case 12:
|
||||
#endif // FAT12_SUPPORT
|
||||
case 16:
|
||||
m_attributes = FILE_ATTR_ROOT_FIXED;
|
||||
break;
|
||||
case 16:
|
||||
m_attributes = FILE_ATTR_ROOT_FIXED;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
m_attributes = FILE_ATTR_ROOT32;
|
||||
break;
|
||||
case 32:
|
||||
m_attributes = FILE_ATTR_ROOT32;
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
default:
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
// read only
|
||||
m_flags = FILE_FLAG_READ;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
int FatFile::peek() {
|
||||
uint32_t curPosition = m_curPosition;
|
||||
uint32_t curCluster = m_curCluster;
|
||||
uint32_t saveCurPosition = m_curPosition;
|
||||
uint32_t saveCurCluster = m_curCluster;
|
||||
int c = read();
|
||||
m_curPosition = curPosition;
|
||||
m_curCluster = curCluster;
|
||||
m_curPosition = saveCurPosition;
|
||||
m_curCluster = saveCurCluster;
|
||||
return c;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -754,13 +752,13 @@ bool FatFile::preAllocate(uint32_t length) {
|
|||
#if USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
// Mark contiguous and insure sync() will update dir entry
|
||||
m_flags |= FILE_FLAG_PREALLOCATE | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
// insure sync() will update dir entry
|
||||
m_flags |= FILE_FLAG_DIR_DIRTY;
|
||||
#endif // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
return sync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -785,7 +783,7 @@ int FatFile::read(void* buf, size_t nbyte) {
|
|||
}
|
||||
} else if (isRootFixed()) {
|
||||
uint16_t tmp16 =
|
||||
FS_DIR_SIZE*m_vol->m_rootDirEntryCount - (uint16_t)m_curPosition;
|
||||
FS_DIR_SIZE * m_vol->m_rootDirEntryCount - (uint16_t)m_curPosition;
|
||||
if (nbyte > tmp16) {
|
||||
nbyte = tmp16;
|
||||
}
|
||||
|
|
@ -795,8 +793,8 @@ int FatFile::read(void* buf, size_t nbyte) {
|
|||
size_t n;
|
||||
offset = m_curPosition & m_vol->sectorMask(); // offset in sector
|
||||
if (isRootFixed()) {
|
||||
sector = m_vol->rootDirStart()
|
||||
+ (m_curPosition >> m_vol->bytesPerSectorShift());
|
||||
sector = m_vol->rootDirStart() +
|
||||
(m_curPosition >> m_vol->bytesPerSectorShift());
|
||||
} else {
|
||||
sectorOfCluster = m_vol->sectorOfCluster(m_curPosition);
|
||||
if (offset == 0 && sectorOfCluster == 0) {
|
||||
|
|
@ -826,8 +824,8 @@ int FatFile::read(void* buf, size_t nbyte) {
|
|||
}
|
||||
sector = m_vol->clusterStartSector(m_curCluster) + sectorOfCluster;
|
||||
}
|
||||
if (offset != 0 || toRead < m_vol->bytesPerSector()
|
||||
|| sector == m_vol->cacheSectorNumber()) {
|
||||
if (offset != 0 || toRead < m_vol->bytesPerSector() ||
|
||||
sector == m_vol->cacheSectorNumber()) {
|
||||
// amount to be read from current sector
|
||||
n = m_vol->bytesPerSector() - offset;
|
||||
if (n > toRead) {
|
||||
|
|
@ -842,7 +840,7 @@ int FatFile::read(void* buf, size_t nbyte) {
|
|||
uint8_t* src = pc + offset;
|
||||
memcpy(dst, src, n);
|
||||
#if USE_MULTI_SECTOR_IO
|
||||
} else if (toRead >= 2*m_vol->bytesPerSector()) {
|
||||
} else if (toRead >= 2 * m_vol->bytesPerSector()) {
|
||||
uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
|
||||
if (!isRootFixed()) {
|
||||
uint32_t mb = m_vol->sectorsPerCluster() - sectorOfCluster;
|
||||
|
|
@ -870,20 +868,19 @@ int FatFile::read(void* buf, size_t nbyte) {
|
|||
}
|
||||
return nbyte - toRead;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_error |= READ_ERROR;
|
||||
return -1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
int8_t FatFile::readDir(DirFat_t* dir) {
|
||||
int16_t n;
|
||||
// if not a directory file or miss-positioned return an error
|
||||
if (!isDir() || (0X1F & m_curPosition)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
n = read(dir, sizeof(DirFat_t));
|
||||
int16_t n = read(dir, sizeof(DirFat_t));
|
||||
if (n != sizeof(DirFat_t)) {
|
||||
return n == 0 ? 0 : -1;
|
||||
}
|
||||
|
|
@ -910,7 +907,7 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) {
|
|||
|
||||
if (i == 0 || !skipReadOk) {
|
||||
int8_t n = read(&n, 1);
|
||||
if (n != 1) {
|
||||
if (n != 1) {
|
||||
if (n != 0) {
|
||||
DBG_FAIL_MACRO;
|
||||
}
|
||||
|
|
@ -923,7 +920,7 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) {
|
|||
// return pointer to entry
|
||||
return reinterpret_cast<DirFat_t*>(m_vol->cacheAddress()) + i;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return nullptr;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -935,7 +932,7 @@ bool FatFile::remove(const char* path) {
|
|||
}
|
||||
return file.remove();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1031,7 +1028,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
|
|||
}
|
||||
// store new dot dot
|
||||
sector = m_vol->clusterStartSector(m_firstCluster);
|
||||
uint8_t* pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
|
||||
pc = m_vol->dataCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
|
||||
dir = reinterpret_cast<DirFat_t*>(pc);
|
||||
if (!dir) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -1049,7 +1046,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
|
|||
}
|
||||
return m_vol->cacheSync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1091,7 +1088,7 @@ bool FatFile::rmdir() {
|
|||
m_flags |= FILE_FLAG_WRITE;
|
||||
return remove();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1105,7 +1102,7 @@ bool FatFile::rmRfStar() {
|
|||
rewind();
|
||||
while (1) {
|
||||
// remember position
|
||||
index = m_curPosition/FS_DIR_SIZE;
|
||||
index = m_curPosition / FS_DIR_SIZE;
|
||||
|
||||
DirFat_t* dir = readDirCache();
|
||||
if (!dir) {
|
||||
|
|
@ -1150,8 +1147,8 @@ bool FatFile::rmRfStar() {
|
|||
}
|
||||
}
|
||||
// position to next entry if required
|
||||
if (m_curPosition != (32UL*(index + 1))) {
|
||||
if (!seekSet(32UL*(index + 1))) {
|
||||
if (m_curPosition != (32UL * (index + 1))) {
|
||||
if (!seekSet(32UL * (index + 1))) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -1166,7 +1163,7 @@ bool FatFile::rmRfStar() {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1194,7 +1191,7 @@ bool FatFile::seekSet(uint32_t pos) {
|
|||
goto fail;
|
||||
}
|
||||
} else if (isRootFixed()) {
|
||||
if (pos <= FS_DIR_SIZE*m_vol->rootDirEntryCount()) {
|
||||
if (pos <= FS_DIR_SIZE * m_vol->rootDirEntryCount()) {
|
||||
goto done;
|
||||
}
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -1225,12 +1222,12 @@ bool FatFile::seekSet(uint32_t pos) {
|
|||
}
|
||||
}
|
||||
|
||||
done:
|
||||
done:
|
||||
m_curPosition = pos;
|
||||
m_flags &= ~FILE_FLAG_PREALLOCATE;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_curCluster = tmp;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1272,27 +1269,20 @@ bool FatFile::sync() {
|
|||
}
|
||||
DBG_FAIL_MACRO;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
m_error |= WRITE_ERROR;
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
|
||||
uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
uint8_t day, uint8_t hour, uint8_t minute,
|
||||
uint8_t second) {
|
||||
uint16_t dirDate;
|
||||
uint16_t dirTime;
|
||||
DirFat_t* dir;
|
||||
|
||||
if (!isFile()
|
||||
|| year < 1980
|
||||
|| year > 2107
|
||||
|| month < 1
|
||||
|| month > 12
|
||||
|| day < 1
|
||||
|| day > 31
|
||||
|| hour > 23
|
||||
|| minute > 59
|
||||
|| second > 59) {
|
||||
if (!isFile() || year < 1980 || year > 2107 || month < 1 || month > 12 ||
|
||||
day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -1323,7 +1313,7 @@ bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
|
|||
}
|
||||
return m_vol->cacheSync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1335,7 +1325,7 @@ bool FatFile::truncate() {
|
|||
goto fail;
|
||||
}
|
||||
if (m_firstCluster == 0) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
if (m_curCluster) {
|
||||
toFree = 0;
|
||||
|
|
@ -1367,7 +1357,7 @@ bool FatFile::truncate() {
|
|||
m_flags |= FILE_FLAG_DIR_DIRTY;
|
||||
return sync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -1414,7 +1404,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
int8_t fg = m_vol->fatGet(m_curCluster, &m_curCluster);
|
||||
if (fg < 0) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -1442,8 +1432,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
|
|||
}
|
||||
}
|
||||
// sector for data write
|
||||
uint32_t sector = m_vol->clusterStartSector(m_curCluster)
|
||||
+ sectorOfCluster;
|
||||
uint32_t sector = m_vol->clusterStartSector(m_curCluster) + sectorOfCluster;
|
||||
|
||||
if (sectorOffset != 0 || nToWrite < m_vol->bytesPerSector()) {
|
||||
// partial sector - must use cache
|
||||
|
|
@ -1455,7 +1444,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
|
|||
}
|
||||
|
||||
if (sectorOffset == 0 &&
|
||||
(m_curPosition >= m_fileSize || m_flags & FILE_FLAG_PREALLOCATE)) {
|
||||
(m_curPosition >= m_fileSize || m_flags & FILE_FLAG_PREALLOCATE)) {
|
||||
// start of new sector don't need to read into cache
|
||||
cacheOption = FsCache::CACHE_RESERVE_FOR_WRITE;
|
||||
} else {
|
||||
|
|
@ -1477,7 +1466,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
|
|||
}
|
||||
}
|
||||
#if USE_MULTI_SECTOR_IO
|
||||
} else if (nToWrite >= 2*m_vol->bytesPerSector()) {
|
||||
} else if (nToWrite >= 2 * m_vol->bytesPerSector()) {
|
||||
// use multiple sector write command
|
||||
uint32_t maxSectors = m_vol->sectorsPerCluster() - sectorOfCluster;
|
||||
uint32_t nSector = nToWrite >> m_vol->bytesPerSectorShift();
|
||||
|
|
@ -1512,7 +1501,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
|
|||
}
|
||||
return nbyte;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
// return for write error
|
||||
m_error |= WRITE_ERROR;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@
|
|||
* \file
|
||||
* \brief FatFile class
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../common/FmtNumber.h"
|
||||
#include "../common/FsApiConstants.h"
|
||||
#include "../common/FsDateTime.h"
|
||||
|
|
@ -38,28 +39,6 @@
|
|||
#include "FatPartition.h"
|
||||
class FatVolume;
|
||||
//------------------------------------------------------------------------------
|
||||
// Stuff to store strings in AVR flash.
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#else // __AVR__
|
||||
#ifndef PSTR
|
||||
/** store literal string in flash for ARM */
|
||||
#define PSTR(x) (x)
|
||||
#endif // PSTR
|
||||
#ifndef pgm_read_byte
|
||||
/** read 8-bits from flash for ARM */
|
||||
#define pgm_read_byte(addr) (*(const unsigned char*)(addr))
|
||||
#endif // pgm_read_byte
|
||||
#ifndef pgm_read_word
|
||||
/** read 16-bits from flash for ARM */
|
||||
#define pgm_read_word(addr) (*(const uint16_t*)(addr))
|
||||
#endif // pgm_read_word
|
||||
#ifndef PROGMEM
|
||||
/** store in flash for ARM */
|
||||
#define PROGMEM
|
||||
#endif // PROGMEM
|
||||
#endif // __AVR__
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct FatPos_t
|
||||
* \brief Internal type for file position - do not use in user apps.
|
||||
|
|
@ -105,7 +84,7 @@ class FatSfn_t {
|
|||
#if USE_LONG_FILE_NAMES
|
||||
/** Internal class for file names */
|
||||
typedef FatLfn_t FatName_t;
|
||||
#else // USE_LONG_FILE_NAMES
|
||||
#else // USE_LONG_FILE_NAMES
|
||||
/** Internal class for file names */
|
||||
typedef FatSfn_t FatName_t;
|
||||
#endif // USE_LONG_FILE_NAMES
|
||||
|
|
@ -116,14 +95,11 @@ const uint8_t FNAME_FLAG_LOST_CHARS = 0X01;
|
|||
const uint8_t FNAME_FLAG_MIXED_CASE = 0X02;
|
||||
/** LFN entries are required for file name. */
|
||||
const uint8_t FNAME_FLAG_NEED_LFN =
|
||||
FNAME_FLAG_LOST_CHARS | FNAME_FLAG_MIXED_CASE;
|
||||
FNAME_FLAG_LOST_CHARS | FNAME_FLAG_MIXED_CASE;
|
||||
/** Filename base-name is all lower case */
|
||||
const uint8_t FNAME_FLAG_LC_BASE = FAT_CASE_LC_BASE;
|
||||
/** Filename extension is all lower case. */
|
||||
const uint8_t FNAME_FLAG_LC_EXT = FAT_CASE_LC_EXT;
|
||||
#if FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT)
|
||||
#error FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT)
|
||||
#endif // FNAME_FLAG_NEED_LFN & (FAT_CASE_LC_BASE || FAT_CASE_LC_EXT)
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class FatFile
|
||||
|
|
@ -140,9 +116,7 @@ class FatFile {
|
|||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
|
||||
*/
|
||||
FatFile(const char* path, oflag_t oflag) {
|
||||
open(path, oflag);
|
||||
}
|
||||
FatFile(const char* path, oflag_t oflag) { open(path, oflag); }
|
||||
#if DESTRUCTOR_CLOSES_FILE
|
||||
/** Destructor */
|
||||
~FatFile() {
|
||||
|
|
@ -155,7 +129,7 @@ class FatFile {
|
|||
*
|
||||
* \return true if a file is open.
|
||||
*/
|
||||
operator bool() const {return isOpen();}
|
||||
operator bool() const { return isOpen(); }
|
||||
/**
|
||||
* \return user settable file attributes for success else -1.
|
||||
*/
|
||||
|
|
@ -190,13 +164,9 @@ class FatFile {
|
|||
return isFile() ? fileSize() - curPosition() : 0;
|
||||
}
|
||||
/** Clear all error bits. */
|
||||
void clearError() {
|
||||
m_error = 0;
|
||||
}
|
||||
void clearError() { m_error = 0; }
|
||||
/** Set writeError to zero */
|
||||
void clearWriteError() {
|
||||
m_error &= ~WRITE_ERROR;
|
||||
}
|
||||
void clearWriteError() { m_error &= ~WRITE_ERROR; }
|
||||
/** Close a file and force cached data and directory information
|
||||
* to be written to the storage device.
|
||||
*
|
||||
|
|
@ -221,8 +191,7 @@ class FatFile {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool createContiguous(FatFile* dirFile,
|
||||
const char* path, uint32_t size);
|
||||
bool createContiguous(FatFile* dirFile, const char* path, uint32_t size);
|
||||
/** Create and open a new contiguous file of a specified size.
|
||||
*
|
||||
* \param[in] path A path with a valid file name.
|
||||
|
|
@ -232,10 +201,10 @@ class FatFile {
|
|||
*/
|
||||
bool createContiguous(const char* path, uint32_t size);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster() const {return m_curCluster;}
|
||||
uint32_t curCluster() const { return m_curCluster; }
|
||||
|
||||
/** \return The current position for a file or directory. */
|
||||
uint32_t curPosition() const {return m_curPosition;}
|
||||
uint32_t curPosition() const { return m_curPosition; }
|
||||
/** Return a file's directory entry.
|
||||
*
|
||||
* \param[out] dir Location for return of the file's directory entry.
|
||||
|
|
@ -244,7 +213,7 @@ class FatFile {
|
|||
*/
|
||||
bool dirEntry(DirFat_t* dir);
|
||||
/** \return Directory entry index. */
|
||||
uint16_t dirIndex() const {return m_dirIndex;}
|
||||
uint16_t dirIndex() const { return m_dirIndex; }
|
||||
/** \return The number of bytes allocated to a directory or zero
|
||||
* if an error occurs.
|
||||
*/
|
||||
|
|
@ -297,13 +266,13 @@ class FatFile {
|
|||
*/
|
||||
int fgets(char* str, int num, char* delim = nullptr);
|
||||
/** \return The total number of bytes in a file. */
|
||||
uint32_t fileSize() const {return m_fileSize;}
|
||||
uint32_t fileSize() const { return m_fileSize; }
|
||||
/** \return first sector of file or zero for empty file. */
|
||||
uint32_t firstBlock() const {return firstSector();}
|
||||
uint32_t firstBlock() const { return firstSector(); }
|
||||
/** \return Address of first sector or zero for empty file. */
|
||||
uint32_t firstSector() const;
|
||||
/** Arduino name for sync() */
|
||||
void flush() {sync();}
|
||||
void flush() { sync(); }
|
||||
/** set position for streams
|
||||
* \param[in] pos struct with value for new position
|
||||
*/
|
||||
|
|
@ -340,7 +309,7 @@ class FatFile {
|
|||
*/
|
||||
bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime);
|
||||
/** \return All error bits. */
|
||||
uint8_t getError() const {return m_error;}
|
||||
uint8_t getError() const { return m_error; }
|
||||
/** Get a file's modify date and time.
|
||||
*
|
||||
* \param[out] pdate Packed date for directory entry.
|
||||
|
|
@ -388,9 +357,7 @@ class FatFile {
|
|||
*/
|
||||
size_t getSFN(char* name, size_t size);
|
||||
/** \return value of writeError */
|
||||
bool getWriteError() const {
|
||||
return isOpen() ? m_error & WRITE_ERROR : true;
|
||||
}
|
||||
bool getWriteError() const { return isOpen() ? m_error & WRITE_ERROR : true; }
|
||||
/**
|
||||
* Check for device busy.
|
||||
*
|
||||
|
|
@ -398,37 +365,37 @@ class FatFile {
|
|||
*/
|
||||
bool isBusy();
|
||||
#if USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
/** \return True if the file is contiguous. */
|
||||
bool isContiguous() const {return m_flags & FILE_FLAG_CONTIGUOUS;}
|
||||
/** \return True if the file is contiguous. */
|
||||
bool isContiguous() const { return m_flags & FILE_FLAG_CONTIGUOUS; }
|
||||
#endif // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
/** \return True if this is a directory. */
|
||||
bool isDir() const {return m_attributes & FILE_ATTR_DIR;}
|
||||
bool isDir() const { return m_attributes & FILE_ATTR_DIR; }
|
||||
/** \return True if this is a normal file. */
|
||||
bool isFile() const {return m_attributes & FILE_ATTR_FILE;}
|
||||
bool isFile() const { return m_attributes & FILE_ATTR_FILE; }
|
||||
/** \return True if this is a normal file or sub-directory. */
|
||||
bool isFileOrSubDir() const {return isFile() || isSubDir();}
|
||||
bool isFileOrSubDir() const { return isFile() || isSubDir(); }
|
||||
/** \return True if this is a hidden file. */
|
||||
bool isHidden() const {return m_attributes & FS_ATTRIB_HIDDEN;}
|
||||
bool isHidden() const { return m_attributes & FS_ATTRIB_HIDDEN; }
|
||||
/** \return true if this file has a Long File Name. */
|
||||
bool isLFN() const {return m_lfnOrd;}
|
||||
bool isLFN() const { return m_lfnOrd; }
|
||||
/** \return True if this is an open file/directory. */
|
||||
bool isOpen() const {return m_attributes;}
|
||||
bool isOpen() const { return m_attributes; }
|
||||
/** \return True file is readable. */
|
||||
bool isReadable() const {return m_flags & FILE_FLAG_READ;}
|
||||
bool isReadable() const { return m_flags & FILE_FLAG_READ; }
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {return m_attributes & FS_ATTRIB_READ_ONLY;}
|
||||
bool isReadOnly() const { return m_attributes & FS_ATTRIB_READ_ONLY; }
|
||||
/** \return True if this is the root directory. */
|
||||
bool isRoot() const {return m_attributes & FILE_ATTR_ROOT;}
|
||||
bool isRoot() const { return m_attributes & FILE_ATTR_ROOT; }
|
||||
/** \return True if this is the FAT32 root directory. */
|
||||
bool isRoot32() const {return m_attributes & FILE_ATTR_ROOT32;}
|
||||
bool isRoot32() const { return m_attributes & FILE_ATTR_ROOT32; }
|
||||
/** \return True if this is the FAT12 of FAT16 root directory. */
|
||||
bool isRootFixed() const {return m_attributes & FILE_ATTR_ROOT_FIXED;}
|
||||
bool isRootFixed() const { return m_attributes & FILE_ATTR_ROOT_FIXED; }
|
||||
/** \return True if this is a sub-directory. */
|
||||
bool isSubDir() const {return m_attributes & FILE_ATTR_SUBDIR;}
|
||||
bool isSubDir() const { return m_attributes & FILE_ATTR_SUBDIR; }
|
||||
/** \return True if this is a system file. */
|
||||
bool isSystem() const {return m_attributes & FS_ATTRIB_SYSTEM;}
|
||||
bool isSystem() const { return m_attributes & FS_ATTRIB_SYSTEM; }
|
||||
/** \return True file is writable. */
|
||||
bool isWritable() const {return m_flags & FILE_FLAG_WRITE;}
|
||||
bool isWritable() const { return m_flags & FILE_FLAG_WRITE; }
|
||||
/** List directory contents.
|
||||
*
|
||||
* \param[in] pr Print stream for list.
|
||||
|
|
@ -553,7 +520,7 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(const char* path, oflag_t oflag = O_RDONLY);
|
||||
/** Open the current working directory.
|
||||
/** Open the current working directory.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
|
|
@ -615,9 +582,7 @@ class FatFile {
|
|||
*
|
||||
* \return The number of characters printed.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr) {
|
||||
return printAccessDate(pr);
|
||||
}
|
||||
size_t printAccessDateTime(print_t* pr) { return printAccessDate(pr); }
|
||||
/** Print a file's creation date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
|
|
@ -676,7 +641,7 @@ class FatFile {
|
|||
template <typename Type>
|
||||
size_t printField(Type value, char term) {
|
||||
char sign = 0;
|
||||
char buf[3*sizeof(Type) + 3];
|
||||
char buf[3 * sizeof(Type) + 3];
|
||||
char* str = buf + sizeof(buf);
|
||||
|
||||
if (term) {
|
||||
|
|
@ -819,9 +784,7 @@ class FatFile {
|
|||
*/
|
||||
bool rename(FatFile* dirFile, const char* newPath);
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind() {
|
||||
seekSet(0);
|
||||
}
|
||||
void rewind() { seekSet(0); }
|
||||
/** Remove a directory file.
|
||||
*
|
||||
* The directory file will be removed only if it is empty and is not the
|
||||
|
|
@ -854,9 +817,7 @@ class FatFile {
|
|||
* \param[in] offset The new position in bytes from the current position.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekCur(int32_t offset) {
|
||||
return seekSet(m_curPosition + offset);
|
||||
}
|
||||
bool seekCur(int32_t offset) { return seekSet(m_curPosition + offset); }
|
||||
/** Set the files position to end-of-file + \a offset. See seekSet().
|
||||
* Can't be used for directory files since file size is not defined.
|
||||
* \param[in] offset The new position in bytes from end-of-file.
|
||||
|
|
@ -927,24 +888,18 @@ class FatFile {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool truncate(uint32_t length) {
|
||||
return seekSet(length) && truncate();
|
||||
}
|
||||
bool truncate(uint32_t length) { return seekSet(length) && truncate(); }
|
||||
/** Write a string to a file. Used by the Arduino Print class.
|
||||
* \param[in] str Pointer to the string.
|
||||
* Use getWriteError to check for errors.
|
||||
* \return count of characters written for success or -1 for failure.
|
||||
*/
|
||||
size_t write(const char* str) {
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
size_t write(const char* str) { return write(str, strlen(str)); }
|
||||
/** Write a single byte.
|
||||
* \param[in] b The byte to be written.
|
||||
* \return +1 for success or -1 for failure.
|
||||
*/
|
||||
size_t write(uint8_t b) {
|
||||
return write(&b, 1);
|
||||
}
|
||||
size_t write(uint8_t b) { return write(&b, 1); }
|
||||
/** Write data to an open file.
|
||||
*
|
||||
* \note Data is moved to the cache but may not be written to the
|
||||
|
|
@ -973,16 +928,12 @@ class FatFile {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(uint8_t flags = 0) {
|
||||
return ls(&Serial, flags);
|
||||
}
|
||||
bool ls(uint8_t flags = 0) { return ls(&Serial, flags); }
|
||||
/** Print a file's name.
|
||||
*
|
||||
* \return length for success or zero for failure.
|
||||
*/
|
||||
size_t printName() {
|
||||
return FatFile::printName(&Serial);
|
||||
}
|
||||
size_t printName() { return FatFile::printName(&Serial); }
|
||||
#endif // ENABLE_ARDUINO_SERIAL
|
||||
|
||||
private:
|
||||
|
|
@ -1000,8 +951,7 @@ class FatFile {
|
|||
/** A FAT32 root directory */
|
||||
static const uint8_t FILE_ATTR_ROOT32 = 0X80;
|
||||
/** Entry is for root. */
|
||||
static const uint8_t FILE_ATTR_ROOT =
|
||||
FILE_ATTR_ROOT_FIXED | FILE_ATTR_ROOT32;
|
||||
static const uint8_t FILE_ATTR_ROOT = FILE_ATTR_ROOT_FIXED | FILE_ATTR_ROOT32;
|
||||
/** Directory type bits */
|
||||
static const uint8_t FILE_ATTR_DIR = FILE_ATTR_SUBDIR | FILE_ATTR_ROOT;
|
||||
|
||||
|
|
@ -1010,16 +960,16 @@ class FatFile {
|
|||
bool addCluster();
|
||||
bool addDirCluster();
|
||||
DirFat_t* cacheDir(uint16_t index) {
|
||||
return seekSet(32UL*index) ? readDirCache() : nullptr;
|
||||
return seekSet(32UL * index) ? readDirCache() : nullptr;
|
||||
}
|
||||
DirFat_t* cacheDirEntry(uint8_t action);
|
||||
bool cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd);
|
||||
bool createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd);
|
||||
uint16_t getLfnChar(DirLfn_t* ldir, uint8_t i);
|
||||
uint8_t lfnChecksum(uint8_t* name) {
|
||||
uint8_t lfnChecksum(const uint8_t* name) {
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < 11; i++) {
|
||||
sum = (((sum & 1) << 7) | (sum >> 1)) + name[i];
|
||||
sum = (((sum & 1) << 7) | (sum >> 1)) + name[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
|
@ -1043,26 +993,26 @@ class FatFile {
|
|||
// treat curPosition as valid length.
|
||||
static const uint8_t FILE_FLAG_PREALLOCATE = 0X20;
|
||||
// file is contiguous
|
||||
static const uint8_t FILE_FLAG_CONTIGUOUS = 0X40;
|
||||
static const uint8_t FILE_FLAG_CONTIGUOUS = 0X40;
|
||||
// sync of directory entry required
|
||||
static const uint8_t FILE_FLAG_DIR_DIRTY = 0X80;
|
||||
|
||||
// private data
|
||||
static const uint8_t WRITE_ERROR = 0X1;
|
||||
static const uint8_t READ_ERROR = 0X2;
|
||||
static const uint8_t READ_ERROR = 0X2;
|
||||
|
||||
uint8_t m_attributes = FILE_ATTR_CLOSED;
|
||||
uint8_t m_error = 0; // Error bits.
|
||||
uint8_t m_flags = 0; // See above for definition of m_flags bits
|
||||
uint8_t m_lfnOrd;
|
||||
uint16_t m_dirIndex; // index of directory entry in dir file
|
||||
FatVolume* m_vol; // volume where file is located
|
||||
uint32_t m_dirCluster;
|
||||
uint32_t m_curCluster; // cluster for current file position
|
||||
uint32_t m_curPosition; // current file position
|
||||
uint32_t m_dirSector; // sector for this files directory entry
|
||||
uint32_t m_fileSize; // file size in bytes
|
||||
uint32_t m_firstCluster; // first cluster of file
|
||||
uint8_t m_attributes = FILE_ATTR_CLOSED;
|
||||
uint8_t m_error = 0; // Error bits.
|
||||
uint8_t m_flags = 0; // See above for definition of m_flags bits
|
||||
uint8_t m_lfnOrd;
|
||||
uint16_t m_dirIndex; // index of directory entry in dir file
|
||||
FatVolume* m_vol; // volume where file is located
|
||||
uint32_t m_dirCluster;
|
||||
uint32_t m_curCluster; // cluster for current file position
|
||||
uint32_t m_curPosition; // current file position
|
||||
uint32_t m_dirSector; // sector for this files directory entry
|
||||
uint32_t m_fileSize; // file size in bytes
|
||||
uint32_t m_firstCluster; // first cluster of file
|
||||
};
|
||||
|
||||
#include "../common/ArduinoFiles.h"
|
||||
|
|
@ -1072,7 +1022,7 @@ class FatFile {
|
|||
*/
|
||||
class File32 : public StreamFile<FatFile, uint32_t> {
|
||||
public:
|
||||
/** Opens the next file or folder in a directory.
|
||||
/** Opens the next file or folder in a directory.
|
||||
*
|
||||
* \param[in] oflag open flags.
|
||||
* \return a FatStream object.
|
||||
|
|
|
|||
|
|
@ -24,23 +24,17 @@
|
|||
*/
|
||||
#define DBG_FILE "FatFileLFN.cpp"
|
||||
#include "../common/DebugMacros.h"
|
||||
#include "../common/upcase.h"
|
||||
#include "../common/FsUtf.h"
|
||||
#include "../common/upcase.h"
|
||||
#include "FatLib.h"
|
||||
#if USE_LONG_FILE_NAMES
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isLower(char c) {
|
||||
return 'a' <= c && c <= 'z';
|
||||
}
|
||||
static bool isLower(char c) { return 'a' <= c && c <= 'z'; }
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isUpper(char c) {
|
||||
return 'A' <= c && c <= 'Z';
|
||||
}
|
||||
static bool isUpper(char c) { return 'A' <= c && c <= 'Z'; }
|
||||
//------------------------------------------------------------------------------
|
||||
// A bit smaller than toupper in AVR 328.
|
||||
inline char toUpper(char c) {
|
||||
return isLower(c) ? c - 'a' + 'A' : c;
|
||||
}
|
||||
inline char toUpper(char c) { return isLower(c) ? c - 'a' + 'A' : c; }
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Store a 16-bit long file name character.
|
||||
|
|
@ -51,24 +45,13 @@ inline char toUpper(char c) {
|
|||
*/
|
||||
static void putLfnChar(DirLfn_t* ldir, uint8_t i, uint16_t c) {
|
||||
if (i < 5) {
|
||||
setLe16(ldir->unicode1 + 2*i, c);
|
||||
setLe16(ldir->unicode1 + 2 * i, c);
|
||||
} else if (i < 11) {
|
||||
setLe16(ldir->unicode2 + 2*i -10, c);
|
||||
setLe16(ldir->unicode2 + 2 * (i - 5), c);
|
||||
} else if (i < 13) {
|
||||
setLe16(ldir->unicode3 + 2*i - 22, c);
|
||||
setLe16(ldir->unicode3 + 2 * (i - 11), c);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Daniel Bernstein University of Illinois at Chicago.
|
||||
// Original had + instead of ^
|
||||
__attribute__((unused))
|
||||
static uint16_t Bernstein(const char* bgn, const char* end, uint16_t hash) {
|
||||
while (bgn < end) {
|
||||
// hash = hash * 33 ^ str[i];
|
||||
hash = ((hash << 5) + hash) ^ (*bgn++);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
//==============================================================================
|
||||
bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
|
||||
FatFile dir = *this;
|
||||
|
|
@ -95,7 +78,7 @@ bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
|
|||
if (toUpcase(u) != toUpcase(cp)) {
|
||||
return false;
|
||||
}
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
if (u > 0X7F || toUpper(u) != toUpper(fname->getch())) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -104,7 +87,7 @@ bool FatFile::cmpName(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -141,13 +124,13 @@ bool FatFile::createLFN(uint16_t index, FatLfn_t* fname, uint8_t lfnOrd) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::makeSFN(FatLfn_t* fname) {
|
||||
bool is83;
|
||||
// char c;
|
||||
// char c;
|
||||
uint8_t c;
|
||||
uint8_t bit = FAT_CASE_LC_BASE;
|
||||
uint8_t lc = 0;
|
||||
|
|
@ -170,15 +153,17 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
|
|||
// Not 8.3 if starts with dot.
|
||||
is83 = *ptr == '.' ? false : true;
|
||||
// Skip leading dots.
|
||||
for (; *ptr == '.'; ptr++) {}
|
||||
for (; *ptr == '.'; ptr++) {
|
||||
}
|
||||
// Find last dot.
|
||||
for (dot = end - 1; dot > ptr && *dot != '.'; dot--) {}
|
||||
for (dot = end - 1; dot > ptr && *dot != '.'; dot--) {
|
||||
}
|
||||
|
||||
for (; ptr < end; ptr++) {
|
||||
c = *ptr;
|
||||
if (c == '.' && ptr == dot) {
|
||||
in = 10; // Max index for full 8.3 name.
|
||||
i = 8; // Place for extension.
|
||||
in = 10; // Max index for full 8.3 name.
|
||||
i = 8; // Place for extension.
|
||||
bit = FAT_CASE_LC_EXT; // bit for extension.
|
||||
} else {
|
||||
if (sfnReservedChar(c)) {
|
||||
|
|
@ -192,7 +177,7 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
|
|||
if (i > in) {
|
||||
is83 = false;
|
||||
if (in == 10 || ptr > dot) {
|
||||
// Done - extension longer than three characters or no extension.
|
||||
// Done - extension longer than three characters or no extension.
|
||||
break;
|
||||
}
|
||||
// Skip to dot.
|
||||
|
|
@ -216,7 +201,7 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
|
|||
goto fail;
|
||||
}
|
||||
if (is83) {
|
||||
fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc;
|
||||
fname->flags = (lc & uc) ? FNAME_FLAG_MIXED_CASE : lc;
|
||||
} else {
|
||||
fname->flags = FNAME_FLAG_LOST_CHARS;
|
||||
fname->sfn[fname->seqPos] = '~';
|
||||
|
|
@ -224,7 +209,7 @@ bool FatFile::makeSFN(FatLfn_t* fname) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -238,17 +223,13 @@ bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
|
|||
DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');
|
||||
|
||||
for (uint8_t seq = FIRST_HASH_SEQ; seq < 100; seq++) {
|
||||
DBG_WARN_IF(seq > FIRST_HASH_SEQ);
|
||||
#ifdef USE_LFN_HASH
|
||||
hex = Bernstein(fname->begin, fname->end, seq);
|
||||
#else
|
||||
DBG_WARN_IF(seq > FIRST_HASH_SEQ);
|
||||
hex += millis();
|
||||
#endif
|
||||
if (pos > 3) {
|
||||
// Make space in name for ~HHHH.
|
||||
pos = 3;
|
||||
}
|
||||
for (uint8_t i = pos + 4 ; i > pos; i--) {
|
||||
for (uint8_t i = pos + 4; i > pos; i--) {
|
||||
uint8_t h = hex & 0XF;
|
||||
fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10;
|
||||
hex >>= 4;
|
||||
|
|
@ -277,25 +258,26 @@ bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
|
|||
// fall inti fail - too many tries.
|
||||
DBG_FAIL_MACRO;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
|
||||
done:
|
||||
done:
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
||||
bool fnameFound = false;
|
||||
uint8_t lfnOrd = 0;
|
||||
uint8_t freeNeed;
|
||||
uint8_t freeFound = 0;
|
||||
uint8_t freeNeed;
|
||||
uint8_t order = 0;
|
||||
uint8_t checksum = 0;
|
||||
uint8_t ms10;
|
||||
uint8_t nameOrd;
|
||||
uint16_t freeIndex = 0;
|
||||
uint16_t curIndex;
|
||||
uint16_t date;
|
||||
uint16_t freeIndex = 0;
|
||||
uint16_t freeTotal;
|
||||
uint16_t time;
|
||||
DirFat_t* dir;
|
||||
DirLfn_t* ldir;
|
||||
|
|
@ -306,11 +288,11 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
goto fail;
|
||||
}
|
||||
// Number of directory entries needed.
|
||||
nameOrd = (fname->len + 12)/13;
|
||||
freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + nameOrd : 1;
|
||||
nameOrd = (fname->len + 12) / 13;
|
||||
freeNeed = (fname->flags & FNAME_FLAG_NEED_LFN) ? 1 + nameOrd : 1;
|
||||
dirFile->rewind();
|
||||
while (1) {
|
||||
curIndex = dirFile->m_curPosition/FS_DIR_SIZE;
|
||||
curIndex = dirFile->m_curPosition / FS_DIR_SIZE;
|
||||
dir = dirFile->readDirCache();
|
||||
if (!dir) {
|
||||
if (dirFile->getError()) {
|
||||
|
|
@ -343,7 +325,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
if (!lfnOrd) {
|
||||
order = ldir->order & 0X1F;
|
||||
if (order != nameOrd ||
|
||||
(ldir->order & FAT_ORDER_LAST_LONG_ENTRY) == 0) {
|
||||
(ldir->order & FAT_ORDER_LAST_LONG_ENTRY) == 0) {
|
||||
continue;
|
||||
}
|
||||
lfnOrd = nameOrd;
|
||||
|
|
@ -376,7 +358,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
}
|
||||
}
|
||||
|
||||
found:
|
||||
found:
|
||||
// Don't open if create only.
|
||||
if (oflag & O_EXCL) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -384,7 +366,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
}
|
||||
goto open;
|
||||
|
||||
create:
|
||||
create:
|
||||
// don't create unless O_CREAT and write mode
|
||||
if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
|
||||
DBG_WARN_MACRO;
|
||||
|
|
@ -407,13 +389,16 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
}
|
||||
freeFound++;
|
||||
}
|
||||
while (freeFound < freeNeed) {
|
||||
// Loop handles the case of huge filename and cluster size one.
|
||||
freeTotal = freeFound;
|
||||
while (freeTotal < freeNeed) {
|
||||
// Will fail if FAT16 root.
|
||||
if (!dirFile->addDirCluster()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
freeFound += vol->dirEntriesPerCluster();
|
||||
// 16-bit freeTotal needed for large cluster size.
|
||||
freeTotal += vol->dirEntriesPerCluster();
|
||||
}
|
||||
if (fnameFound) {
|
||||
if (!dirFile->makeUniqueSfn(fname)) {
|
||||
|
|
@ -456,7 +441,7 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
// Force write of entry to device.
|
||||
vol->cacheDirty();
|
||||
|
||||
open:
|
||||
open:
|
||||
// open entry in cache.
|
||||
if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -464,12 +449,12 @@ bool FatFile::open(FatFile* dirFile, FatLfn_t* fname, oflag_t oflag) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::parsePathName(const char* path,
|
||||
FatLfn_t* fname, const char** ptr) {
|
||||
bool FatFile::parsePathName(const char* path, FatLfn_t* fname,
|
||||
const char** ptr) {
|
||||
size_t len = 0;
|
||||
// Skip leading spaces.
|
||||
while (*path == ' ') {
|
||||
|
|
@ -491,7 +476,7 @@ bool FatFile::parsePathName(const char* path,
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
#else // USE_UTF8_LONG_NAMES
|
||||
uint8_t cp = *path++;
|
||||
if (cp >= 0X80 || lfnReservedChar(cp)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -510,11 +495,12 @@ bool FatFile::parsePathName(const char* path,
|
|||
goto fail;
|
||||
}
|
||||
// Advance to next path component.
|
||||
for (; *path == ' ' || isDirSeparator(*path); path++) {}
|
||||
for (; *path == ' ' || isDirSeparator(*path); path++) {
|
||||
}
|
||||
*ptr = path;
|
||||
return makeSFN(fname);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -570,8 +556,7 @@ bool FatFile::remove() {
|
|||
goto fail;
|
||||
}
|
||||
if (ldir->attributes != FAT_ATTRIB_LONG_NAME ||
|
||||
order != (ldir->order & 0X1F) ||
|
||||
checksum != ldir->checksum) {
|
||||
order != (ldir->order & 0X1F) || checksum != ldir->checksum) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -589,7 +574,7 @@ bool FatFile::remove() {
|
|||
// Fall into fail.
|
||||
DBG_FAIL_MACRO;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif // #if USE_LONG_FILE_NAMES
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ bool FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -99,7 +99,7 @@ size_t FatFile::printModifyDateTime(print_t* pr) {
|
|||
//------------------------------------------------------------------------------
|
||||
size_t FatFile::printFileSize(print_t* pr) {
|
||||
char buf[11];
|
||||
char *ptr = buf + sizeof(buf);
|
||||
char* ptr = buf + sizeof(buf);
|
||||
*--ptr = 0;
|
||||
ptr = fmtBase10(ptr, fileSize());
|
||||
while (ptr > buf) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
|
|||
while (true) {
|
||||
dir = dirFile->readDirCache(true);
|
||||
if (!dir) {
|
||||
if (dirFile->getError()) {
|
||||
if (dirFile->getError()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -143,7 +143,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
|
|||
// open entry in cache.
|
||||
return openCachedEntry(dirFile, index, oflag, 0);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -169,7 +169,7 @@ bool FatFile::openExistingSFN(const char* path) {
|
|||
} while (*path);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -192,9 +192,9 @@ bool FatFile::openSFN(FatSfn_t* fname) {
|
|||
goto fail;
|
||||
}
|
||||
if (isFatFileOrSubdir(&dir) && memcmp(fname->sfn, dir.name, 11) == 0) {
|
||||
uint16_t dirIndex = (m_curPosition - 32) >> 5;
|
||||
uint32_t dirCluster = m_firstCluster;
|
||||
memset(this, 0 , sizeof(FatFile));
|
||||
uint16_t saveDirIndex = (m_curPosition - 32) >> 5;
|
||||
uint32_t saveDirCluster = m_firstCluster;
|
||||
memset(this, 0, sizeof(FatFile));
|
||||
m_attributes = dir.attributes & FS_ATTRIB_COPY;
|
||||
m_flags = FILE_FLAG_READ;
|
||||
if (isFatFile(&dir)) {
|
||||
|
|
@ -209,9 +209,9 @@ bool FatFile::openSFN(FatSfn_t* fname) {
|
|||
m_firstCluster |= getLe16(dir.firstClusterLow);
|
||||
m_fileSize = getLe32(dir.fileSize);
|
||||
m_vol = vol;
|
||||
m_dirCluster = dirCluster;
|
||||
m_dirCluster = saveDirCluster;
|
||||
m_dirSector = m_vol->cacheSectorNumber();
|
||||
m_dirIndex = dirIndex;
|
||||
m_dirIndex = saveDirIndex;
|
||||
return true;
|
||||
} else if (isFatLongName(&dir)) {
|
||||
ldir = reinterpret_cast<DirLfn_t*>(&dir);
|
||||
|
|
@ -223,7 +223,7 @@ bool FatFile::openSFN(FatSfn_t* fname) {
|
|||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -269,14 +269,14 @@ bool FatFile::parsePathName(const char* path, FatSfn_t* fname,
|
|||
goto fail;
|
||||
}
|
||||
// Set base-name and extension bits.
|
||||
fname->flags = lc & uc ? 0 : lc;
|
||||
fname->flags = (lc & uc) ? 0 : lc;
|
||||
while (isDirSeparator(*path)) {
|
||||
path++;
|
||||
}
|
||||
*ptr = path;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#if !USE_LONG_FILE_NAMES
|
||||
|
|
@ -309,7 +309,7 @@ bool FatFile::remove() {
|
|||
// Write entry to device.
|
||||
return m_vol->cacheSync();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif // !USE_LONG_FILE_NAMES
|
||||
|
|
|
|||
|
|
@ -31,18 +31,20 @@ uint16_t const BU16 = 128;
|
|||
uint16_t const BU32 = 8192;
|
||||
// Assume 512 byte sectors.
|
||||
const uint16_t BYTES_PER_SECTOR = 512;
|
||||
const uint16_t SECTORS_PER_MB = 0X100000/BYTES_PER_SECTOR;
|
||||
const uint16_t SECTORS_PER_MB = 0X100000 / BYTES_PER_SECTOR;
|
||||
const uint16_t FAT16_ROOT_ENTRY_COUNT = 512;
|
||||
const uint16_t FAT16_ROOT_SECTOR_COUNT =
|
||||
32*FAT16_ROOT_ENTRY_COUNT/BYTES_PER_SECTOR;
|
||||
32 * FAT16_ROOT_ENTRY_COUNT / BYTES_PER_SECTOR;
|
||||
//------------------------------------------------------------------------------
|
||||
#define PRINT_FORMAT_PROGRESS 1
|
||||
#if !PRINT_FORMAT_PROGRESS
|
||||
#define writeMsg(str)
|
||||
#elif defined(__AVR__)
|
||||
#define writeMsg(str) if (m_pr) m_pr->print(F(str))
|
||||
#define writeMsg(str) \
|
||||
if (m_pr) m_pr->print(F(str))
|
||||
#else // PRINT_FORMAT_PROGRESS
|
||||
#define writeMsg(str) if (m_pr) m_pr->write(str)
|
||||
#define writeMsg(str) \
|
||||
if (m_pr) m_pr->write(str)
|
||||
#endif // PRINT_FORMAT_PROGRESS
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
||||
|
|
@ -51,7 +53,7 @@ bool FatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
|
|||
m_secBuf = secBuf;
|
||||
m_pr = pr;
|
||||
m_sectorCount = m_dev->sectorCount();
|
||||
m_capacityMB = (m_sectorCount + SECTORS_PER_MB - 1)/SECTORS_PER_MB;
|
||||
m_capacityMB = (m_sectorCount + SECTORS_PER_MB - 1) / SECTORS_PER_MB;
|
||||
|
||||
if (m_capacityMB <= 6) {
|
||||
writeMsg("Card is too small.\r\n");
|
||||
|
|
@ -87,9 +89,9 @@ bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) {
|
|||
writeMsg("Writing FAT ");
|
||||
for (uint32_t i = 1; i < sectorCount; i++) {
|
||||
if (!m_dev->writeSector(m_fatStart + i, m_secBuf)) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
if ((i%(sectorCount/32)) == 0) {
|
||||
if ((i % (sectorCount / 32)) == 0) {
|
||||
writeMsg(".");
|
||||
}
|
||||
}
|
||||
|
|
@ -131,13 +133,12 @@ void FatFormatter::initPbs() {
|
|||
//------------------------------------------------------------------------------
|
||||
bool FatFormatter::makeFat16() {
|
||||
uint32_t nc;
|
||||
uint32_t r;
|
||||
PbsFat_t* pbs = reinterpret_cast<PbsFat_t*>(m_secBuf);
|
||||
|
||||
for (m_dataStart = 2*BU16; ; m_dataStart += BU16) {
|
||||
nc = (m_sectorCount - m_dataStart)/m_sectorsPerCluster;
|
||||
m_fatSize = (nc + 2 + (BYTES_PER_SECTOR/2) - 1)/(BYTES_PER_SECTOR/2);
|
||||
r = BU16 + 1 + 2*m_fatSize + FAT16_ROOT_SECTOR_COUNT;
|
||||
for (m_dataStart = 2 * BU16;; m_dataStart += BU16) {
|
||||
nc = (m_sectorCount - m_dataStart) / m_sectorsPerCluster;
|
||||
m_fatSize = (nc + 2 + (BYTES_PER_SECTOR / 2) - 1) / (BYTES_PER_SECTOR / 2);
|
||||
uint32_t r = BU16 + 1 + 2 * m_fatSize + FAT16_ROOT_SECTOR_COUNT;
|
||||
if (m_dataStart >= r) {
|
||||
m_relativeSectors = m_dataStart - r + BU16;
|
||||
break;
|
||||
|
|
@ -150,8 +151,8 @@ bool FatFormatter::makeFat16() {
|
|||
}
|
||||
m_reservedSectorCount = 1;
|
||||
m_fatStart = m_relativeSectors + m_reservedSectorCount;
|
||||
m_totalSectors = nc*m_sectorsPerCluster
|
||||
+ 2*m_fatSize + m_reservedSectorCount + 32;
|
||||
m_totalSectors =
|
||||
nc * m_sectorsPerCluster + 2 * m_fatSize + m_reservedSectorCount + 32;
|
||||
if (m_totalSectors < 65536) {
|
||||
m_partType = 0X04;
|
||||
} else {
|
||||
|
|
@ -183,15 +184,14 @@ bool FatFormatter::makeFat16() {
|
|||
//------------------------------------------------------------------------------
|
||||
bool FatFormatter::makeFat32() {
|
||||
uint32_t nc;
|
||||
uint32_t r;
|
||||
PbsFat_t* pbs = reinterpret_cast<PbsFat_t*>(m_secBuf);
|
||||
FsInfo_t* fsi = reinterpret_cast<FsInfo_t*>(m_secBuf);
|
||||
|
||||
m_relativeSectors = BU32;
|
||||
for (m_dataStart = 2*BU32; ; m_dataStart += BU32) {
|
||||
nc = (m_sectorCount - m_dataStart)/m_sectorsPerCluster;
|
||||
m_fatSize = (nc + 2 + (BYTES_PER_SECTOR/4) - 1)/(BYTES_PER_SECTOR/4);
|
||||
r = m_relativeSectors + 9 + 2*m_fatSize;
|
||||
for (m_dataStart = 2 * BU32;; m_dataStart += BU32) {
|
||||
nc = (m_sectorCount - m_dataStart) / m_sectorsPerCluster;
|
||||
m_fatSize = (nc + 2 + (BYTES_PER_SECTOR / 4) - 1) / (BYTES_PER_SECTOR / 4);
|
||||
uint32_t r = m_relativeSectors + 9 + 2 * m_fatSize;
|
||||
if (m_dataStart >= r) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -201,9 +201,9 @@ bool FatFormatter::makeFat32() {
|
|||
writeMsg("Bad cluster count\r\n");
|
||||
return false;
|
||||
}
|
||||
m_reservedSectorCount = m_dataStart - m_relativeSectors - 2*m_fatSize;
|
||||
m_reservedSectorCount = m_dataStart - m_relativeSectors - 2 * m_fatSize;
|
||||
m_fatStart = m_relativeSectors + m_reservedSectorCount;
|
||||
m_totalSectors = nc*m_sectorsPerCluster + m_dataStart - m_relativeSectors;
|
||||
m_totalSectors = nc * m_sectorsPerCluster + m_dataStart - m_relativeSectors;
|
||||
// type depends on address of end sector
|
||||
// max CHS has lba = 16450560 = 1024*255*63
|
||||
if ((m_relativeSectors + m_totalSectors) <= 16450560) {
|
||||
|
|
@ -232,14 +232,14 @@ bool FatFormatter::makeFat32() {
|
|||
pbs->bpb.bpb32.volumeType[2] = 'T';
|
||||
pbs->bpb.bpb32.volumeType[3] = '3';
|
||||
pbs->bpb.bpb32.volumeType[4] = '2';
|
||||
if (!m_dev->writeSector(m_relativeSectors, m_secBuf) ||
|
||||
if (!m_dev->writeSector(m_relativeSectors, m_secBuf) ||
|
||||
!m_dev->writeSector(m_relativeSectors + 6, m_secBuf)) {
|
||||
return false;
|
||||
}
|
||||
// write extra boot area and backup
|
||||
memset(m_secBuf, 0 , BYTES_PER_SECTOR);
|
||||
memset(m_secBuf, 0, BYTES_PER_SECTOR);
|
||||
setLe32(fsi->trailSignature, FSINFO_TRAIL_SIGNATURE);
|
||||
if (!m_dev->writeSector(m_relativeSectors + 2, m_secBuf) ||
|
||||
if (!m_dev->writeSector(m_relativeSectors + 2, m_secBuf) ||
|
||||
!m_dev->writeSector(m_relativeSectors + 8, m_secBuf)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -248,11 +248,11 @@ bool FatFormatter::makeFat32() {
|
|||
setLe32(fsi->structSignature, FSINFO_STRUCT_SIGNATURE);
|
||||
setLe32(fsi->freeCount, 0XFFFFFFFF);
|
||||
setLe32(fsi->nextFree, 0XFFFFFFFF);
|
||||
if (!m_dev->writeSector(m_relativeSectors + 1, m_secBuf) ||
|
||||
if (!m_dev->writeSector(m_relativeSectors + 1, m_secBuf) ||
|
||||
!m_dev->writeSector(m_relativeSectors + 7, m_secBuf)) {
|
||||
return false;
|
||||
}
|
||||
return initFatDir(32, 2*m_fatSize + m_sectorsPerCluster);
|
||||
return initFatDir(32, 2 * m_fatSize + m_sectorsPerCluster);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFormatter::writeMbr() {
|
||||
|
|
@ -262,8 +262,8 @@ bool FatFormatter::writeMbr() {
|
|||
#if USE_LBA_TO_CHS
|
||||
lbaToMbrChs(mbr->part->beginCHS, m_capacityMB, m_relativeSectors);
|
||||
lbaToMbrChs(mbr->part->endCHS, m_capacityMB,
|
||||
m_relativeSectors + m_totalSectors -1);
|
||||
#else // USE_LBA_TO_CHS
|
||||
m_relativeSectors + m_totalSectors - 1);
|
||||
#else // USE_LBA_TO_CHS
|
||||
mbr->part->beginCHS[0] = 1;
|
||||
mbr->part->beginCHS[1] = 1;
|
||||
mbr->part->beginCHS[2] = 0;
|
||||
|
|
|
|||
|
|
@ -24,14 +24,16 @@
|
|||
*/
|
||||
#ifndef FatFormatter_h
|
||||
#define FatFormatter_h
|
||||
#include "../common/SysCall.h"
|
||||
#include "../common/FsBlockDevice.h"
|
||||
#include "../common/SysCall.h"
|
||||
/**
|
||||
* \class FatFormatter
|
||||
* \brief Format a FAT volume.
|
||||
*/
|
||||
class FatFormatter {
|
||||
public:
|
||||
/** Constructor. */
|
||||
FatFormatter() = default;
|
||||
/**
|
||||
* Format a FAT volume.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -24,6 +24,6 @@
|
|||
*/
|
||||
#ifndef FatLib_h
|
||||
#define FatLib_h
|
||||
#include "FatVolume.h"
|
||||
#include "FatFormatter.h"
|
||||
#include "FatVolume.h"
|
||||
#endif // FatLib_h
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@
|
|||
//------------------------------------------------------------------------------
|
||||
uint16_t FatFile::getLfnChar(DirLfn_t* ldir, uint8_t i) {
|
||||
if (i < 5) {
|
||||
return getLe16(ldir->unicode1 + 2*i);
|
||||
return getLe16(ldir->unicode1 + 2 * i);
|
||||
} else if (i < 11) {
|
||||
return getLe16(ldir->unicode2 + 2*i - 10);
|
||||
return getLe16(ldir->unicode2 + 2 * (i - 5));
|
||||
} else if (i < 13) {
|
||||
return getLe16(ldir->unicode3 + 2*i - 22);
|
||||
return getLe16(ldir->unicode3 + 2 * (i - 11));
|
||||
}
|
||||
DBG_HALT_IF(i >= 13);
|
||||
return 0;
|
||||
|
|
@ -87,11 +87,11 @@ size_t FatFile::getName7(char* name, size_t size) {
|
|||
name[n++] = c >= 0X7F ? '?' : c;
|
||||
}
|
||||
}
|
||||
done:
|
||||
done:
|
||||
name[n] = 0;
|
||||
return n;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
name[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -105,8 +105,8 @@ size_t FatFile::getName8(char* name, size_t size) {
|
|||
uint16_t hs = 0;
|
||||
uint32_t cp;
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
if (!isLFN()) {
|
||||
return getSFN(name, size);
|
||||
|
|
@ -156,11 +156,11 @@ size_t FatFile::getName8(char* name, size_t size) {
|
|||
str = ptr;
|
||||
}
|
||||
}
|
||||
done:
|
||||
done:
|
||||
*str = '\0';
|
||||
return str - name;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
*name = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ size_t FatFile::getSFN(char* name, size_t size) {
|
|||
name[j] = '\0';
|
||||
return j;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
name[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -227,10 +227,10 @@ size_t FatFile::printName(print_t* pr) {
|
|||
return printSFN(pr);
|
||||
#elif USE_UTF8_LONG_NAMES
|
||||
return printName8(pr);
|
||||
# else // USE_LONG_FILE_NAMES
|
||||
#else // USE_LONG_FILE_NAMES
|
||||
return printName7(pr);
|
||||
#endif // !USE_LONG_FILE_NAMES
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
size_t FatFile::printName7(print_t* pr) {
|
||||
FatFile dir;
|
||||
|
|
@ -240,8 +240,8 @@ size_t FatFile::printName7(print_t* pr) {
|
|||
uint8_t i;
|
||||
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
if (!isLFN()) {
|
||||
return printSFN(pr);
|
||||
|
|
@ -274,11 +274,11 @@ size_t FatFile::printName7(print_t* pr) {
|
|||
}
|
||||
return n;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
size_t FatFile::printName8(print_t *pr) {
|
||||
size_t FatFile::printName8(print_t* pr) {
|
||||
FatFile dir;
|
||||
DirLfn_t* ldir;
|
||||
uint16_t hs = 0;
|
||||
|
|
@ -287,8 +287,8 @@ size_t FatFile::printName8(print_t *pr) {
|
|||
char buf[5];
|
||||
char* end = buf + sizeof(buf);
|
||||
if (!isOpen()) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
if (!isLFN()) {
|
||||
return printSFN(pr);
|
||||
|
|
@ -309,7 +309,7 @@ size_t FatFile::printName8(print_t *pr) {
|
|||
goto fail;
|
||||
}
|
||||
for (uint8_t i = 0; i < 13; i++) {
|
||||
uint16_t c = getLfnChar(ldir, i);;
|
||||
uint16_t c = getLfnChar(ldir, i);
|
||||
if (hs) {
|
||||
if (!FsUtf::isLowSurrogate(c)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -334,12 +334,12 @@ size_t FatFile::printName8(print_t *pr) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
n += pr->write(buf, str - buf);
|
||||
n += pr->write(reinterpret_cast<uint8_t*>(buf), str - buf);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -351,6 +351,6 @@ size_t FatFile::printSFN(print_t* pr) {
|
|||
}
|
||||
return pr->write(name);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ bool FatPartition::allocateCluster(uint32_t current, uint32_t* next) {
|
|||
*next = find;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -149,7 +149,7 @@ bool FatPartition::allocContiguous(uint32_t count, uint32_t* firstCluster) {
|
|||
*firstCluster = bgnCluster;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -176,7 +176,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
|
|||
next = getLe32(pc + offset);
|
||||
} else if (fatType() == 16) {
|
||||
cluster &= 0XFFFF;
|
||||
sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) );
|
||||
sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1));
|
||||
pc = fatCachePrepare(sector, FsCache::CACHE_FOR_READ);
|
||||
if (!pc) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -216,7 +216,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
|
|||
*value = next;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return -1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -245,7 +245,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) {
|
|||
|
||||
if (fatType() == 16) {
|
||||
cluster &= 0XFFFF;
|
||||
sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) );
|
||||
sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1));
|
||||
pc = fatCachePrepare(sector, FsCache::CACHE_FOR_WRITE);
|
||||
if (!pc) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -293,7 +293,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -322,7 +322,7 @@ bool FatPartition::freeChain(uint32_t cluster) {
|
|||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -357,7 +357,7 @@ int32_t FatPartition::freeClusterCount() {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
n = fatType() == 16 ? m_bytesPerSector/2 : m_bytesPerSector/4;
|
||||
n = fatType() == 16 ? m_bytesPerSector / 2 : m_bytesPerSector / 4;
|
||||
if (todo < n) {
|
||||
n = todo;
|
||||
}
|
||||
|
|
@ -386,12 +386,12 @@ int32_t FatPartition::freeClusterCount() {
|
|||
setFreeClusterCount(free);
|
||||
return free;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return -1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
||||
uint32_t clusterCount;
|
||||
uint32_t countOfClusters;
|
||||
uint32_t totalSectors;
|
||||
m_blockDev = dev;
|
||||
pbs_t* pbs;
|
||||
|
|
@ -411,8 +411,8 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
mbr = reinterpret_cast<MbrSector_t*>
|
||||
(dataCachePrepare(0, FsCache::CACHE_FOR_READ));
|
||||
mbr = reinterpret_cast<MbrSector_t*>(
|
||||
dataCachePrepare(0, FsCache::CACHE_FOR_READ));
|
||||
if (!mbr) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -424,8 +424,8 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
}
|
||||
volStart = getLe32(mp->relativeSectors);
|
||||
}
|
||||
pbs = reinterpret_cast<pbs_t*>
|
||||
(dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
|
||||
pbs = reinterpret_cast<pbs_t*>(
|
||||
dataCachePrepare(volStart, FsCache::CACHE_FOR_READ));
|
||||
if (!pbs) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
|
|
@ -458,8 +458,10 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
// directory start for FAT16 dataStart for FAT32
|
||||
m_rootDirStart = m_fatStartSector + 2 * m_sectorsPerFat;
|
||||
// data start for FAT16 and FAT32
|
||||
m_dataStartSector = m_rootDirStart +
|
||||
((FS_DIR_SIZE*m_rootDirEntryCount + m_bytesPerSector - 1)/m_bytesPerSector);
|
||||
m_dataStartSector =
|
||||
m_rootDirStart +
|
||||
((FS_DIR_SIZE * m_rootDirEntryCount + m_bytesPerSector - 1) /
|
||||
m_bytesPerSector);
|
||||
|
||||
// total sectors for FAT16 or FAT32
|
||||
totalSectors = getLe16(bpb->totalSectors16);
|
||||
|
|
@ -467,22 +469,22 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
totalSectors = getLe32(bpb->totalSectors32);
|
||||
}
|
||||
// total data sectors
|
||||
clusterCount = totalSectors - (m_dataStartSector - volStart);
|
||||
countOfClusters = totalSectors - (m_dataStartSector - volStart);
|
||||
|
||||
// divide by cluster size to get cluster count
|
||||
clusterCount >>= m_sectorsPerClusterShift;
|
||||
m_lastCluster = clusterCount + 1;
|
||||
countOfClusters >>= m_sectorsPerClusterShift;
|
||||
m_lastCluster = countOfClusters + 1;
|
||||
|
||||
// Indicate unknown number of free clusters.
|
||||
setFreeClusterCount(-1);
|
||||
// FAT type is determined by cluster count
|
||||
if (clusterCount < 4085) {
|
||||
if (countOfClusters < 4085) {
|
||||
m_fatType = 12;
|
||||
if (!FAT12_SUPPORT) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
} else if (clusterCount < 65525) {
|
||||
} else if (countOfClusters < 65525) {
|
||||
m_fatType = 16;
|
||||
} else {
|
||||
m_rootDirStart = getLe32(bpb->fat32RootCluster);
|
||||
|
|
@ -494,6 +496,6 @@ bool FatPartition::init(FsBlockDevice* dev, uint8_t part, uint32_t volStart) {
|
|||
#endif // USE_SEPARATE_FAT_CACHE
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@
|
|||
* \brief FatPartition class
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include "../common/SysCall.h"
|
||||
|
||||
#include "../common/FsBlockDevice.h"
|
||||
#include "../common/FsCache.h"
|
||||
#include "../common/FsStructs.h"
|
||||
#include "../common/SysCall.h"
|
||||
|
||||
/** Type for FAT12 partition */
|
||||
const uint8_t FAT_TYPE_FAT12 = 12;
|
||||
|
|
@ -52,7 +53,7 @@ class FatPartition {
|
|||
public:
|
||||
/** Create an instance of FatPartition
|
||||
*/
|
||||
FatPartition() {}
|
||||
FatPartition() = default;
|
||||
|
||||
/** \return The shift count required to multiply by bytesPerCluster. */
|
||||
uint8_t bytesPerClusterShift() const {
|
||||
|
|
@ -63,50 +64,32 @@ class FatPartition {
|
|||
return m_bytesPerSector << m_sectorsPerClusterShift;
|
||||
}
|
||||
/** \return Number of bytes per sector. */
|
||||
uint16_t bytesPerSector() const {
|
||||
return m_bytesPerSector;
|
||||
}
|
||||
uint16_t bytesPerSector() const { return m_bytesPerSector; }
|
||||
/** \return The shift count required to multiply by bytesPerCluster. */
|
||||
uint8_t bytesPerSectorShift() const {
|
||||
return m_bytesPerSectorShift;
|
||||
}
|
||||
/** \return Number of directory entries per sector. */
|
||||
uint8_t bytesPerSectorShift() const { return m_bytesPerSectorShift; }
|
||||
/** \return Number of directory entries per cluster. */
|
||||
uint16_t dirEntriesPerCluster() const {
|
||||
return m_sectorsPerCluster*(m_bytesPerSector/FS_DIR_SIZE);
|
||||
return m_sectorsPerCluster * (m_bytesPerSector / FS_DIR_SIZE);
|
||||
}
|
||||
/** \return Mask for sector offset. */
|
||||
uint16_t sectorMask() const {
|
||||
return m_sectorMask;
|
||||
}
|
||||
uint16_t sectorMask() const { return m_sectorMask; }
|
||||
/** \return The volume's cluster size in sectors. */
|
||||
uint8_t sectorsPerCluster() const {
|
||||
return m_sectorsPerCluster;
|
||||
}
|
||||
uint8_t sectorsPerCluster() const { return m_sectorsPerCluster; }
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
uint8_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/** \return The number of sectors in one FAT. */
|
||||
uint32_t sectorsPerFat() const {
|
||||
return m_sectorsPerFat;
|
||||
}
|
||||
uint32_t sectorsPerFat() const { return m_sectorsPerFat; }
|
||||
/** Clear the cache and returns a pointer to the cache. Not for normal apps.
|
||||
* \return A pointer to the cache buffer or zero if an error occurs.
|
||||
*/
|
||||
uint8_t* cacheClear() {
|
||||
return m_cache.clear();
|
||||
}
|
||||
uint8_t* cacheClear() { return m_cache.clear(); }
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount() const {
|
||||
return m_lastCluster - 1;
|
||||
}
|
||||
uint32_t clusterCount() const { return m_lastCluster - 1; }
|
||||
/** \return The shift count required to multiply by sectorsPerCluster. */
|
||||
uint8_t sectorsPerClusterShift() const {
|
||||
return m_sectorsPerClusterShift;
|
||||
}
|
||||
uint8_t sectorsPerClusterShift() const { return m_sectorsPerClusterShift; }
|
||||
/** \return The logical sector number for the start of file data. */
|
||||
uint32_t dataStartSector() const {
|
||||
return m_dataStartSector;
|
||||
}
|
||||
uint32_t dataStartSector() const { return m_dataStartSector; }
|
||||
/** End access to volume
|
||||
* \return pointer to sector size buffer for format.
|
||||
*/
|
||||
|
|
@ -115,17 +98,11 @@ class FatPartition {
|
|||
return cacheClear();
|
||||
}
|
||||
/** \return The number of File Allocation Tables. */
|
||||
uint8_t fatCount() const {
|
||||
return 2;
|
||||
}
|
||||
uint8_t fatCount() const { return 2; }
|
||||
/** \return The logical sector number for the start of the first FAT. */
|
||||
uint32_t fatStartSector() const {
|
||||
return m_fatStartSector;
|
||||
}
|
||||
uint32_t fatStartSector() const { return m_fatStartSector; }
|
||||
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||
uint8_t fatType() const {
|
||||
return m_fatType;
|
||||
}
|
||||
uint8_t fatType() const { return m_fatType; }
|
||||
/** \return free cluster count or -1 if an error occurs. */
|
||||
int32_t freeClusterCount();
|
||||
/** Initialize a FAT partition.
|
||||
|
|
@ -141,17 +118,13 @@ class FatPartition {
|
|||
*/
|
||||
bool init(FsBlockDevice* dev, uint8_t part = 1, uint32_t volStart = 0);
|
||||
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||
uint16_t rootDirEntryCount() const {
|
||||
return m_rootDirEntryCount;
|
||||
}
|
||||
uint16_t rootDirEntryCount() const { return m_rootDirEntryCount; }
|
||||
/** \return The logical sector number for the start of the root directory
|
||||
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||
uint32_t rootDirStart() const {
|
||||
return m_rootDirStart;
|
||||
}
|
||||
uint32_t rootDirStart() const { return m_rootDirStart; }
|
||||
/** \return The number of sectors in the volume */
|
||||
uint32_t volumeSectorCount() const {
|
||||
return sectorsPerCluster()*clusterCount();
|
||||
return sectorsPerCluster() * clusterCount();
|
||||
}
|
||||
/** Debug access to FAT table
|
||||
*
|
||||
|
|
@ -159,15 +132,13 @@ class FatPartition {
|
|||
* \param[out] v value of entry
|
||||
* \return -1 error, 0 EOC, else 1.
|
||||
*/
|
||||
int8_t dbgFat(uint32_t n, uint32_t* v) {
|
||||
return fatGet(n, v);
|
||||
}
|
||||
int8_t dbgFat(uint32_t n, uint32_t* v) { return fatGet(n, v); }
|
||||
/**
|
||||
* Check for FsBlockDevice busy.
|
||||
*
|
||||
* \return true if busy else false.
|
||||
*/
|
||||
bool isBusy() {return m_blockDev->isBusy();}
|
||||
bool isBusy() { return m_blockDev->isBusy(); }
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
bool dmpDirSector(print_t* pr, uint32_t sector);
|
||||
|
|
@ -180,22 +151,22 @@ class FatPartition {
|
|||
/** FatFile allowed access to private members. */
|
||||
friend class FatFile;
|
||||
//----------------------------------------------------------------------------
|
||||
static const uint8_t m_bytesPerSectorShift = 9;
|
||||
static const uint8_t m_bytesPerSectorShift = 9;
|
||||
static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift;
|
||||
static const uint16_t m_sectorMask = m_bytesPerSector - 1;
|
||||
//----------------------------------------------------------------------------
|
||||
FsBlockDevice* m_blockDev; // sector device
|
||||
uint8_t m_sectorsPerCluster; // Cluster size in sectors.
|
||||
uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
|
||||
uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.
|
||||
uint8_t m_fatType = 0; // Volume type (12, 16, OR 32).
|
||||
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
|
||||
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
||||
uint32_t m_sectorsPerFat; // FAT size in sectors
|
||||
uint32_t m_dataStartSector; // First data sector number.
|
||||
uint32_t m_fatStartSector; // Start sector for first FAT.
|
||||
uint32_t m_lastCluster; // Last cluster number in FAT.
|
||||
uint32_t m_rootDirStart; // Start sector FAT16, cluster FAT32.
|
||||
FsBlockDevice* m_blockDev; // sector device
|
||||
uint8_t m_sectorsPerCluster; // Cluster size in sectors.
|
||||
uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
|
||||
uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.
|
||||
uint8_t m_fatType = 0; // Volume type (12, 16, OR 32).
|
||||
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
|
||||
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
||||
uint32_t m_sectorsPerFat; // FAT size in sectors
|
||||
uint32_t m_dataStartSector; // First data sector number.
|
||||
uint32_t m_fatStartSector; // Start sector for first FAT.
|
||||
uint32_t m_lastCluster; // Last cluster number in FAT.
|
||||
uint32_t m_rootDirStart; // Start sector FAT16, cluster FAT32.
|
||||
//----------------------------------------------------------------------------
|
||||
// sector I/O functions.
|
||||
bool cacheSafeRead(uint32_t sector, uint8_t* dst) {
|
||||
|
|
@ -210,33 +181,22 @@ class FatPartition {
|
|||
bool cacheSafeWrite(uint32_t sector, const uint8_t* dst, size_t count) {
|
||||
return m_cache.cacheSafeWrite(sector, dst, count);
|
||||
}
|
||||
bool syncDevice() {
|
||||
return m_blockDev->syncDevice();
|
||||
}
|
||||
bool syncDevice() { return m_blockDev->syncDevice(); }
|
||||
#if MAINTAIN_FREE_CLUSTER_COUNT
|
||||
int32_t m_freeClusterCount; // Count of free clusters in volume.
|
||||
void setFreeClusterCount(int32_t value) {
|
||||
m_freeClusterCount = value;
|
||||
}
|
||||
int32_t m_freeClusterCount; // Count of free clusters in volume.
|
||||
void setFreeClusterCount(int32_t value) { m_freeClusterCount = value; }
|
||||
void updateFreeClusterCount(int32_t change) {
|
||||
if (m_freeClusterCount >= 0) {
|
||||
m_freeClusterCount += change;
|
||||
}
|
||||
}
|
||||
#else // MAINTAIN_FREE_CLUSTER_COUNT
|
||||
void setFreeClusterCount(int32_t value) {
|
||||
(void)value;
|
||||
}
|
||||
void updateFreeClusterCount(int32_t change) {
|
||||
(void)change;
|
||||
}
|
||||
#else // MAINTAIN_FREE_CLUSTER_COUNT
|
||||
void setFreeClusterCount(int32_t value) { (void)value; }
|
||||
void updateFreeClusterCount(int32_t change) { (void)change; }
|
||||
#endif // MAINTAIN_FREE_CLUSTER_COUNT
|
||||
// sector caches
|
||||
// sector caches
|
||||
FsCache m_cache;
|
||||
bool cachePrepare(uint32_t sector, uint8_t option) {
|
||||
return m_cache.prepare(sector, option);
|
||||
}
|
||||
FsCache* dataCache() {return &m_cache;}
|
||||
FsCache* dataCache() { return &m_cache; }
|
||||
#if USE_SEPARATE_FAT_CACHE
|
||||
FsCache m_fatCache;
|
||||
uint8_t* fatCachePrepare(uint32_t sector, uint8_t options) {
|
||||
|
|
@ -246,33 +206,20 @@ class FatPartition {
|
|||
bool cacheSync() {
|
||||
return m_cache.sync() && m_fatCache.sync() && syncDevice();
|
||||
}
|
||||
#else // USE_SEPARATE_FAT_CACHE
|
||||
#else // USE_SEPARATE_FAT_CACHE
|
||||
uint8_t* fatCachePrepare(uint32_t sector, uint8_t options) {
|
||||
options |= FsCache::CACHE_STATUS_MIRROR_FAT;
|
||||
return dataCachePrepare(sector, options);
|
||||
}
|
||||
bool cacheSync() {
|
||||
return m_cache.sync() && syncDevice();
|
||||
}
|
||||
bool cacheSync() { return m_cache.sync() && syncDevice(); }
|
||||
#endif // USE_SEPARATE_FAT_CACHE
|
||||
uint8_t* dataCachePrepare(uint32_t sector, uint8_t options) {
|
||||
return m_cache.prepare(sector, options);
|
||||
}
|
||||
void cacheInvalidate() {
|
||||
m_cache.invalidate();
|
||||
}
|
||||
bool cacheSyncData() {
|
||||
return m_cache.sync();
|
||||
}
|
||||
uint8_t* cacheAddress() {
|
||||
return m_cache.cacheBuffer();
|
||||
}
|
||||
uint32_t cacheSectorNumber() {
|
||||
return m_cache.sector();
|
||||
}
|
||||
void cacheDirty() {
|
||||
m_cache.dirty();
|
||||
}
|
||||
bool cacheSyncData() { return m_cache.sync(); }
|
||||
uint8_t* cacheAddress() { return m_cache.cacheBuffer(); }
|
||||
uint32_t cacheSectorNumber() { return m_cache.sector(); }
|
||||
void cacheDirty() { m_cache.dirty(); }
|
||||
//----------------------------------------------------------------------------
|
||||
bool allocateCluster(uint32_t current, uint32_t* next);
|
||||
bool allocContiguous(uint32_t count, uint32_t* firstCluster);
|
||||
|
|
@ -284,12 +231,8 @@ class FatPartition {
|
|||
}
|
||||
int8_t fatGet(uint32_t cluster, uint32_t* value);
|
||||
bool fatPut(uint32_t cluster, uint32_t value);
|
||||
bool fatPutEOC(uint32_t cluster) {
|
||||
return fatPut(cluster, 0x0FFFFFFF);
|
||||
}
|
||||
bool fatPutEOC(uint32_t cluster) { return fatPut(cluster, 0x0FFFFFFF); }
|
||||
bool freeChain(uint32_t cluster);
|
||||
bool isEOC(uint32_t cluster) const {
|
||||
return cluster > m_lastCluster;
|
||||
}
|
||||
bool isEOC(uint32_t cluster) const { return cluster > m_lastCluster; }
|
||||
};
|
||||
#endif // FatPartition
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include "FatLib.h"
|
||||
FatVolume* FatVolume::m_cwv = nullptr;
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatVolume::chdir(const char *path) {
|
||||
bool FatVolume::chdir(const char* path) {
|
||||
FatFile dir;
|
||||
if (!dir.open(vwd(), path, O_RDONLY)) {
|
||||
DBG_FAIL_MACRO;
|
||||
|
|
@ -40,6 +40,6 @@ bool FatVolume::chdir(const char *path) {
|
|||
m_vwd = dir;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
* \class FatVolume
|
||||
* \brief Integration class for the FatLib library.
|
||||
*/
|
||||
class FatVolume : public FatPartition {
|
||||
class FatVolume : public FatPartition {
|
||||
public:
|
||||
/** Get file's user settable attributes.
|
||||
* \param[in] path path to file.
|
||||
|
|
@ -63,8 +63,8 @@ class FatVolume : public FatPartition {
|
|||
* \param[in] volStart Start sector of volume if part is zero.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool begin(FsBlockDevice* dev, bool setCwv = true,
|
||||
uint8_t part = 1, uint32_t volStart = 0) {
|
||||
bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1,
|
||||
uint32_t volStart = 0) {
|
||||
if (!init(dev, part, volStart)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ class FatVolume : public FatPartition {
|
|||
return true;
|
||||
}
|
||||
/** Change global current working volume to this volume. */
|
||||
void chvol() {m_cwv = this;}
|
||||
void chvol() { m_cwv = this; }
|
||||
|
||||
/**
|
||||
* Set volume working directory to root.
|
||||
|
|
@ -92,7 +92,7 @@ class FatVolume : public FatPartition {
|
|||
* \param[in] path Path for volume working directory.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool chdir(const char *path);
|
||||
bool chdir(const char* path);
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Test for the existence of a file.
|
||||
|
|
@ -120,9 +120,7 @@ class FatVolume : public FatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr, uint8_t flags = 0) {
|
||||
return m_vwd.ls(pr, flags);
|
||||
}
|
||||
bool ls(print_t* pr, uint8_t flags = 0) { return m_vwd.ls(pr, flags); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** List the contents of a directory.
|
||||
*
|
||||
|
|
@ -164,7 +162,7 @@ class FatVolume : public FatPartition {
|
|||
* \param[in] oflag open flags.
|
||||
* \return a File32 object.
|
||||
*/
|
||||
File32 open(const char *path, oflag_t oflag = O_RDONLY) {
|
||||
File32 open(const char* path, oflag_t oflag = O_RDONLY) {
|
||||
File32 tmpFile;
|
||||
tmpFile.open(this, path, oflag);
|
||||
return tmpFile;
|
||||
|
|
@ -195,7 +193,7 @@ class FatVolume : public FatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rename(const char *oldPath, const char *newPath) {
|
||||
bool rename(const char* oldPath, const char* newPath) {
|
||||
FatFile file;
|
||||
return file.open(vwd(), oldPath, O_RDONLY) && file.rename(vwd(), newPath);
|
||||
}
|
||||
|
|
@ -226,7 +224,7 @@ class FatVolume : public FatPartition {
|
|||
return file.open(this, path, O_WRONLY) && file.truncate(length);
|
||||
}
|
||||
#if ENABLE_ARDUINO_SERIAL
|
||||
/** List the directory contents of the root directory to Serial.
|
||||
/** List the directory contents of the root directory to Serial.
|
||||
*
|
||||
* \param[in] flags The inclusive OR of
|
||||
*
|
||||
|
|
@ -238,9 +236,7 @@ class FatVolume : public FatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(uint8_t flags = 0) {
|
||||
return ls(&Serial, flags);
|
||||
}
|
||||
bool ls(uint8_t flags = 0) { return ls(&Serial, flags); }
|
||||
/** List the directory contents of a directory to Serial.
|
||||
*
|
||||
* \param[in] path directory to list.
|
||||
|
|
@ -266,19 +262,15 @@ class FatVolume : public FatPartition {
|
|||
* \param[in] path Path for volume working directory.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool chdir(const String& path) {
|
||||
return chdir(path.c_str());
|
||||
}
|
||||
/**
|
||||
bool chdir(const String& path) { return chdir(path.c_str()); }
|
||||
/**
|
||||
* Test for the existence of a file.
|
||||
*
|
||||
* \param[in] path Path of the file to be tested for.
|
||||
*
|
||||
* \return true if the file exists else false.
|
||||
*/
|
||||
bool exists(const String& path) {
|
||||
return exists(path.c_str());
|
||||
}
|
||||
bool exists(const String& path) { return exists(path.c_str()); }
|
||||
/** Make a subdirectory in the volume root directory.
|
||||
*
|
||||
* \param[in] path A path with a valid name for the subdirectory.
|
||||
|
|
@ -297,7 +289,7 @@ class FatVolume : public FatPartition {
|
|||
* \return a File32 object.
|
||||
*/
|
||||
File32 open(const String& path, oflag_t oflag = O_RDONLY) {
|
||||
return open(path.c_str(), oflag );
|
||||
return open(path.c_str(), oflag);
|
||||
}
|
||||
/** Remove a file from the volume root directory.
|
||||
*
|
||||
|
|
@ -305,9 +297,7 @@ class FatVolume : public FatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const String& path) {
|
||||
return remove(path.c_str());
|
||||
}
|
||||
bool remove(const String& path) { return remove(path.c_str()); }
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
|
||||
|
|
@ -333,9 +323,7 @@ class FatVolume : public FatPartition {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rmdir(const String& path) {
|
||||
return rmdir(path.c_str());
|
||||
}
|
||||
bool rmdir(const String& path) { return rmdir(path.c_str()); }
|
||||
/** Truncate a file to a specified length. The current file position
|
||||
* will be at the new EOF.
|
||||
*
|
||||
|
|
@ -351,8 +339,8 @@ class FatVolume : public FatPartition {
|
|||
|
||||
private:
|
||||
friend FatFile;
|
||||
static FatVolume* cwv() {return m_cwv;}
|
||||
FatFile* vwd() {return &m_vwd;}
|
||||
static FatVolume* cwv() { return m_cwv; }
|
||||
FatFile* vwd() { return &m_vwd; }
|
||||
static FatVolume* m_cwv;
|
||||
FatFile m_vwd;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
/** Indicate FillStack() and UnusedStack() are available. */
|
||||
#define HAS_UNUSED_STACK 1
|
||||
/** boundary between stack and heap. */
|
||||
extern char *__brkval;
|
||||
extern char* __brkval;
|
||||
/** End of bss section.*/
|
||||
extern char __bss_end;
|
||||
/** Amount of free stack space.
|
||||
|
|
@ -48,9 +48,7 @@ inline int FreeStack() {
|
|||
#define HAS_UNUSED_STACK 0
|
||||
#elif defined(PLATFORM_ID) // Particle board
|
||||
#include "Arduino.h"
|
||||
inline int FreeStack() {
|
||||
return System.freeMemory();
|
||||
}
|
||||
inline int FreeStack() { return System.freeMemory(); }
|
||||
#elif defined(__IMXRT1062__)
|
||||
#define HAS_UNUSED_STACK 1
|
||||
extern uint8_t _ebss;
|
||||
|
|
@ -69,9 +67,7 @@ inline int FreeStack() {
|
|||
#ifndef FREE_STACK_CPP
|
||||
#warning FreeStack is not defined for this system.
|
||||
#endif // FREE_STACK_CPP
|
||||
inline int FreeStack() {
|
||||
return 0;
|
||||
}
|
||||
inline int FreeStack() { return 0; }
|
||||
#endif // defined(__AVR__) || defined(DOXYGEN)
|
||||
#if defined(HAS_UNUSED_STACK) || defined(DOXYGEN)
|
||||
/** Fill stack with 0x55 pattern */
|
||||
|
|
@ -89,6 +85,6 @@ int UnusedStack();
|
|||
#else // HAS_UNUSED_STACK
|
||||
#define HAS_UNUSED_STACK 0
|
||||
inline void FillStack() {}
|
||||
inline int UnusedStack() {return 0;}
|
||||
inline int UnusedStack() { return 0; }
|
||||
#endif // defined(HAS_UNUSED_STACK)
|
||||
#endif // FreeStack_h
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ FsBaseFile::FsBaseFile(const FsBaseFile& from) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
FsBaseFile& FsBaseFile::operator=(const FsBaseFile& from) {
|
||||
if (this == &from) {return *this;}
|
||||
if (this == &from) {
|
||||
return *this;
|
||||
}
|
||||
close();
|
||||
if (from.m_fFile) {
|
||||
m_fFile = new (m_fileMem) FatFile;
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@
|
|||
* \file
|
||||
* \brief FsBaseFile include file.
|
||||
*/
|
||||
#include "FsNew.h"
|
||||
#include "FatLib/FatLib.h"
|
||||
#include "ExFatLib/ExFatLib.h"
|
||||
#include "FatLib/FatLib.h"
|
||||
#include "FsNew.h"
|
||||
#include "FsVolume.h"
|
||||
/**
|
||||
* \class FsBaseFile
|
||||
* \brief FsBaseFile class.
|
||||
|
|
@ -38,7 +39,7 @@
|
|||
class FsBaseFile {
|
||||
public:
|
||||
/** Create an instance. */
|
||||
FsBaseFile() {}
|
||||
FsBaseFile() = default;
|
||||
/** Create a file object and open it in the current working directory.
|
||||
*
|
||||
* \param[in] path A path for a file to be opened.
|
||||
|
|
@ -46,11 +47,9 @@ class FsBaseFile {
|
|||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
|
||||
*/
|
||||
FsBaseFile(const char* path, oflag_t oflag) {
|
||||
open(path, oflag);
|
||||
}
|
||||
FsBaseFile(const char* path, oflag_t oflag) { open(path, oflag); }
|
||||
|
||||
~FsBaseFile() {close();}
|
||||
~FsBaseFile() { close(); }
|
||||
/** Copy constructor.
|
||||
*
|
||||
* \param[in] from Object used to initialize this instance.
|
||||
|
|
@ -62,16 +61,15 @@ class FsBaseFile {
|
|||
*/
|
||||
FsBaseFile& operator=(const FsBaseFile& from);
|
||||
/** The parenthesis operator.
|
||||
*
|
||||
* \return true if a file is open.
|
||||
*/
|
||||
operator bool() const {return isOpen();}
|
||||
*
|
||||
* \return true if a file is open.
|
||||
*/
|
||||
operator bool() const { return isOpen(); }
|
||||
/**
|
||||
* \return user settable file attributes for success else -1.
|
||||
*/
|
||||
int attrib() {
|
||||
return m_fFile ? m_fFile->attrib() :
|
||||
m_xFile ? m_xFile->attrib() : -1;
|
||||
return m_fFile ? m_fFile->attrib() : m_xFile ? m_xFile->attrib() : -1;
|
||||
}
|
||||
/** Set file attributes
|
||||
*
|
||||
|
|
@ -82,22 +80,23 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool attrib(uint8_t bits) {
|
||||
return m_fFile ? m_fFile->attrib(bits) :
|
||||
m_xFile ? m_xFile->attrib(bits) : false;
|
||||
return m_fFile ? m_fFile->attrib(bits)
|
||||
: m_xFile ? m_xFile->attrib(bits)
|
||||
: false;
|
||||
}
|
||||
/** \return number of bytes available from the current position to EOF
|
||||
* or INT_MAX if more than INT_MAX bytes are available.
|
||||
*/
|
||||
int available() const {
|
||||
return m_fFile ? m_fFile->available() :
|
||||
m_xFile ? m_xFile->available() : 0;
|
||||
return m_fFile ? m_fFile->available() : m_xFile ? m_xFile->available() : 0;
|
||||
}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint64_t available64() const {
|
||||
return m_fFile ? m_fFile->available32() :
|
||||
m_xFile ? m_xFile->available64() : 0;
|
||||
return m_fFile ? m_fFile->available32()
|
||||
: m_xFile ? m_xFile->available64()
|
||||
: 0;
|
||||
}
|
||||
/** Clear writeError. */
|
||||
void clearWriteError() {
|
||||
|
|
@ -121,23 +120,29 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
|
||||
return m_fFile ? m_fFile->contiguousRange(bgnSector, endSector) :
|
||||
m_xFile ? m_xFile->contiguousRange(bgnSector, endSector) : false;
|
||||
return m_fFile ? m_fFile->contiguousRange(bgnSector, endSector)
|
||||
: m_xFile ? m_xFile->contiguousRange(bgnSector, endSector)
|
||||
: false;
|
||||
}
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster() const {
|
||||
return m_fFile ? m_fFile->curCluster() :
|
||||
m_xFile ? m_xFile->curCluster() : 0;
|
||||
return m_fFile ? m_fFile->curCluster()
|
||||
: m_xFile ? m_xFile->curCluster()
|
||||
: 0;
|
||||
}
|
||||
/** \return The current position for a file or directory. */
|
||||
uint64_t curPosition() const {
|
||||
return m_fFile ? m_fFile->curPosition() :
|
||||
m_xFile ? m_xFile->curPosition() : 0;
|
||||
return m_fFile ? m_fFile->curPosition()
|
||||
: m_xFile ? m_xFile->curPosition()
|
||||
: 0;
|
||||
}
|
||||
/** \return Total allocated length for file. */
|
||||
uint64_t dataLength() const {
|
||||
return m_fFile ? m_fFile->fileSize() : m_xFile ? m_xFile->dataLength() : 0;
|
||||
}
|
||||
/** \return Directory entry index. */
|
||||
uint32_t dirIndex() const {
|
||||
return m_fFile ? m_fFile->dirIndex() :
|
||||
m_xFile ? m_xFile->dirIndex() : 0;
|
||||
return m_fFile ? m_fFile->dirIndex() : m_xFile ? m_xFile->dirIndex() : 0;
|
||||
}
|
||||
/** Test for the existence of a file in a directory
|
||||
*
|
||||
|
|
@ -151,8 +156,9 @@ class FsBaseFile {
|
|||
* \return true if the file exists else false.
|
||||
*/
|
||||
bool exists(const char* path) {
|
||||
return m_fFile ? m_fFile->exists(path) :
|
||||
m_xFile ? m_xFile->exists(path) : false;
|
||||
return m_fFile ? m_fFile->exists(path)
|
||||
: m_xFile ? m_xFile->exists(path)
|
||||
: false;
|
||||
}
|
||||
/** get position for streams
|
||||
* \param[out] pos struct to receive position
|
||||
|
|
@ -161,13 +167,13 @@ class FsBaseFile {
|
|||
if (m_fFile) m_fFile->fgetpos(pos);
|
||||
if (m_xFile) m_xFile->fgetpos(pos);
|
||||
}
|
||||
/**
|
||||
/**
|
||||
* Get a string from a file.
|
||||
*
|
||||
* fgets() reads bytes from a file into the array pointed to by \a str, until
|
||||
* \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
|
||||
* or end-of-file is encountered. The string is then terminated
|
||||
* with a null byte.
|
||||
* \a num - 1 bytes are read, or a delimiter is read and transferred to \a
|
||||
* str, or end-of-file is encountered. The string is then terminated with a
|
||||
* null byte.
|
||||
*
|
||||
* fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
|
||||
* terminates the string for Windows text files which use CRLF for newline.
|
||||
|
|
@ -179,24 +185,26 @@ class FsBaseFile {
|
|||
* \param[in] delim Optional set of delimiters. The default is "\n".
|
||||
*
|
||||
* \return For success fgets() returns the length of the string in \a str.
|
||||
* If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
|
||||
* If no data is read, fgets() returns zero for EOF or -1 if an error
|
||||
* occurred.
|
||||
*/
|
||||
int fgets(char* str, int num, char* delim = nullptr) {
|
||||
return m_fFile ? m_fFile->fgets(str, num, delim) :
|
||||
m_xFile ? m_xFile->fgets(str, num, delim) : -1;
|
||||
return m_fFile ? m_fFile->fgets(str, num, delim)
|
||||
: m_xFile ? m_xFile->fgets(str, num, delim)
|
||||
: -1;
|
||||
}
|
||||
/** \return The total number of bytes in a file. */
|
||||
uint64_t fileSize() const {
|
||||
return m_fFile ? m_fFile->fileSize() :
|
||||
m_xFile ? m_xFile->fileSize() : 0;
|
||||
return m_fFile ? m_fFile->fileSize() : m_xFile ? m_xFile->fileSize() : 0;
|
||||
}
|
||||
/** \return Address of first sector or zero for empty file. */
|
||||
uint32_t firstSector() const {
|
||||
return m_fFile ? m_fFile->firstSector() :
|
||||
m_xFile ? m_xFile->firstSector() : 0;
|
||||
return m_fFile ? m_fFile->firstSector()
|
||||
: m_xFile ? m_xFile->firstSector()
|
||||
: 0;
|
||||
}
|
||||
/** Ensure that any bytes written to the file are saved to the SD card. */
|
||||
void flush() {sync();}
|
||||
void flush() { sync(); }
|
||||
/** set position for streams
|
||||
* \param[in] pos struct with value for new position
|
||||
*/
|
||||
|
|
@ -212,8 +220,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
|
||||
return m_fFile ? m_fFile->getAccessDateTime(pdate, ptime) :
|
||||
m_xFile ? m_xFile->getAccessDateTime(pdate, ptime) : false;
|
||||
return m_fFile ? m_fFile->getAccessDateTime(pdate, ptime)
|
||||
: m_xFile ? m_xFile->getAccessDateTime(pdate, ptime)
|
||||
: false;
|
||||
}
|
||||
/** Get a file's create date and time.
|
||||
*
|
||||
|
|
@ -223,13 +232,13 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
|
||||
return m_fFile ? m_fFile->getCreateDateTime(pdate, ptime) :
|
||||
m_xFile ? m_xFile->getCreateDateTime(pdate, ptime) : false;
|
||||
return m_fFile ? m_fFile->getCreateDateTime(pdate, ptime)
|
||||
: m_xFile ? m_xFile->getCreateDateTime(pdate, ptime)
|
||||
: false;
|
||||
}
|
||||
/** \return All error bits. */
|
||||
uint8_t getError() const {
|
||||
return m_fFile ? m_fFile->getError() :
|
||||
m_xFile ? m_xFile->getError() : 0XFF;
|
||||
return m_fFile ? m_fFile->getError() : m_xFile ? m_xFile->getError() : 0XFF;
|
||||
}
|
||||
/** Get a file's Modify date and time.
|
||||
*
|
||||
|
|
@ -239,8 +248,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
|
||||
return m_fFile ? m_fFile->getModifyDateTime(pdate, ptime) :
|
||||
m_xFile ? m_xFile->getModifyDateTime(pdate, ptime) : false;
|
||||
return m_fFile ? m_fFile->getModifyDateTime(pdate, ptime)
|
||||
: m_xFile ? m_xFile->getModifyDateTime(pdate, ptime)
|
||||
: false;
|
||||
}
|
||||
/**
|
||||
* Get a file's name followed by a zero byte.
|
||||
|
|
@ -253,14 +263,16 @@ class FsBaseFile {
|
|||
*/
|
||||
size_t getName(char* name, size_t len) {
|
||||
*name = 0;
|
||||
return m_fFile ? m_fFile->getName(name, len) :
|
||||
m_xFile ? m_xFile->getName(name, len) : 0;
|
||||
return m_fFile ? m_fFile->getName(name, len)
|
||||
: m_xFile ? m_xFile->getName(name, len)
|
||||
: 0;
|
||||
}
|
||||
|
||||
/** \return value of writeError */
|
||||
bool getWriteError() const {
|
||||
return m_fFile ? m_fFile->getWriteError() :
|
||||
m_xFile ? m_xFile->getWriteError() : true;
|
||||
return m_fFile ? m_fFile->getWriteError()
|
||||
: m_xFile ? m_xFile->getWriteError()
|
||||
: true;
|
||||
}
|
||||
/**
|
||||
* Check for FsBlockDevice busy.
|
||||
|
|
@ -268,63 +280,67 @@ class FsBaseFile {
|
|||
* \return true if busy else false.
|
||||
*/
|
||||
bool isBusy() {
|
||||
return m_fFile ? m_fFile->isBusy() :
|
||||
m_xFile ? m_xFile->isBusy() : true;
|
||||
return m_fFile ? m_fFile->isBusy() : m_xFile ? m_xFile->isBusy() : true;
|
||||
}
|
||||
/** \return True if the file is contiguous. */
|
||||
bool isContiguous() const {
|
||||
#if USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
return m_fFile ? m_fFile->isContiguous() :
|
||||
m_xFile ? m_xFile->isContiguous() : false;
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
return m_fFile ? m_fFile->isContiguous()
|
||||
: m_xFile ? m_xFile->isContiguous()
|
||||
: false;
|
||||
#else // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
return m_xFile ? m_xFile->isContiguous() : false;
|
||||
#endif // USE_FAT_FILE_FLAG_CONTIGUOUS
|
||||
}
|
||||
/** \return True if this is a directory else false. */
|
||||
bool isDir() const {
|
||||
return m_fFile ? m_fFile->isDir() :
|
||||
m_xFile ? m_xFile->isDir() : false;
|
||||
return m_fFile ? m_fFile->isDir() : m_xFile ? m_xFile->isDir() : false;
|
||||
}
|
||||
/** This function reports if the current file is a directory or not.
|
||||
* \return true if the file is a directory.
|
||||
*/
|
||||
bool isDirectory() const {return isDir();}
|
||||
bool isDirectory() const { return isDir(); }
|
||||
/** \return True if this is a normal file. */
|
||||
bool isFile() const {
|
||||
return m_fFile ? m_fFile->isFile() :
|
||||
m_xFile ? m_xFile->isFile() : false;
|
||||
return m_fFile ? m_fFile->isFile() : m_xFile ? m_xFile->isFile() : false;
|
||||
}
|
||||
/** \return True if this is a normal file or sub-directory. */
|
||||
bool isFileOrSubDir() const {
|
||||
return m_fFile ? m_fFile->isFileOrSubDir() :
|
||||
m_xFile ? m_xFile->isFileOrSubDir() : false;
|
||||
return m_fFile ? m_fFile->isFileOrSubDir()
|
||||
: m_xFile ? m_xFile->isFileOrSubDir()
|
||||
: false;
|
||||
}
|
||||
/** \return True if this is a hidden file else false. */
|
||||
bool isHidden() const {
|
||||
return m_fFile ? m_fFile->isHidden() :
|
||||
m_xFile ? m_xFile->isHidden() : false;
|
||||
return m_fFile ? m_fFile->isHidden()
|
||||
: m_xFile ? m_xFile->isHidden()
|
||||
: false;
|
||||
}
|
||||
/** \return True if this is an open file/directory else false. */
|
||||
bool isOpen() const {return m_fFile || m_xFile;}
|
||||
bool isOpen() const { return m_fFile || m_xFile; }
|
||||
/** \return True file is readable. */
|
||||
bool isReadable() const {
|
||||
return m_fFile ? m_fFile->isReadable() :
|
||||
m_xFile ? m_xFile->isReadable() : false;
|
||||
}
|
||||
return m_fFile ? m_fFile->isReadable()
|
||||
: m_xFile ? m_xFile->isReadable()
|
||||
: false;
|
||||
}
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {
|
||||
return m_fFile ? m_fFile->isReadOnly() :
|
||||
m_xFile ? m_xFile->isReadOnly() : false;
|
||||
return m_fFile ? m_fFile->isReadOnly()
|
||||
: m_xFile ? m_xFile->isReadOnly()
|
||||
: false;
|
||||
}
|
||||
/** \return True if this is a sub-directory file else false. */
|
||||
bool isSubDir() const {
|
||||
return m_fFile ? m_fFile->isSubDir() :
|
||||
m_xFile ? m_xFile->isSubDir() : false;
|
||||
return m_fFile ? m_fFile->isSubDir()
|
||||
: m_xFile ? m_xFile->isSubDir()
|
||||
: false;
|
||||
}
|
||||
/** \return True file is writable. */
|
||||
bool isWritable() const {
|
||||
return m_fFile ? m_fFile->isWritable() :
|
||||
m_xFile ? m_xFile->isWritable() : false;
|
||||
return m_fFile ? m_fFile->isWritable()
|
||||
: m_xFile ? m_xFile->isWritable()
|
||||
: false;
|
||||
}
|
||||
#if ENABLE_ARDUINO_SERIAL
|
||||
/** List directory contents.
|
||||
|
|
@ -336,14 +352,13 @@ class FsBaseFile {
|
|||
* LS_SIZE - %Print file size.
|
||||
*
|
||||
* LS_R - Recursive list of subdirectories.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(uint8_t flags) {
|
||||
return ls(&Serial, flags);
|
||||
}
|
||||
/** List directory contents. */
|
||||
bool ls() {
|
||||
return ls(&Serial);
|
||||
}
|
||||
bool ls(uint8_t flags) { return ls(&Serial, flags); }
|
||||
/** List directory contents.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls() { return ls(&Serial); }
|
||||
#endif // ENABLE_ARDUINO_SERIAL
|
||||
/** List directory contents.
|
||||
*
|
||||
|
|
@ -352,8 +367,7 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr) {
|
||||
return m_fFile ? m_fFile->ls(pr) :
|
||||
m_xFile ? m_xFile->ls(pr) : false;
|
||||
return m_fFile ? m_fFile->ls(pr) : m_xFile ? m_xFile->ls(pr) : false;
|
||||
}
|
||||
/** List directory contents.
|
||||
*
|
||||
|
|
@ -369,8 +383,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr, uint8_t flags) {
|
||||
return m_fFile ? m_fFile->ls(pr, flags) :
|
||||
m_xFile ? m_xFile->ls(pr, flags) : false;
|
||||
return m_fFile ? m_fFile->ls(pr, flags)
|
||||
: m_xFile ? m_xFile->ls(pr, flags)
|
||||
: false;
|
||||
}
|
||||
/** Make a new directory.
|
||||
*
|
||||
|
|
@ -412,10 +427,12 @@ class FsBaseFile {
|
|||
* O_CREAT - If the file exists, this flag has no effect except as noted
|
||||
* under O_EXCL below. Otherwise, the file shall be created
|
||||
*
|
||||
* O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
|
||||
* O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file
|
||||
* exists.
|
||||
*
|
||||
* O_TRUNC - If the file exists and is a regular file, and the file is
|
||||
* successfully opened and is not read only, its length shall be truncated to 0.
|
||||
* successfully opened and is not read only, its length shall be truncated to
|
||||
* 0.
|
||||
*
|
||||
* WARNING: A given file must not be opened by more than one file object
|
||||
* or file corruption may occur.
|
||||
|
|
@ -464,7 +481,7 @@ class FsBaseFile {
|
|||
bool open(const char* path, oflag_t oflag = O_RDONLY) {
|
||||
return FsVolume::m_cwv && open(FsVolume::m_cwv, path, oflag);
|
||||
}
|
||||
/** Open a file or directory by index in the current working directory.
|
||||
/** Open a file or directory by index in the current working directory.
|
||||
*
|
||||
* \param[in] index The \a index of the directory entry for the file to be
|
||||
* opened. The value for \a index is (directory file position)/32.
|
||||
|
|
@ -497,14 +514,13 @@ class FsBaseFile {
|
|||
*/
|
||||
bool openRoot(FsVolume* vol);
|
||||
/** \return the current file position. */
|
||||
uint64_t position() const {return curPosition();}
|
||||
uint64_t position() const { return curPosition(); }
|
||||
/** Return the next available byte without consuming it.
|
||||
*
|
||||
* \return The byte if no error and not at eof else -1;
|
||||
*/
|
||||
int peek() {
|
||||
return m_fFile ? m_fFile->peek() :
|
||||
m_xFile ? m_xFile->peek() : -1;
|
||||
return m_fFile ? m_fFile->peek() : m_xFile ? m_xFile->peek() : -1;
|
||||
}
|
||||
/** Allocate contiguous clusters to an empty file.
|
||||
*
|
||||
|
|
@ -518,8 +534,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool preAllocate(uint64_t length) {
|
||||
return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length) :
|
||||
m_xFile ? m_xFile->preAllocate(length) : false;
|
||||
return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length)
|
||||
: m_xFile ? m_xFile->preAllocate(length)
|
||||
: false;
|
||||
}
|
||||
/** Print a file's access date and time
|
||||
*
|
||||
|
|
@ -528,8 +545,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printAccessDateTime(pr) :
|
||||
m_xFile ? m_xFile->printAccessDateTime(pr) : 0;
|
||||
return m_fFile ? m_fFile->printAccessDateTime(pr)
|
||||
: m_xFile ? m_xFile->printAccessDateTime(pr)
|
||||
: 0;
|
||||
}
|
||||
/** Print a file's creation date and time
|
||||
*
|
||||
|
|
@ -538,8 +556,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printCreateDateTime(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printCreateDateTime(pr) :
|
||||
m_xFile ? m_xFile->printCreateDateTime(pr) : 0;
|
||||
return m_fFile ? m_fFile->printCreateDateTime(pr)
|
||||
: m_xFile ? m_xFile->printCreateDateTime(pr)
|
||||
: 0;
|
||||
}
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
|
|
@ -548,8 +567,9 @@ class FsBaseFile {
|
|||
* \return The number of bytes written or -1 if an error occurs.
|
||||
*/
|
||||
size_t printField(double value, char term, uint8_t prec = 2) {
|
||||
return m_fFile ? m_fFile->printField(value, term, prec) :
|
||||
m_xFile ? m_xFile->printField(value, term, prec) : 0;
|
||||
return m_fFile ? m_fFile->printField(value, term, prec)
|
||||
: m_xFile ? m_xFile->printField(value, term, prec)
|
||||
: 0;
|
||||
}
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
|
|
@ -558,17 +578,18 @@ class FsBaseFile {
|
|||
* \return The number of bytes written or -1 if an error occurs.
|
||||
*/
|
||||
size_t printField(float value, char term, uint8_t prec = 2) {
|
||||
return printField(static_cast<double>(value), term, prec);
|
||||
return printField(static_cast<double>(value), term, prec);
|
||||
}
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \return The number of bytes written or -1 if an error occurs.
|
||||
*/
|
||||
template<typename Type>
|
||||
template <typename Type>
|
||||
size_t printField(Type value, char term) {
|
||||
return m_fFile ? m_fFile->printField(value, term) :
|
||||
m_xFile ? m_xFile->printField(value, term) : 0;
|
||||
return m_fFile ? m_fFile->printField(value, term)
|
||||
: m_xFile ? m_xFile->printField(value, term)
|
||||
: 0;
|
||||
}
|
||||
/** Print a file's size.
|
||||
*
|
||||
|
|
@ -578,8 +599,9 @@ class FsBaseFile {
|
|||
* for success and zero is returned for failure.
|
||||
*/
|
||||
size_t printFileSize(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printFileSize(pr) :
|
||||
m_xFile ? m_xFile->printFileSize(pr) : 0;
|
||||
return m_fFile ? m_fFile->printFileSize(pr)
|
||||
: m_xFile ? m_xFile->printFileSize(pr)
|
||||
: 0;
|
||||
}
|
||||
/** Print a file's modify date and time
|
||||
*
|
||||
|
|
@ -588,8 +610,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printModifyDateTime(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printModifyDateTime(pr) :
|
||||
m_xFile ? m_xFile->printModifyDateTime(pr) : 0;
|
||||
return m_fFile ? m_fFile->printModifyDateTime(pr)
|
||||
: m_xFile ? m_xFile->printModifyDateTime(pr)
|
||||
: 0;
|
||||
}
|
||||
/** Print a file's name
|
||||
*
|
||||
|
|
@ -598,8 +621,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printName(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printName(pr) :
|
||||
m_xFile ? m_xFile->printName(pr) : 0;
|
||||
return m_fFile ? m_fFile->printName(pr)
|
||||
: m_xFile ? m_xFile->printName(pr)
|
||||
: 0;
|
||||
}
|
||||
/** Read the next byte from a file.
|
||||
*
|
||||
|
|
@ -624,8 +648,9 @@ class FsBaseFile {
|
|||
* or an I/O error occurred.
|
||||
*/
|
||||
int read(void* buf, size_t count) {
|
||||
return m_fFile ? m_fFile->read(buf, count) :
|
||||
m_xFile ? m_xFile->read(buf, count) : -1;
|
||||
return m_fFile ? m_fFile->read(buf, count)
|
||||
: m_xFile ? m_xFile->read(buf, count)
|
||||
: -1;
|
||||
}
|
||||
/** Remove a file.
|
||||
*
|
||||
|
|
@ -638,7 +663,7 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove();
|
||||
/** Remove a file.
|
||||
/** Remove a file.
|
||||
*
|
||||
* The directory entry and all data for the file are deleted.
|
||||
*
|
||||
|
|
@ -653,8 +678,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const char* path) {
|
||||
return m_fFile ? m_fFile->remove(path) :
|
||||
m_xFile ? m_xFile->remove(path) : false;
|
||||
return m_fFile ? m_fFile->remove(path)
|
||||
: m_xFile ? m_xFile->remove(path)
|
||||
: false;
|
||||
}
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
|
|
@ -663,8 +689,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rename(const char* newPath) {
|
||||
return m_fFile ? m_fFile->rename(newPath) :
|
||||
m_xFile ? m_xFile->rename(newPath) : false;
|
||||
return m_fFile ? m_fFile->rename(newPath)
|
||||
: m_xFile ? m_xFile->rename(newPath)
|
||||
: false;
|
||||
}
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
|
|
@ -674,9 +701,9 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rename(FsBaseFile* dir, const char* newPath) {
|
||||
return m_fFile && dir->m_fFile ? m_fFile->rename(dir->m_fFile, newPath) :
|
||||
m_xFile && dir->m_xFile ? m_xFile->rename(dir->m_xFile, newPath) :
|
||||
false;
|
||||
return m_fFile && dir->m_fFile ? m_fFile->rename(dir->m_fFile, newPath)
|
||||
: m_xFile && dir->m_xFile ? m_xFile->rename(dir->m_xFile, newPath)
|
||||
: false;
|
||||
}
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind() {
|
||||
|
|
@ -706,22 +733,18 @@ class FsBaseFile {
|
|||
* \param[in] pos the new file position.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seek(uint64_t pos) {return seekSet(pos);}
|
||||
bool seek(uint64_t pos) { return seekSet(pos); }
|
||||
/** Set the files position to current position + \a pos. See seekSet().
|
||||
* \param[in] offset The new position in bytes from the current position.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekCur(int64_t offset) {
|
||||
return seekSet(curPosition() + offset);
|
||||
}
|
||||
bool seekCur(int64_t offset) { return seekSet(curPosition() + offset); }
|
||||
/** Set the files position to end-of-file + \a offset. See seekSet().
|
||||
* Can't be used for directory files since file size is not defined.
|
||||
* \param[in] offset The new position in bytes from end-of-file.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekEnd(int64_t offset = 0) {
|
||||
return seekSet(fileSize() + offset);
|
||||
}
|
||||
bool seekEnd(int64_t offset = 0) { return seekSet(fileSize() + offset); }
|
||||
/** Sets a file's position.
|
||||
*
|
||||
* \param[in] pos The new position in bytes from the beginning of the file.
|
||||
|
|
@ -729,19 +752,19 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekSet(uint64_t pos) {
|
||||
return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet(pos) :
|
||||
m_xFile ? m_xFile->seekSet(pos) : false;
|
||||
return m_fFile ? pos < (1ULL << 32) && m_fFile->seekSet(pos)
|
||||
: m_xFile ? m_xFile->seekSet(pos)
|
||||
: false;
|
||||
}
|
||||
/** \return the file's size. */
|
||||
uint64_t size() const {return fileSize();}
|
||||
uint64_t size() const { return fileSize(); }
|
||||
/** The sync() call causes all modified data and directory fields
|
||||
* to be written to the storage device.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool sync() {
|
||||
return m_fFile ? m_fFile->sync() :
|
||||
m_xFile ? m_xFile->sync() : false;
|
||||
return m_fFile ? m_fFile->sync() : m_xFile ? m_xFile->sync() : false;
|
||||
}
|
||||
/** Set a file's timestamps in its directory entry.
|
||||
*
|
||||
|
|
@ -777,19 +800,20 @@ class FsBaseFile {
|
|||
*/
|
||||
bool timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
return m_fFile ?
|
||||
m_fFile->timestamp(flags, year, month, day, hour, minute, second) :
|
||||
m_xFile ?
|
||||
m_xFile->timestamp(flags, year, month, day, hour, minute, second) :
|
||||
false;
|
||||
return m_fFile ? m_fFile->timestamp(flags, year, month, day, hour, minute,
|
||||
second)
|
||||
: m_xFile ? m_xFile->timestamp(flags, year, month, day, hour, minute,
|
||||
second)
|
||||
: false;
|
||||
}
|
||||
/** Truncate a file to the current position.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool truncate() {
|
||||
return m_fFile ? m_fFile->truncate() :
|
||||
m_xFile ? m_xFile->truncate() : false;
|
||||
return m_fFile ? m_fFile->truncate()
|
||||
: m_xFile ? m_xFile->truncate()
|
||||
: false;
|
||||
}
|
||||
/** Truncate a file to a specified length.
|
||||
* The current file position will be set to end of file.
|
||||
|
|
@ -799,23 +823,22 @@ class FsBaseFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool truncate(uint64_t length) {
|
||||
return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length) :
|
||||
m_xFile ? m_xFile->truncate(length) : false;
|
||||
return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length)
|
||||
: m_xFile ? m_xFile->truncate(length)
|
||||
: false;
|
||||
}
|
||||
/** Write a string to a file. Used by the Arduino Print class.
|
||||
* \param[in] str Pointer to the string.
|
||||
* Use getWriteError to check for errors.
|
||||
* \return count of characters written for success or -1 for failure.
|
||||
*/
|
||||
size_t write(const char* str) {
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
size_t write(const char* str) { return write(str, strlen(str)); }
|
||||
/** Write a byte to a file. Required by the Arduino Print class.
|
||||
* \param[in] b the byte to be written.
|
||||
* Use getWriteError to check for errors.
|
||||
* \return 1 for success and 0 for failure.
|
||||
*/
|
||||
size_t write(uint8_t b) {return write(&b, 1);}
|
||||
size_t write(uint8_t b) { return write(&b, 1); }
|
||||
/** Write data to an open file.
|
||||
*
|
||||
* \note Data is moved to the cache but may not be written to the
|
||||
|
|
@ -829,13 +852,14 @@ class FsBaseFile {
|
|||
* \a nbyte. If an error occurs, write() returns zero and writeError is set.
|
||||
*/
|
||||
size_t write(const void* buf, size_t count) {
|
||||
return m_fFile ? m_fFile->write(buf, count) :
|
||||
m_xFile ? m_xFile->write(buf, count) : 0;
|
||||
return m_fFile ? m_fFile->write(buf, count)
|
||||
: m_xFile ? m_xFile->write(buf, count)
|
||||
: 0;
|
||||
}
|
||||
|
||||
private:
|
||||
newalign_t m_fileMem[FS_ALIGN_DIM(ExFatFile, FatFile)];
|
||||
FatFile* m_fFile = nullptr;
|
||||
FatFile* m_fFile = nullptr;
|
||||
ExFatFile* m_xFile = nullptr;
|
||||
};
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,14 +24,16 @@
|
|||
*/
|
||||
#ifndef FsFormatter_h
|
||||
#define FsFormatter_h
|
||||
#include "FatLib/FatLib.h"
|
||||
#include "ExFatLib/ExFatLib.h"
|
||||
#include "FatLib/FatLib.h"
|
||||
/**
|
||||
* \class FsFormatter
|
||||
* \brief Format a exFAT/FAT volume.
|
||||
*/
|
||||
class FsFormatter {
|
||||
public:
|
||||
/** Constructor. */
|
||||
FsFormatter() = default;
|
||||
/**
|
||||
* Format a FAT volume.
|
||||
*
|
||||
|
|
@ -46,10 +48,10 @@ class FsFormatter {
|
|||
if (sectorCount == 0) {
|
||||
return false;
|
||||
}
|
||||
return sectorCount <= 67108864 ?
|
||||
m_fFmt.format(dev, secBuffer, pr) :
|
||||
m_xFmt.format(dev, secBuffer, pr);
|
||||
return sectorCount <= 67108864 ? m_fFmt.format(dev, secBuffer, pr)
|
||||
: m_xFmt.format(dev, secBuffer, pr);
|
||||
}
|
||||
|
||||
private:
|
||||
FatFormatter m_fFmt;
|
||||
ExFatFormatter m_xFmt;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
* \file
|
||||
* \brief FsLib include file.
|
||||
*/
|
||||
#include "FsVolume.h"
|
||||
#include "FsFile.h"
|
||||
#include "FsFormatter.h"
|
||||
#include "FsVolume.h"
|
||||
#endif // FsLib_h
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ typedef uint32_t newalign_t;
|
|||
|
||||
/** Dimension of aligned area. */
|
||||
#define NEW_ALIGN_DIM(n) \
|
||||
(((size_t)(n) + sizeof(newalign_t) - 1U)/sizeof(newalign_t))
|
||||
(((size_t)(n) + sizeof(newalign_t) - 1U) / sizeof(newalign_t))
|
||||
|
||||
/** Dimension of aligned area for etype or ftype class. */
|
||||
#define FS_ALIGN_DIM(etype, ftype) NEW_ALIGN_DIM(FS_SIZE(etype, ftype))
|
||||
|
|
|
|||
|
|
@ -25,23 +25,22 @@
|
|||
#include "FsLib.h"
|
||||
FsVolume* FsVolume::m_cwv = nullptr;
|
||||
//------------------------------------------------------------------------------
|
||||
bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv,
|
||||
uint8_t part, uint32_t volStart) {
|
||||
m_blockDev = blockDev;
|
||||
bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv, uint8_t part,
|
||||
uint32_t volStart) {
|
||||
m_fVol = nullptr;
|
||||
m_xVol = new (m_volMem) ExFatVolume;
|
||||
if (m_xVol && m_xVol->begin(m_blockDev, false, part, volStart)) {
|
||||
if (m_xVol && m_xVol->begin(blockDev, false, part, volStart)) {
|
||||
goto done;
|
||||
}
|
||||
m_xVol = nullptr;
|
||||
m_fVol = new (m_volMem) FatVolume;
|
||||
if (m_fVol && m_fVol->begin(m_blockDev, false, part, volStart)) {
|
||||
if (m_fVol && m_fVol->begin(blockDev, false, part, volStart)) {
|
||||
goto done;
|
||||
}
|
||||
m_fVol = nullptr;
|
||||
return false;
|
||||
|
||||
done:
|
||||
done:
|
||||
if (setCwv || !m_cwv) {
|
||||
m_cwv = this;
|
||||
}
|
||||
|
|
@ -53,14 +52,14 @@ bool FsVolume::ls(print_t* pr, const char* path, uint8_t flags) {
|
|||
return dir.open(this, path, O_RDONLY) && dir.ls(pr, flags);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
FsFile FsVolume::open(const char *path, oflag_t oflag) {
|
||||
FsFile FsVolume::open(const char* path, oflag_t oflag) {
|
||||
FsFile tmpFile;
|
||||
tmpFile.open(this, path, oflag);
|
||||
return tmpFile;
|
||||
}
|
||||
#if ENABLE_ARDUINO_STRING
|
||||
//------------------------------------------------------------------------------
|
||||
FsFile FsVolume::open(const String &path, oflag_t oflag) {
|
||||
return open(path.c_str(), oflag );
|
||||
FsFile FsVolume::open(const String& path, oflag_t oflag) {
|
||||
return open(path.c_str(), oflag);
|
||||
}
|
||||
#endif // ENABLE_ARDUINO_STRING
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@
|
|||
* \file
|
||||
* \brief FsVolume include file.
|
||||
*/
|
||||
#include "FsNew.h"
|
||||
#include "../FatLib/FatLib.h"
|
||||
#include "../ExFatLib/ExFatLib.h"
|
||||
#include "../FatLib/FatLib.h"
|
||||
#include "FsNew.h"
|
||||
|
||||
class FsFile;
|
||||
/**
|
||||
|
|
@ -39,16 +39,15 @@ class FsFile;
|
|||
*/
|
||||
class FsVolume {
|
||||
public:
|
||||
FsVolume() {}
|
||||
FsVolume() = default;
|
||||
|
||||
~FsVolume() {end();}
|
||||
~FsVolume() { end(); }
|
||||
/** Get file's user settable attributes.
|
||||
* \param[in] path path to file.
|
||||
* \return user settable file attributes for success else -1.
|
||||
*/
|
||||
int attrib(const char* path) {
|
||||
return m_fVol ? m_fVol->attrib(path) :
|
||||
m_xVol ? m_xVol->attrib(path) : -1;
|
||||
return m_fVol ? m_fVol->attrib(path) : m_xVol ? m_xVol->attrib(path) : -1;
|
||||
}
|
||||
/** Set file's user settable attributes.
|
||||
* \param[in] path path to file.
|
||||
|
|
@ -58,8 +57,9 @@ class FsVolume {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool attrib(const char* path, uint8_t bits) {
|
||||
return m_fVol ? m_fVol->attrib(path, bits) :
|
||||
m_xVol ? m_xVol->attrib(path, bits) : false;
|
||||
return m_fVol ? m_fVol->attrib(path, bits)
|
||||
: m_xVol ? m_xVol->attrib(path, bits)
|
||||
: false;
|
||||
}
|
||||
/**
|
||||
* Initialize an FatVolume object.
|
||||
|
|
@ -69,44 +69,45 @@ class FsVolume {
|
|||
* \param[in] volStart Start sector of volume if part is zero.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t
|
||||
part = 1, uint32_t volStart = 0);
|
||||
bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t part = 1,
|
||||
uint32_t volStart = 0);
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/** \return the number of bytes in a cluster. */
|
||||
uint32_t bytesPerCluster() const {
|
||||
return m_fVol ? m_fVol->bytesPerCluster() :
|
||||
m_xVol ? m_xVol->bytesPerCluster() : 0;
|
||||
return m_fVol ? m_fVol->bytesPerCluster()
|
||||
: m_xVol ? m_xVol->bytesPerCluster()
|
||||
: 0;
|
||||
}
|
||||
/**
|
||||
* Set volume working directory to root.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool chdir() {
|
||||
return m_fVol ? m_fVol->chdir() :
|
||||
m_xVol ? m_xVol->chdir() : false;
|
||||
return m_fVol ? m_fVol->chdir() : m_xVol ? m_xVol->chdir() : false;
|
||||
}
|
||||
/**
|
||||
* Set volume working directory.
|
||||
* \param[in] path Path for volume working directory.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool chdir(const char* path) {
|
||||
return m_fVol ? m_fVol->chdir(path) :
|
||||
m_xVol ? m_xVol->chdir(path) : false;
|
||||
bool chdir(const char* path) {
|
||||
return m_fVol ? m_fVol->chdir(path) : m_xVol ? m_xVol->chdir(path) : false;
|
||||
}
|
||||
/** Change global working volume to this volume. */
|
||||
void chvol() {m_cwv = this;}
|
||||
void chvol() { m_cwv = this; }
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount() const {
|
||||
return m_fVol ? m_fVol->clusterCount() :
|
||||
m_xVol ? m_xVol->clusterCount() : 0;
|
||||
return m_fVol ? m_fVol->clusterCount()
|
||||
: m_xVol ? m_xVol->clusterCount()
|
||||
: 0;
|
||||
}
|
||||
/** \return The logical sector number for the start of file data. */
|
||||
uint32_t dataStartSector() const {
|
||||
return m_fVol ? m_fVol->dataStartSector() :
|
||||
m_xVol ? m_xVol->clusterHeapStartSector() : 0;
|
||||
return m_fVol ? m_fVol->dataStartSector()
|
||||
: m_xVol ? m_xVol->clusterHeapStartSector()
|
||||
: 0;
|
||||
}
|
||||
/** End access to volume
|
||||
* \return pointer to sector size buffer for format.
|
||||
|
|
@ -124,25 +125,27 @@ class FsVolume {
|
|||
* \return true if the file exists else false.
|
||||
*/
|
||||
bool exists(const char* path) {
|
||||
return m_fVol ? m_fVol->exists(path) :
|
||||
m_xVol ? m_xVol->exists(path) : false;
|
||||
return m_fVol ? m_fVol->exists(path)
|
||||
: m_xVol ? m_xVol->exists(path)
|
||||
: false;
|
||||
}
|
||||
/** \return The logical sector number for the start of the first FAT. */
|
||||
uint32_t fatStartSector() const {
|
||||
return m_fVol ? m_fVol->fatStartSector() :
|
||||
m_xVol ? m_xVol->fatStartSector() : 0;
|
||||
return m_fVol ? m_fVol->fatStartSector()
|
||||
: m_xVol ? m_xVol->fatStartSector()
|
||||
: 0;
|
||||
}
|
||||
/** \return Partition type, FAT_TYPE_EXFAT, FAT_TYPE_FAT32,
|
||||
* FAT_TYPE_FAT16, or zero for error.
|
||||
*/
|
||||
uint8_t fatType() const {
|
||||
return m_fVol ? m_fVol->fatType() :
|
||||
m_xVol ? m_xVol->fatType() : 0;
|
||||
return m_fVol ? m_fVol->fatType() : m_xVol ? m_xVol->fatType() : 0;
|
||||
}
|
||||
/** \return free cluster count or -1 if an error occurs. */
|
||||
int32_t freeClusterCount() const {
|
||||
return m_fVol ? m_fVol->freeClusterCount() :
|
||||
m_xVol ? m_xVol->freeClusterCount() : -1;
|
||||
return m_fVol ? m_fVol->freeClusterCount()
|
||||
: m_xVol ? m_xVol->freeClusterCount()
|
||||
: -1;
|
||||
}
|
||||
/**
|
||||
* Check for device busy.
|
||||
|
|
@ -150,8 +153,7 @@ class FsVolume {
|
|||
* \return true if busy else false.
|
||||
*/
|
||||
bool isBusy() {
|
||||
return m_fVol ? m_fVol->isBusy() :
|
||||
m_xVol ? m_xVol->isBusy() : false;
|
||||
return m_fVol ? m_fVol->isBusy() : m_xVol ? m_xVol->isBusy() : false;
|
||||
}
|
||||
/** List directory contents.
|
||||
*
|
||||
|
|
@ -160,8 +162,7 @@ class FsVolume {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr) {
|
||||
return m_fVol ? m_fVol->ls(pr) :
|
||||
m_xVol ? m_xVol->ls(pr) : false;
|
||||
return m_fVol ? m_fVol->ls(pr) : m_xVol ? m_xVol->ls(pr) : false;
|
||||
}
|
||||
/** List directory contents.
|
||||
*
|
||||
|
|
@ -177,8 +178,9 @@ class FsVolume {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr, uint8_t flags) {
|
||||
return m_fVol ? m_fVol->ls(pr, flags) :
|
||||
m_xVol ? m_xVol->ls(pr, flags) : false;
|
||||
return m_fVol ? m_fVol->ls(pr, flags)
|
||||
: m_xVol ? m_xVol->ls(pr, flags)
|
||||
: false;
|
||||
}
|
||||
/** List the directory contents of a directory.
|
||||
*
|
||||
|
|
@ -197,7 +199,7 @@ class FsVolume {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(print_t* pr, const char* path, uint8_t flags);
|
||||
/** Make a subdirectory in the volume root directory.
|
||||
/** Make a subdirectory in the volume root directory.
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
|
||||
*
|
||||
|
|
@ -205,9 +207,10 @@ class FsVolume {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool mkdir(const char *path, bool pFlag = true) {
|
||||
return m_fVol ? m_fVol->mkdir(path, pFlag) :
|
||||
m_xVol ? m_xVol->mkdir(path, pFlag) : false;
|
||||
bool mkdir(const char* path, bool pFlag = true) {
|
||||
return m_fVol ? m_fVol->mkdir(path, pFlag)
|
||||
: m_xVol ? m_xVol->mkdir(path, pFlag)
|
||||
: false;
|
||||
}
|
||||
/** open a file
|
||||
*
|
||||
|
|
@ -217,14 +220,15 @@ class FsVolume {
|
|||
*/
|
||||
FsFile open(const char* path, oflag_t oflag = O_RDONLY);
|
||||
/** Remove a file from the volume root directory.
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||
*
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const char *path) {
|
||||
return m_fVol ? m_fVol->remove(path) :
|
||||
m_xVol ? m_xVol->remove(path) : false;
|
||||
*/
|
||||
bool remove(const char* path) {
|
||||
return m_fVol ? m_fVol->remove(path)
|
||||
: m_xVol ? m_xVol->remove(path)
|
||||
: false;
|
||||
}
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
|
|
@ -240,9 +244,10 @@ class FsVolume {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rename(const char *oldPath, const char *newPath) {
|
||||
return m_fVol ? m_fVol->rename(oldPath, newPath) :
|
||||
m_xVol ? m_xVol->rename(oldPath, newPath) : false;
|
||||
bool rename(const char* oldPath, const char* newPath) {
|
||||
return m_fVol ? m_fVol->rename(oldPath, newPath)
|
||||
: m_xVol ? m_xVol->rename(oldPath, newPath)
|
||||
: false;
|
||||
}
|
||||
/** Remove a subdirectory from the volume's root directory.
|
||||
*
|
||||
|
|
@ -252,22 +257,20 @@ class FsVolume {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rmdir(const char *path) {
|
||||
return m_fVol ? m_fVol->rmdir(path) :
|
||||
m_xVol ? m_xVol->rmdir(path) : false;
|
||||
bool rmdir(const char* path) {
|
||||
return m_fVol ? m_fVol->rmdir(path) : m_xVol ? m_xVol->rmdir(path) : false;
|
||||
}
|
||||
/** \return The volume's cluster size in sectors. */
|
||||
uint32_t sectorsPerCluster() const {
|
||||
return m_fVol ? m_fVol->sectorsPerCluster() :
|
||||
m_xVol ? m_xVol->sectorsPerCluster() : 0;
|
||||
return m_fVol ? m_fVol->sectorsPerCluster()
|
||||
: m_xVol ? m_xVol->sectorsPerCluster()
|
||||
: 0;
|
||||
}
|
||||
#if ENABLE_ARDUINO_SERIAL
|
||||
/** List directory contents.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls() {
|
||||
return ls(&Serial);
|
||||
}
|
||||
bool ls() { return ls(&Serial); }
|
||||
/** List directory contents.
|
||||
*
|
||||
* \param[in] flags The inclusive OR of
|
||||
|
|
@ -280,9 +283,7 @@ class FsVolume {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool ls(uint8_t flags) {
|
||||
return ls(&Serial, flags);
|
||||
}
|
||||
bool ls(uint8_t flags) { return ls(&Serial, flags); }
|
||||
/** List the directory contents of a directory to Serial.
|
||||
*
|
||||
* \param[in] path directory to list.
|
||||
|
|
@ -309,18 +310,14 @@ class FsVolume {
|
|||
* \param[in] path Path for volume working directory.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool chdir(const String& path) {
|
||||
return chdir(path.c_str());
|
||||
}
|
||||
bool chdir(const String& path) { return chdir(path.c_str()); }
|
||||
/** Test for the existence of a file in a directory
|
||||
*
|
||||
* \param[in] path Path of the file to be tested for.
|
||||
*
|
||||
* \return true if the file exists else false.
|
||||
*/
|
||||
bool exists(const String &path) {
|
||||
return exists(path.c_str());
|
||||
}
|
||||
bool exists(const String& path) { return exists(path.c_str()); }
|
||||
/** Make a subdirectory in the volume root directory.
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
|
||||
|
|
@ -329,7 +326,7 @@ class FsVolume {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool mkdir(const String &path, bool pFlag = true) {
|
||||
bool mkdir(const String& path, bool pFlag = true) {
|
||||
return mkdir(path.c_str(), pFlag);
|
||||
}
|
||||
/** open a file
|
||||
|
|
@ -338,16 +335,14 @@ class FsVolume {
|
|||
* \param[in] oflag open flags.
|
||||
* \return a FsBaseFile object.
|
||||
*/
|
||||
FsFile open(const String &path, oflag_t oflag = O_RDONLY);
|
||||
FsFile open(const String& path, oflag_t oflag = O_RDONLY);
|
||||
/** Remove a file from the volume root directory.
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||
*
|
||||
*
|
||||
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const String &path) {
|
||||
return remove(path.c_str());
|
||||
}
|
||||
*/
|
||||
bool remove(const String& path) { return remove(path.c_str()); }
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
|
||||
|
|
@ -373,9 +368,7 @@ class FsVolume {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rmdir(const String &path) {
|
||||
return rmdir(path.c_str());
|
||||
}
|
||||
bool rmdir(const String& path) { return rmdir(path.c_str()); }
|
||||
/** Rename a file or subdirectory.
|
||||
*
|
||||
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
|
||||
|
|
@ -393,18 +386,17 @@ class FsVolume {
|
|||
#endif // ENABLE_ARDUINO_STRING
|
||||
|
||||
protected:
|
||||
newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)];
|
||||
newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)];
|
||||
|
||||
private:
|
||||
/** FsBaseFile allowed access to private members. */
|
||||
friend class FsBaseFile;
|
||||
static FsVolume* cwv() {return m_cwv;}
|
||||
static FsVolume* cwv() { return m_cwv; }
|
||||
FsVolume(const FsVolume& from);
|
||||
FsVolume& operator=(const FsVolume& from);
|
||||
|
||||
static FsVolume* m_cwv;
|
||||
FatVolume* m_fVol = nullptr;
|
||||
FatVolume* m_fVol = nullptr;
|
||||
ExFatVolume* m_xVol = nullptr;
|
||||
FsBlockDevice* m_blockDev;
|
||||
};
|
||||
#endif // FsVolume_h
|
||||
|
|
|
|||
|
|
@ -22,14 +22,11 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "common/SysCall.h"
|
||||
#if defined(UDR0) || defined(DOXYGEN)
|
||||
#include "MinimumSerial.h"
|
||||
const uint16_t MIN_2X_BAUD = F_CPU/(4*(2*0XFFF + 1)) + 1;
|
||||
#if defined(UDR0) || defined(DOXYGEN)
|
||||
const uint16_t MIN_2X_BAUD = F_CPU / (4 * (2 * 0XFFF + 1)) + 1;
|
||||
//------------------------------------------------------------------------------
|
||||
int MinimumSerial::available() {
|
||||
return UCSR0A & (1 << RXC0) ? 1 : 0;
|
||||
}
|
||||
int MinimumSerial::available() { return UCSR0A & (1 << RXC0) ? 1 : 0; }
|
||||
//------------------------------------------------------------------------------
|
||||
void MinimumSerial::begin(uint32_t baud) {
|
||||
uint16_t baud_setting;
|
||||
|
|
@ -53,7 +50,8 @@ void MinimumSerial::begin(uint32_t baud) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void MinimumSerial::flush() {
|
||||
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
|
||||
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
int MinimumSerial::read() {
|
||||
|
|
@ -64,7 +62,8 @@ int MinimumSerial::read() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
size_t MinimumSerial::write(uint8_t b) {
|
||||
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
|
||||
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {
|
||||
}
|
||||
UDR0 = b;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
/**
|
||||
* \file
|
||||
* \brief Minimal AVR Serial driver.
|
||||
*/
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
class MinimumSerial : public print_t {
|
||||
public:
|
||||
/** \return true for hardware serial */
|
||||
operator bool() {return true;}
|
||||
operator bool() { return true; }
|
||||
/**
|
||||
* \return one if data is available.
|
||||
*/
|
||||
|
|
|
|||
310
src/RingBuf.h
310
src/RingBuf.h
|
|
@ -28,22 +28,22 @@
|
|||
* \file
|
||||
* \brief Ring buffer for data loggers.
|
||||
*/
|
||||
#include "common/SysCall.h"
|
||||
#include "common/FmtNumber.h"
|
||||
#include "common/SysCall.h"
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// Teensy 3.5/3.6 has hard fault at 0x20000000 for unaligned memcpy.
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
inline bool is_aligned(const void* ptr, uintptr_t alignment) {
|
||||
auto iptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
return !(iptr % alignment);
|
||||
auto iptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
return !(iptr % alignment);
|
||||
}
|
||||
inline void memcpyBuf(void* dst, const void* src, size_t len) {
|
||||
const uint8_t* b = reinterpret_cast<const uint8_t*>(0X20000000UL);
|
||||
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
|
||||
const uint8_t *s = reinterpret_cast<const uint8_t*>(src);
|
||||
const uint8_t* s = reinterpret_cast<const uint8_t*>(src);
|
||||
if ((is_aligned(d, 4) && is_aligned(s, 4) && (len & 3) == 0) ||
|
||||
!((d < b && b <= (d + len)) || (s < b && b <= (s + len)))) {
|
||||
!((d < b && b <= (d + len)) || (s < b && b <= (s + len)))) {
|
||||
memcpy(dst, src, len);
|
||||
} else {
|
||||
while (len--) {
|
||||
|
|
@ -51,7 +51,7 @@ inline void memcpyBuf(void* dst, const void* src, size_t len) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
inline void memcpyBuf(void* dst, const void* src, size_t len) {
|
||||
memcpy(dst, src, len);
|
||||
}
|
||||
|
|
@ -59,23 +59,22 @@ inline void memcpyBuf(void* dst, const void* src, size_t len) {
|
|||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/**
|
||||
* \class RingBuf
|
||||
* \brief Ring buffer for data loggers.
|
||||
* \brief Ring buffer for data loggers and data transmitters.
|
||||
*
|
||||
* This ring buffer may be used in ISRs. bytesFreeIsr(), bytesUsedIsr(),
|
||||
* memcopyIn(), and memcopyOut() are ISR callable. For ISR use call
|
||||
* memcopyIn() in the ISR and use writeOut() in non-interrupt code
|
||||
* to write data to a file. readIn() and memcopyOut can be use in a
|
||||
* similar way to provide file data to an ISR.
|
||||
* This ring buffer may be used in ISRs. Use beginISR(), endISR(), write()
|
||||
* and print() in the ISR and use writeOut() in non-interrupt code
|
||||
* to write data to a file.
|
||||
*
|
||||
* Print into a RingBuf in an ISR should also work but has not been verified.
|
||||
* Use beginISR(), endISR() and read() in an ISR with readIn() in non-interrupt
|
||||
* code to provide file data to an ISR.
|
||||
*/
|
||||
template<class F, size_t Size>
|
||||
template <class F, size_t Size>
|
||||
class RingBuf : public Print {
|
||||
public:
|
||||
/**
|
||||
* RingBuf Constructor.
|
||||
*/
|
||||
RingBuf() {}
|
||||
RingBuf() { begin(nullptr); }
|
||||
/**
|
||||
* Initialize RingBuf.
|
||||
* \param[in] file Underlying file.
|
||||
|
|
@ -85,97 +84,41 @@ class RingBuf : public Print {
|
|||
m_count = 0;
|
||||
m_head = 0;
|
||||
m_tail = 0;
|
||||
m_inISR = false;
|
||||
clearWriteError();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* \return the RingBuf free space in bytes. Not ISR callable.
|
||||
* Disable protection of m_count by noInterrupts()/interrupts.
|
||||
*/
|
||||
size_t bytesFree() const {
|
||||
size_t count;
|
||||
noInterrupts();
|
||||
count = m_count;
|
||||
interrupts();
|
||||
return Size - count;
|
||||
}
|
||||
void beginISR() { m_inISR = true; }
|
||||
/**
|
||||
* \return the RingBuf free space in bytes. ISR callable.
|
||||
* \return the RingBuf free space in bytes.
|
||||
*/
|
||||
size_t bytesFreeIsr() const {
|
||||
return Size - m_count;
|
||||
}
|
||||
size_t bytesFree() const { return Size - bytesUsed(); }
|
||||
/**
|
||||
* \return the RingBuf used space in bytes. Not ISR callable.
|
||||
* \return the RingBuf used space in bytes.
|
||||
*/
|
||||
size_t bytesUsed() const {
|
||||
size_t count;
|
||||
noInterrupts();
|
||||
count = m_count;
|
||||
interrupts();
|
||||
return count;
|
||||
if (m_inISR) {
|
||||
return m_count;
|
||||
} else {
|
||||
noInterrupts();
|
||||
size_t rtn = m_count;
|
||||
interrupts();
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \return the RingBuf used space in bytes. ISR callable.
|
||||
* Enable protection of m_count by noInterrupts()/interrupts.
|
||||
*/
|
||||
size_t bytesUsedIsr() const {
|
||||
return m_count;
|
||||
}
|
||||
/**
|
||||
* Copy data to the RingBuf from buf.
|
||||
* The number of bytes copied may be less than count if
|
||||
* count is greater than bytesFree.
|
||||
*
|
||||
* This function may be used in an ISR with writeOut()
|
||||
* in non-interrupt code.
|
||||
*
|
||||
* \param[in] buf Location of data to be copied.
|
||||
* \param[in] count number of bytes to be copied.
|
||||
* \return Number of bytes actually copied.
|
||||
*/
|
||||
size_t memcpyIn(const void* buf, size_t count) {
|
||||
const uint8_t* src = (const uint8_t*)buf;
|
||||
size_t n = Size - m_count;
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
size_t nread = 0;
|
||||
while (nread != count) {
|
||||
n = minSize(Size - m_head, count - nread);
|
||||
memcpyBuf(m_buf + m_head, src + nread, n);
|
||||
m_head = advance(m_head, n);
|
||||
nread += n;
|
||||
}
|
||||
m_count += nread;
|
||||
return nread;
|
||||
}
|
||||
/**
|
||||
* Copy date from the RingBuf to buf.
|
||||
* The number of bytes copied may be less than count if
|
||||
* bytesUsed is less than count.
|
||||
*
|
||||
* This function may be used in an ISR with readIn() in
|
||||
* non-interrupt code.
|
||||
*
|
||||
* \param[out] buf Location to receive the data.
|
||||
* \param[in] count number of bytes to be copied.
|
||||
* \return Number of bytes actually copied.
|
||||
*/
|
||||
size_t memcpyOut(void* buf, size_t count) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||
size_t nwrite = 0;
|
||||
size_t n = m_count;
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
while (nwrite != count) {
|
||||
n = minSize(Size - m_tail, count - nwrite);
|
||||
memcpyBuf(dst + nwrite, m_buf + m_tail, n);
|
||||
m_tail = advance(m_tail, n);
|
||||
nwrite += n;
|
||||
}
|
||||
m_count -= nwrite;
|
||||
return nwrite;
|
||||
}
|
||||
void endISR() { m_inISR = false; }
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// See write(), read(), beginISR() and endISR().
|
||||
size_t __attribute__((error("use write(buf, count), beginISR(), endISR()")))
|
||||
memcpyIn(const void* buf, size_t count);
|
||||
size_t __attribute__((error("use read(buf, count), beginISR(), endISR()")))
|
||||
memcpyOut(void* buf, size_t count);
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
|
|
@ -211,7 +154,7 @@ class RingBuf : public Print {
|
|||
template <typename Type>
|
||||
size_t printField(Type value, char term) {
|
||||
char sign = 0;
|
||||
char buf[3*sizeof(Type) + 3];
|
||||
char buf[3 * sizeof(Type) + 3];
|
||||
char* str = buf + sizeof(buf);
|
||||
|
||||
if (term) {
|
||||
|
|
@ -234,34 +177,77 @@ class RingBuf : public Print {
|
|||
}
|
||||
return write((const uint8_t*)str, &buf[sizeof(buf)] - str);
|
||||
}
|
||||
/** Read data from RingBuf.
|
||||
* \param[out] buf destination for data.
|
||||
* \param[in] count number of bytes to read.
|
||||
* \return Actual count of bytes read.
|
||||
*/
|
||||
size_t read(void* buf, size_t count) {
|
||||
size_t n = bytesFree();
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||
n = minSize(Size - m_tail, count);
|
||||
if (n == count) {
|
||||
memcpyBuf(dst, m_buf + m_tail, n);
|
||||
m_tail = advance(m_tail, n);
|
||||
} else {
|
||||
memcpyBuf(dst, m_buf + m_tail, n);
|
||||
memcpyBuf(dst + n, m_buf, count - n);
|
||||
m_tail = count - n;
|
||||
}
|
||||
adjustCount(-count);
|
||||
return count;
|
||||
}
|
||||
/**
|
||||
* Efficient read for small types.
|
||||
*
|
||||
* \param[in] data location for data item.
|
||||
* \return true for success else false.
|
||||
*/
|
||||
template <typename Type>
|
||||
bool read(Type* data) {
|
||||
if (bytesUsed() < sizeof(Type)) {
|
||||
return false;
|
||||
}
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(data);
|
||||
for (size_t i = 0; i < sizeof(Type); i++) {
|
||||
ptr[i] = m_buf[m_tail];
|
||||
m_tail = advance(m_tail);
|
||||
}
|
||||
adjustCount(-sizeof(Type));
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Read data into the RingBuf from the underlying file.
|
||||
* the number of bytes read may be less than count if
|
||||
* bytesFree is less than count.
|
||||
*
|
||||
* This function may be used in non-interrupt code with
|
||||
* memcopyOut() in an ISR.
|
||||
* This function must not be used in an ISR.
|
||||
*
|
||||
* \param[in] count number of bytes to be read.
|
||||
* \return Number of bytes actually read.
|
||||
* \return Number of bytes actually read or negative for read error.
|
||||
*/
|
||||
size_t readIn(size_t count) {
|
||||
size_t nread = 0;
|
||||
size_t n = bytesFree(); // Protected from interrupts.
|
||||
int readIn(size_t count) {
|
||||
size_t n = bytesFree();
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
while (nread != count) {
|
||||
n = minSize(Size - m_head, count - nread);
|
||||
if ((size_t)m_file->read(m_buf + m_head, n) != n) {
|
||||
return nread;
|
||||
}
|
||||
m_head = advance(m_head, n);
|
||||
nread += n;
|
||||
n = minSize(Size - m_head, count);
|
||||
auto rtn = m_file->read(m_buf + m_head, n);
|
||||
if (rtn <= 0) {
|
||||
return rtn;
|
||||
}
|
||||
noInterrupts();
|
||||
m_count += nread;
|
||||
interrupts();
|
||||
size_t nread = rtn;
|
||||
if (n < count && nread == n) {
|
||||
rtn = m_file->read(m_buf, count - n);
|
||||
if (rtn > 0) {
|
||||
nread += rtn;
|
||||
}
|
||||
}
|
||||
m_head = advance(m_head, nread);
|
||||
adjustCount(nread);
|
||||
return nread;
|
||||
}
|
||||
/**
|
||||
|
|
@ -270,25 +256,36 @@ class RingBuf : public Print {
|
|||
*/
|
||||
bool sync() {
|
||||
size_t n = bytesUsed();
|
||||
return writeOut(n) == n;
|
||||
return n ? writeOut(n) == n : true;
|
||||
}
|
||||
/**
|
||||
* Copy data to the RingBuf from buf.
|
||||
*
|
||||
* The number of bytes copied may be less than count if
|
||||
* count is greater than bytesFree.
|
||||
* No data will be copied if count is greater than bytesFree.
|
||||
* Use getWriteError() to check for print errors and
|
||||
* clearWriteError() to clear error.
|
||||
* clearWriteError() to clear the error.
|
||||
*
|
||||
* \param[in] buf Location of data to be written.
|
||||
* \param[in] count number of bytes to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t write(const void* buf, size_t count) {
|
||||
if (count > bytesFree()) {
|
||||
if (bytesFree() < count) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
return memcpyIn(buf, count);
|
||||
const uint8_t* src = (const uint8_t*)buf;
|
||||
size_t n = minSize(Size - m_head, count);
|
||||
if (n == count) {
|
||||
memcpyBuf(m_buf + m_head, src, n);
|
||||
m_head = advance(m_head, n);
|
||||
} else {
|
||||
memcpyBuf(m_buf + m_head, src, n);
|
||||
memcpyBuf(m_buf, src + n, count - n);
|
||||
m_head = count - n;
|
||||
}
|
||||
adjustCount(count);
|
||||
return count;
|
||||
}
|
||||
/**
|
||||
* Copy str to RingBuf.
|
||||
|
|
@ -296,9 +293,7 @@ class RingBuf : public Print {
|
|||
* \param[in] str Location of data to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t write(const char* str) {
|
||||
return Print::write(str);
|
||||
}
|
||||
size_t write(const char* str) { return Print::write(str); }
|
||||
/**
|
||||
* Override virtual function in Print for efficiency.
|
||||
*
|
||||
|
|
@ -309,13 +304,35 @@ class RingBuf : public Print {
|
|||
size_t write(const uint8_t* buf, size_t count) override {
|
||||
return write((const void*)buf, count);
|
||||
}
|
||||
/**
|
||||
* Efficient write for small types.
|
||||
* \param[in] data Item to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
template <typename Type>
|
||||
size_t write(Type data) {
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(&data);
|
||||
if (bytesFree() < sizeof(Type)) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(Type); i++) {
|
||||
m_buf[m_head] = ptr[i];
|
||||
m_head = advance(m_head);
|
||||
}
|
||||
adjustCount(sizeof(Type));
|
||||
return sizeof(Type);
|
||||
}
|
||||
/**
|
||||
* Required function for Print.
|
||||
* \param[in] data Byte to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*
|
||||
* Try to force devirtualization by using final and always_inline.
|
||||
*/
|
||||
size_t write(uint8_t data) override {
|
||||
return write(&data, 1);
|
||||
size_t write(uint8_t data) final __attribute__((always_inline)) {
|
||||
// Use this if above does not compile size_t write(uint8_t data) final {
|
||||
return write<uint8_t>(data);
|
||||
}
|
||||
/**
|
||||
* Write data to file from RingBuf buffer.
|
||||
|
|
@ -324,43 +341,60 @@ class RingBuf : public Print {
|
|||
* The number of bytes written may be less than count if
|
||||
* bytesUsed is less than count or if an error occurs.
|
||||
*
|
||||
* This function may be used in non-interrupt code with
|
||||
* memcopyIn() in an ISR.
|
||||
* This function must only be used in non-interrupt code.
|
||||
*
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t writeOut(size_t count) {
|
||||
size_t n = bytesUsed(); // Protected from interrupts;
|
||||
if (count > n) {
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
size_t nwrite = 0;
|
||||
while (nwrite != count) {
|
||||
n = minSize(Size - m_tail, count - nwrite);
|
||||
if (m_file->write(m_buf + m_tail, n) != n) {
|
||||
break;
|
||||
}
|
||||
m_tail = advance(m_tail, n);
|
||||
nwrite += n;
|
||||
n = minSize(Size - m_tail, count);
|
||||
auto rtn = m_file->write(m_buf + m_tail, n);
|
||||
if (rtn <= 0) {
|
||||
return 0;
|
||||
}
|
||||
noInterrupts();
|
||||
m_count -= nwrite;
|
||||
interrupts();
|
||||
size_t nwrite = rtn;
|
||||
if (n < count && nwrite == n) {
|
||||
rtn = m_file->write(m_buf, count - n);
|
||||
if (rtn > 0) {
|
||||
nwrite += rtn;
|
||||
}
|
||||
}
|
||||
m_tail = advance(m_tail, nwrite);
|
||||
adjustCount(-nwrite);
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t __attribute__((aligned(4))) m_buf[Size];
|
||||
F* m_file = nullptr;
|
||||
F* m_file;
|
||||
volatile size_t m_count;
|
||||
size_t m_head;
|
||||
size_t m_tail;
|
||||
volatile bool m_inISR;
|
||||
|
||||
void adjustCount(int amount) {
|
||||
if (m_inISR) {
|
||||
m_count += amount;
|
||||
} else {
|
||||
noInterrupts();
|
||||
m_count += amount;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
size_t advance(size_t index) {
|
||||
if (!((Size - 1) & Size)) {
|
||||
return (index + 1) & (Size - 1);
|
||||
}
|
||||
return index + 1 < Size ? index + 1 : 0;
|
||||
}
|
||||
size_t advance(size_t index, size_t n) {
|
||||
index += n;
|
||||
return index < Size ? index : index - Size;
|
||||
}
|
||||
// avoid macro MIN
|
||||
size_t minSize(size_t a, size_t b) {return a < b ? a : b;}
|
||||
size_t minSize(size_t a, size_t b) { return a < b ? a : b; }
|
||||
};
|
||||
#endif // RingBuf_h
|
||||
|
|
|
|||
|
|
@ -22,13 +22,19 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief Top level include for SPI and SDIO cards.
|
||||
*/
|
||||
#ifndef SdCard_h
|
||||
#define SdCard_h
|
||||
#include "SdioCard.h"
|
||||
#include "SdSpiCard.h"
|
||||
#include "SdioCard.h"
|
||||
#if HAS_SDIO_CLASS
|
||||
/** Type for both SPI and SDIO cards. */
|
||||
typedef SdCardInterface SdCard;
|
||||
#else // HAS_SDIO_CLASS
|
||||
#else // HAS_SDIO_CLASS
|
||||
/** Type for SPI card. */
|
||||
typedef SdSpiCard SdCard;
|
||||
#endif // HAS_SDIO_CLASS
|
||||
/** Determine card configuration type.
|
||||
|
|
@ -36,13 +42,19 @@ typedef SdSpiCard SdCard;
|
|||
* \param[in] cfg Card configuration.
|
||||
* \return true if SPI.
|
||||
*/
|
||||
inline bool isSpi(SdSpiConfig cfg) {(void)cfg; return true;}
|
||||
inline bool isSpi(SdSpiConfig cfg) {
|
||||
(void)cfg;
|
||||
return true;
|
||||
}
|
||||
/** Determine card configuration type.
|
||||
*
|
||||
* \param[in] cfg Card configuration.
|
||||
* \return true if SPI.
|
||||
*/
|
||||
inline bool isSpi(SdioConfig cfg) {(void)cfg; return false;}
|
||||
inline bool isSpi(SdioConfig cfg) {
|
||||
(void)cfg;
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* \class SdCardFactory
|
||||
* \brief Setup a SPI card or SDIO card.
|
||||
|
|
@ -67,7 +79,7 @@ class SdCardFactory {
|
|||
#if HAS_SDIO_CLASS
|
||||
m_sdioCard.begin(config);
|
||||
return &m_sdioCard;
|
||||
#else // HAS_SDIO_CLASS
|
||||
#else // HAS_SDIO_CLASS
|
||||
(void)config;
|
||||
return nullptr;
|
||||
#endif // HAS_SDIO_CLASS
|
||||
|
|
|
|||
|
|
@ -25,21 +25,28 @@
|
|||
#include "SdCardInfo.h"
|
||||
//------------------------------------------------------------------------------
|
||||
#undef SD_CARD_ERROR
|
||||
#define SD_CARD_ERROR(e, m) case SD_CARD_ERROR_##e: pr->print(F(#e)); break;
|
||||
#define SD_CARD_ERROR(e, m) \
|
||||
case SD_CARD_ERROR_##e: \
|
||||
pr->print(F(#e)); \
|
||||
break;
|
||||
void printSdErrorSymbol(print_t* pr, uint8_t code) {
|
||||
pr->print(F("SD_CARD_ERROR_"));
|
||||
switch (code) {
|
||||
SD_ERROR_CODE_LIST
|
||||
default: pr->print(F("UNKNOWN"));
|
||||
default:
|
||||
pr->print(F("UNKNOWN"));
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
#undef SD_CARD_ERROR
|
||||
#define SD_CARD_ERROR(e, m) case SD_CARD_ERROR_##e: pr->print(F(m)); break;
|
||||
#define SD_CARD_ERROR(e, m) \
|
||||
case SD_CARD_ERROR_##e: \
|
||||
pr->print(F(m)); \
|
||||
break;
|
||||
void printSdErrorText(print_t* pr, uint8_t code) {
|
||||
switch
|
||||
(code) {
|
||||
switch (code) {
|
||||
SD_ERROR_CODE_LIST
|
||||
default: pr->print(F("Unknown error"));
|
||||
default:
|
||||
pr->print(F("Unknown error"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,14 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief Definitions for SD cards.
|
||||
*/
|
||||
#ifndef SdCardInfo_h
|
||||
#define SdCardInfo_h
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../common/SysCall.h"
|
||||
// Based on the document:
|
||||
//
|
||||
|
|
@ -43,73 +48,81 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// SD card errors
|
||||
// See the SD Specification for command info.
|
||||
#define SD_ERROR_CODE_LIST\
|
||||
SD_CARD_ERROR(NONE, "No error")\
|
||||
SD_CARD_ERROR(CMD0, "Card reset failed")\
|
||||
SD_CARD_ERROR(CMD2, "SDIO read CID")\
|
||||
SD_CARD_ERROR(CMD3, "SDIO publish RCA")\
|
||||
SD_CARD_ERROR(CMD6, "Switch card function")\
|
||||
SD_CARD_ERROR(CMD7, "SDIO card select")\
|
||||
SD_CARD_ERROR(CMD8, "Send and check interface settings")\
|
||||
SD_CARD_ERROR(CMD9, "Read CSD data")\
|
||||
SD_CARD_ERROR(CMD10, "Read CID data")\
|
||||
SD_CARD_ERROR(CMD12, "Stop multiple block read")\
|
||||
SD_CARD_ERROR(CMD13, "Read card status")\
|
||||
SD_CARD_ERROR(CMD17, "Read single block")\
|
||||
SD_CARD_ERROR(CMD18, "Read multiple blocks")\
|
||||
SD_CARD_ERROR(CMD24, "Write single block")\
|
||||
SD_CARD_ERROR(CMD25, "Write multiple blocks")\
|
||||
SD_CARD_ERROR(CMD32, "Set first erase block")\
|
||||
SD_CARD_ERROR(CMD33, "Set last erase block")\
|
||||
SD_CARD_ERROR(CMD38, "Erase selected blocks")\
|
||||
SD_CARD_ERROR(CMD58, "Read OCR register")\
|
||||
SD_CARD_ERROR(CMD59, "Set CRC mode")\
|
||||
SD_CARD_ERROR(ACMD6, "Set SDIO bus width")\
|
||||
SD_CARD_ERROR(ACMD13, "Read extended status")\
|
||||
SD_CARD_ERROR(ACMD23, "Set pre-erased count")\
|
||||
SD_CARD_ERROR(ACMD41, "Activate card initialization")\
|
||||
SD_CARD_ERROR(ACMD51, "Read SCR data")\
|
||||
SD_CARD_ERROR(READ_TOKEN, "Bad read data token")\
|
||||
SD_CARD_ERROR(READ_CRC, "Read CRC error")\
|
||||
SD_CARD_ERROR(READ_FIFO, "SDIO fifo read timeout")\
|
||||
SD_CARD_ERROR(READ_REG, "Read CID or CSD failed.")\
|
||||
SD_CARD_ERROR(READ_START, "Bad readStart argument")\
|
||||
SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout")\
|
||||
SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed")\
|
||||
SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete")\
|
||||
SD_CARD_ERROR(WRITE_DATA, "Write data not accepted")\
|
||||
SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout")\
|
||||
SD_CARD_ERROR(WRITE_START, "Bad writeStart argument")\
|
||||
SD_CARD_ERROR(WRITE_PROGRAMMING, "Flash programming")\
|
||||
SD_CARD_ERROR(WRITE_TIMEOUT, "Write timeout")\
|
||||
SD_CARD_ERROR(DMA, "DMA transfer failed")\
|
||||
SD_CARD_ERROR(ERASE, "Card did not accept erase commands")\
|
||||
SD_CARD_ERROR(ERASE_SINGLE_SECTOR, "Card does not support erase")\
|
||||
SD_CARD_ERROR(ERASE_TIMEOUT, "Erase command timeout")\
|
||||
SD_CARD_ERROR(INIT_NOT_CALLED, "Card has not been initialized")\
|
||||
SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config")\
|
||||
/** Define error codes and brief description. */
|
||||
#define SD_ERROR_CODE_LIST \
|
||||
SD_CARD_ERROR(NONE, "No error") \
|
||||
SD_CARD_ERROR(CMD0, "Card reset failed") \
|
||||
SD_CARD_ERROR(CMD2, "SDIO read CID") \
|
||||
SD_CARD_ERROR(CMD3, "SDIO publish RCA") \
|
||||
SD_CARD_ERROR(CMD6, "Switch card function") \
|
||||
SD_CARD_ERROR(CMD7, "SDIO card select") \
|
||||
SD_CARD_ERROR(CMD8, "Send and check interface settings") \
|
||||
SD_CARD_ERROR(CMD9, "Read CSD data") \
|
||||
SD_CARD_ERROR(CMD10, "Read CID data") \
|
||||
SD_CARD_ERROR(CMD12, "Stop multiple block read") \
|
||||
SD_CARD_ERROR(CMD13, "Read card status") \
|
||||
SD_CARD_ERROR(CMD17, "Read single block") \
|
||||
SD_CARD_ERROR(CMD18, "Read multiple blocks") \
|
||||
SD_CARD_ERROR(CMD24, "Write single block") \
|
||||
SD_CARD_ERROR(CMD25, "Write multiple blocks") \
|
||||
SD_CARD_ERROR(CMD32, "Set first erase block") \
|
||||
SD_CARD_ERROR(CMD33, "Set last erase block") \
|
||||
SD_CARD_ERROR(CMD38, "Erase selected blocks") \
|
||||
SD_CARD_ERROR(CMD58, "Read OCR register") \
|
||||
SD_CARD_ERROR(CMD59, "Set CRC mode") \
|
||||
SD_CARD_ERROR(ACMD6, "Set SDIO bus width") \
|
||||
SD_CARD_ERROR(ACMD13, "Read extended status") \
|
||||
SD_CARD_ERROR(ACMD23, "Set pre-erased count") \
|
||||
SD_CARD_ERROR(ACMD41, "Activate card initialization") \
|
||||
SD_CARD_ERROR(ACMD51, "Read SCR data") \
|
||||
SD_CARD_ERROR(READ_TOKEN, "Bad read data token") \
|
||||
SD_CARD_ERROR(READ_CRC, "Read CRC error") \
|
||||
SD_CARD_ERROR(READ_FIFO, "SDIO fifo read timeout") \
|
||||
SD_CARD_ERROR(READ_REG, "Read CID or CSD failed.") \
|
||||
SD_CARD_ERROR(READ_START, "Bad readStart argument") \
|
||||
SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout") \
|
||||
SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed") \
|
||||
SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete") \
|
||||
SD_CARD_ERROR(WRITE_DATA, "Write data not accepted") \
|
||||
SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout") \
|
||||
SD_CARD_ERROR(WRITE_START, "Bad writeStart argument") \
|
||||
SD_CARD_ERROR(WRITE_PROGRAMMING, "Flash programming") \
|
||||
SD_CARD_ERROR(WRITE_TIMEOUT, "Write timeout") \
|
||||
SD_CARD_ERROR(DMA, "DMA transfer failed") \
|
||||
SD_CARD_ERROR(ERASE, "Card did not accept erase commands") \
|
||||
SD_CARD_ERROR(ERASE_SINGLE_SECTOR, "Card does not support erase") \
|
||||
SD_CARD_ERROR(ERASE_TIMEOUT, "Erase command timeout") \
|
||||
SD_CARD_ERROR(INIT_NOT_CALLED, "Card has not been initialized") \
|
||||
SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config") \
|
||||
SD_CARD_ERROR(FUNCTION_NOT_SUPPORTED, "Unsupported SDIO command")
|
||||
|
||||
enum {
|
||||
/** Macro for generation of error codes using an enum. */
|
||||
#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e,
|
||||
SD_ERROR_CODE_LIST
|
||||
#undef SD_CARD_ERROR
|
||||
SD_CARD_ERROR_UNKNOWN
|
||||
SD_CARD_ERROR_UNKNOWN
|
||||
};
|
||||
/** Print the enum symbol for an error code.
|
||||
* \param[in] pr Print stream.
|
||||
* \param[in] code enum value for error.
|
||||
*/
|
||||
void printSdErrorSymbol(print_t* pr, uint8_t code);
|
||||
/** Print text for an error code.
|
||||
* \param[in] pr Print stream.
|
||||
* \param[in] code enum value for error.
|
||||
*/
|
||||
void printSdErrorText(print_t* pr, uint8_t code);
|
||||
//------------------------------------------------------------------------------
|
||||
// card types
|
||||
/** Standard capacity V1 SD card */
|
||||
const uint8_t SD_CARD_TYPE_SD1 = 1;
|
||||
const uint8_t SD_CARD_TYPE_SD1 = 1;
|
||||
/** Standard capacity V2 SD card */
|
||||
const uint8_t SD_CARD_TYPE_SD2 = 2;
|
||||
const uint8_t SD_CARD_TYPE_SD2 = 2;
|
||||
/** High Capacity SD card */
|
||||
const uint8_t SD_CARD_TYPE_SDHC = 3;
|
||||
//------------------------------------------------------------------------------
|
||||
// SD operation timeouts
|
||||
/** CMD0 retry count */
|
||||
const uint8_t SD_CMD0_RETRY = 10;
|
||||
/** command timeout ms */
|
||||
const uint16_t SD_CMD_TIMEOUT = 300;
|
||||
/** erase timeout ms */
|
||||
|
|
@ -186,7 +199,7 @@ const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30;
|
|||
/** The transferred sector length is not allowed for this card. */
|
||||
const uint32_t CARD_STATUS_SECTOR_LEN_ERROR = 1UL << 29;
|
||||
/** An error in the sequence of erase commands occurred. */
|
||||
const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL <<28;
|
||||
const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL << 28;
|
||||
/** An invalid selection of write-sectors for erase occurred. */
|
||||
const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27;
|
||||
/** Set when the host attempts to write to a protected sector. */
|
||||
|
|
@ -207,7 +220,7 @@ const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20;
|
|||
const uint32_t CARD_STATUS_ERROR = 1UL << 19;
|
||||
// bits 19, 18, and 17 reserved.
|
||||
/** Permanent WP set or attempt to change read only values of CSD. */
|
||||
const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL <<16;
|
||||
const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL << 16;
|
||||
/** partial address space was erased due to write protect. */
|
||||
const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15;
|
||||
/** The command has been executed without using the internal ECC. */
|
||||
|
|
@ -260,10 +273,10 @@ const uint8_t DATA_RES_MASK = 0X1F;
|
|||
const uint8_t DATA_RES_ACCEPTED = 0X05;
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class CID
|
||||
* \brief Card IDentification (CID) register.
|
||||
* \class cid_t
|
||||
* \brief Card Identification (CID) register.
|
||||
*/
|
||||
typedef struct CID {
|
||||
struct cid_t {
|
||||
// byte 0
|
||||
/** Manufacturer ID */
|
||||
uint8_t mid;
|
||||
|
|
@ -287,27 +300,25 @@ typedef struct CID {
|
|||
uint8_t crc;
|
||||
// Extract big endian fields.
|
||||
/** \return major revision number. */
|
||||
int prvN() const {return prv >> 4;}
|
||||
int prvN() const { return prv >> 4; }
|
||||
/** \return minor revision number. */
|
||||
int prvM() const {return prv & 0XF;}
|
||||
int prvM() const { return prv & 0XF; }
|
||||
/** \return Manufacturing Year. */
|
||||
int mdtYear() const {return 2000 + ((mdt[0] & 0XF) << 4) + (mdt[1] >> 4);}
|
||||
int mdtYear() const { return 2000 + ((mdt[0] & 0XF) << 4) + (mdt[1] >> 4); }
|
||||
/** \return Manufacturing Month. */
|
||||
int mdtMonth() const {return mdt[1] & 0XF;}
|
||||
int mdtMonth() const { return mdt[1] & 0XF; }
|
||||
/** \return Product Serial Number. */
|
||||
uint32_t psn() const {
|
||||
return (uint32_t)psn8[0] << 24 |
|
||||
(uint32_t)psn8[1] << 16 |
|
||||
(uint32_t)psn8[2] << 8 |
|
||||
(uint32_t)psn8[3];
|
||||
return (uint32_t)psn8[0] << 24 | (uint32_t)psn8[1] << 16 |
|
||||
(uint32_t)psn8[2] << 8 | (uint32_t)psn8[3];
|
||||
}
|
||||
} __attribute__((packed)) cid_t;
|
||||
} __attribute__((packed));
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class CSD
|
||||
* \class csd_t
|
||||
* \brief Union of old and new style CSD register.
|
||||
*/
|
||||
typedef struct CSD {
|
||||
struct csd_t {
|
||||
/** union of all CSD versions */
|
||||
uint8_t csd[16];
|
||||
// Extract big endian fields.
|
||||
|
|
@ -331,45 +342,45 @@ typedef struct CSD {
|
|||
}
|
||||
}
|
||||
/** \return true if erase granularity is single block. */
|
||||
bool eraseSingleBlock() const {return csd[10] & 0X40;}
|
||||
bool eraseSingleBlock() const { return csd[10] & 0X40; }
|
||||
/** \return erase size in 512 byte blocks if eraseSingleBlock is false. */
|
||||
int eraseSize() const {return ((csd[10] & 0X3F) << 1 | csd[11] >> 7) + 1;}
|
||||
int eraseSize() const { return ((csd[10] & 0X3F) << 1 | csd[11] >> 7) + 1; }
|
||||
/** \return true if the contents is copied or true if original. */
|
||||
bool copy() const {return csd[14] & 0X40;}
|
||||
bool copy() const { return csd[14] & 0X40; }
|
||||
/** \return true if the entire card is permanently write protected. */
|
||||
bool permWriteProtect() const {return csd[14] & 0X20;}
|
||||
bool permWriteProtect() const { return csd[14] & 0X20; }
|
||||
/** \return true if the entire card is temporarily write protected. */
|
||||
bool tempWriteProtect() const {return csd[14] & 0X10;}
|
||||
} csd_t;
|
||||
bool tempWriteProtect() const { return csd[14] & 0X10; }
|
||||
};
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class SCR
|
||||
* \class scr_t
|
||||
* \brief SCR register.
|
||||
*/
|
||||
typedef struct SCR {
|
||||
struct scr_t {
|
||||
/** Bytes 0-3 SD Association, bytes 4-7 reserved for manufacturer. */
|
||||
uint8_t scr[8];
|
||||
/** \return SCR_STRUCTURE field - must be zero.*/
|
||||
uint8_t srcStructure() {return scr[0] >> 4;}
|
||||
uint8_t srcStructure() const { return scr[0] >> 4; }
|
||||
/** \return SD_SPEC field 0 - v1.0 or V1.01, 1 - 1.10, 2 - V2.00 or greater */
|
||||
uint8_t sdSpec() {return scr[0] & 0XF;}
|
||||
uint8_t sdSpec() const { return scr[0] & 0XF; }
|
||||
/** \return false if all zero, true if all one. */
|
||||
bool dataAfterErase() {return 0X80 & scr[1];}
|
||||
bool dataAfterErase() const { return scr[1] & 0X80; }
|
||||
/** \return CPRM Security Version. */
|
||||
uint8_t sdSecurity() {return (scr[1] >> 4) & 0X7;}
|
||||
uint8_t sdSecurity() const { return (scr[1] >> 4) & 0X7; }
|
||||
/** \return 0101b. */
|
||||
uint8_t sdBusWidths() {return scr[1] & 0XF;}
|
||||
uint8_t sdBusWidths() const { return scr[1] & 0XF; }
|
||||
/** \return true if V3.0 or greater. */
|
||||
bool sdSpec3() {return scr[2] & 0X80;}
|
||||
bool sdSpec3() const { return scr[2] & 0X80; }
|
||||
/** \return if true and sdSpecX is zero V4.xx. */
|
||||
bool sdSpec4() {return scr[2] & 0X4;}
|
||||
bool sdSpec4() const { return scr[2] & 0X4; }
|
||||
/** \return nonzero for version 5 or greater if sdSpec == 2,
|
||||
sdSpec3 == true. Version is return plus four.*/
|
||||
uint8_t sdSpecX() {return (scr[2] & 0X3) << 2 | scr[3] >> 6;}
|
||||
uint8_t sdSpecX() const { return (scr[2] & 0X3) << 2 | scr[3] >> 6; }
|
||||
/** \return bit map for support CMD58/59, CMD48/49, CMD23, and CMD20 */
|
||||
uint8_t cmdSupport() {return scr[3] &0XF;}
|
||||
uint8_t cmdSupport() const { return scr[3] & 0XF; }
|
||||
/** \return SD spec version */
|
||||
int16_t sdSpecVer() {
|
||||
int16_t sdSpecVer() const {
|
||||
if (sdSpec() > 2) {
|
||||
return -1;
|
||||
} else if (sdSpec() < 2) {
|
||||
|
|
@ -379,42 +390,88 @@ typedef struct SCR {
|
|||
} else if (!sdSpec4() && !sdSpecX()) {
|
||||
return 300;
|
||||
}
|
||||
return 400 + 100*sdSpecX();
|
||||
return 400 + 100 * sdSpecX();
|
||||
}
|
||||
} scr_t;
|
||||
};
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
/**
|
||||
* \class sds_t
|
||||
* \brief SD Status.
|
||||
*/
|
||||
// fields are big endian
|
||||
typedef struct SdStatus {
|
||||
//
|
||||
struct sds_t {
|
||||
/** byte 0, bit 7-6 width, bit 5 secured mode, bits 4-0 reserved. */
|
||||
uint8_t busWidthSecureMode;
|
||||
/** byte 1 reserved */
|
||||
uint8_t reserved1;
|
||||
// byte 2
|
||||
/** byte 2-3 zero for SD rd/wr memory card. */
|
||||
uint8_t sdCardType[2];
|
||||
// byte 4
|
||||
/** byte 4-7 size of protected area big endian */
|
||||
uint8_t sizeOfProtectedArea[4];
|
||||
// byte 8
|
||||
uint8_t speedClass;
|
||||
// byte 9
|
||||
/** byte 8 speed class. */
|
||||
uint8_t speed;
|
||||
/** byte 9 performance move */
|
||||
uint8_t performanceMove;
|
||||
// byte 10
|
||||
/** byte 10 AU size code. */
|
||||
uint8_t auSize;
|
||||
// byte 11
|
||||
/** byte 11-12 erase size big endian */
|
||||
uint8_t eraseSize[2];
|
||||
// byte 13
|
||||
/** byte 13 erase timeout and erase offset */
|
||||
uint8_t eraseTimeoutOffset;
|
||||
// byte 14
|
||||
uint8_t uhsSpeedAuSize;
|
||||
// byte 15
|
||||
uint8_t videoSpeed;
|
||||
// byte 16
|
||||
/** byte 14 */
|
||||
uint8_t uhsClassAuSize;
|
||||
/** byte 15 */
|
||||
uint8_t videoSpeedClass;
|
||||
/** byte 16-17 */
|
||||
uint8_t vscAuSize[2];
|
||||
// byte 18
|
||||
/** byte 18-21 */
|
||||
uint8_t susAddr[3];
|
||||
// byte 21
|
||||
uint8_t reserved2[3];
|
||||
// byte 24
|
||||
/** byte 21 */
|
||||
uint8_t appPerfClass;
|
||||
/** byte 22 */
|
||||
uint8_t perfEnhance;
|
||||
/** byte 23 */
|
||||
uint8_t discardFule;
|
||||
/** byte 24 */
|
||||
uint8_t reservedManufacturer[40];
|
||||
} SdStatus_t;
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
/** \return appClass. */
|
||||
int appClass() { return appPerfClass; }
|
||||
/** \return AU size in KB. or zero for error. */
|
||||
uint32_t auSizeKB() {
|
||||
// 0XF mask and uint16_t array helps compiler optimize size on Uno.
|
||||
uint8_t val = (auSize >> 4) & 0XF;
|
||||
static const uint16_t au[] = {0, 16, 32, 64, 128,
|
||||
256, 512, 1024, 2048, 4096,
|
||||
8192, 12288, 16384, 24576, 32768};
|
||||
return val < 0XF ? au[val] : 65536UL;
|
||||
}
|
||||
/** \return current bus width or -1 for error. */
|
||||
uint8_t busWidth() const {
|
||||
uint8_t w = busWidthSecureMode >> 6;
|
||||
return w == 2 ? 4 : w == 0 ? 1 : -1;
|
||||
}
|
||||
/** \return true is discard operation is supported else true. */
|
||||
bool discard() const { return discardFule & 2; }
|
||||
/** \return eraseSize in AUs. */
|
||||
uint16_t eraseSizeAU() const {
|
||||
return (uint16_t)eraseSize[0] << 8 | (uint16_t)eraseSize[1];
|
||||
}
|
||||
/** \return eraseTimeout seconds. */
|
||||
uint8_t eraseTimeout() const { return eraseTimeoutOffset >> 2; }
|
||||
/** \return eraseOffset seconds. */
|
||||
uint8_t eraseOffset() const { return eraseTimeoutOffset & 3; }
|
||||
/** \return true if full user logical erase is supported else false. */
|
||||
bool fule() const { return discardFule & 1; }
|
||||
/** \return true for secure mode else false. */
|
||||
bool secureMode() const { return busWidthSecureMode & 0X20; }
|
||||
/** \return speed class or -1 for error. */
|
||||
int speedClass() const {
|
||||
return speed < 4 ? 2 * speed : speed == 4 ? 10 : -1;
|
||||
}
|
||||
/** \return UHS Speed Grade. */
|
||||
int uhsClass() const { return uhsClassAuSize >> 4; }
|
||||
/** \return Video Speed */
|
||||
int videoClass() { return videoSpeedClass; }
|
||||
};
|
||||
#endif // SdCardInfo_h
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief Abstract interface for an SD card.
|
||||
*/
|
||||
#ifndef SdCardInterface_h
|
||||
#define SdCardInterface_h
|
||||
#include "../common/FsBlockDeviceInterface.h"
|
||||
|
|
@ -39,9 +43,7 @@ class SdCardInterface : public FsBlockDeviceInterface {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
virtual bool cardCMD6(uint32_t arg, uint8_t* status) = 0;
|
||||
/** end use of card */
|
||||
virtual void end() = 0;
|
||||
/** Erase a range of sectors.
|
||||
/** Erase a range of sectors.
|
||||
*
|
||||
* \param[in] firstSector The address of the first sector in the range.
|
||||
* \param[in] lastSector The address of the last sector in the range.
|
||||
|
|
@ -53,12 +55,10 @@ class SdCardInterface : public FsBlockDeviceInterface {
|
|||
virtual uint8_t errorCode() const = 0;
|
||||
/** \return error data. */
|
||||
virtual uint32_t errorData() const = 0;
|
||||
/** \return true if card is busy. */
|
||||
virtual bool isBusy() = 0;
|
||||
/** \return false by default */
|
||||
virtual bool hasDedicatedSpi() {return false;}
|
||||
virtual bool hasDedicatedSpi() { return false; }
|
||||
/** \return false by default */
|
||||
bool virtual isDedicatedSpi() {return false;}
|
||||
bool virtual isDedicatedSpi() { return false; }
|
||||
/** Set SPI sharing state
|
||||
* \param[in] value desired state.
|
||||
* \return false by default.
|
||||
|
|
@ -75,7 +75,7 @@ class SdCardInterface : public FsBlockDeviceInterface {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
virtual bool readCID(cid_t* cid) = 0;
|
||||
/**
|
||||
/**
|
||||
* Read a card's CSD register.
|
||||
*
|
||||
* \param[out] csd pointer to area for returned data.
|
||||
|
|
@ -94,16 +94,14 @@ class SdCardInterface : public FsBlockDeviceInterface {
|
|||
* \param[out] scr Value of SCR register.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
virtual bool readSCR(scr_t *scr) = 0;
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
* \return The number of 512 byte data sectors in the card
|
||||
* or zero if an error occurs.
|
||||
virtual bool readSCR(scr_t* scr) = 0;
|
||||
/** Return the 64 byte SD Status register.
|
||||
* \param[out] sds location for 64 status bytes.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
virtual uint32_t sectorCount() = 0;
|
||||
virtual bool readSDS(sds_t* sds) = 0;
|
||||
/** \return card status. */
|
||||
virtual uint32_t status() {return 0XFFFFFFFF;}
|
||||
virtual uint32_t status() { return 0XFFFFFFFF; }
|
||||
/** Return the card type: SD V1, SD V2 or SDHC/SDXC
|
||||
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -27,14 +27,11 @@
|
|||
class Timeout {
|
||||
public:
|
||||
Timeout() {}
|
||||
explicit Timeout(uint16_t ms) {set(ms);}
|
||||
uint16_t millis16() {return millis();}
|
||||
void set(uint16_t ms) {
|
||||
m_endTime = ms + millis16();
|
||||
}
|
||||
bool timedOut() {
|
||||
return (int16_t)(m_endTime - millis16()) < 0;
|
||||
}
|
||||
explicit Timeout(uint16_t ms) { set(ms); }
|
||||
uint16_t millis16() { return millis(); }
|
||||
void set(uint16_t ms) { m_endTime = ms + millis16(); }
|
||||
bool timedOut() { return (int16_t)(m_endTime - millis16()) < 0; }
|
||||
|
||||
private:
|
||||
uint16_t m_endTime;
|
||||
};
|
||||
|
|
@ -77,48 +74,44 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
|||
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||
#ifdef __AVR__
|
||||
static const uint16_t crctab[] PROGMEM = {
|
||||
#else // __AVR__
|
||||
#else // __AVR__
|
||||
static const uint16_t crctab[] = {
|
||||
#endif // __AVR__
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
|
||||
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
|
||||
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
|
||||
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
|
||||
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
|
||||
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
|
||||
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
|
||||
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
|
||||
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
|
||||
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
|
||||
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
|
||||
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
|
||||
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
|
||||
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
|
||||
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
|
||||
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
|
||||
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
|
||||
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
|
||||
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
|
||||
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
|
||||
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
|
||||
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
|
||||
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
||||
uint16_t crc = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
#ifdef __AVR__
|
||||
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
|
||||
#else // __AVR__
|
||||
#else // __AVR__
|
||||
crc = crctab[(crc >> 8 ^ data[i]) & 0XFF] ^ (crc << 8);
|
||||
#endif // __AVR__
|
||||
}
|
||||
|
|
@ -131,10 +124,9 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
|||
//------------------------------------------------------------------------------
|
||||
bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
|
||||
Timeout timeout;
|
||||
m_spiActive = false;
|
||||
m_beginCalled = false;
|
||||
// Restore state to creator.
|
||||
initSharedSpiCard();
|
||||
m_errorCode = SD_CARD_ERROR_NONE;
|
||||
m_type = 0;
|
||||
m_csPin = spiConfig.csPin;
|
||||
#if SPI_DRIVER_SELECT >= 2
|
||||
m_spiDriverPtr = spiConfig.spiPort;
|
||||
|
|
@ -145,32 +137,28 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
|
|||
#endif // SPI_DRIVER_SELECT
|
||||
sdCsInit(m_csPin);
|
||||
spiUnselect();
|
||||
spiSetSckSpeed(1000UL*SD_MAX_INIT_RATE_KHZ);
|
||||
spiSetSckSpeed(1000UL * SD_MAX_INIT_RATE_KHZ);
|
||||
spiBegin(spiConfig);
|
||||
m_beginCalled = true;
|
||||
uint32_t arg;
|
||||
m_state = IDLE_STATE;
|
||||
spiStart();
|
||||
|
||||
// must supply min of 74 clock cycles with CS high.
|
||||
spiUnselect();
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
spiSend(0XFF);
|
||||
spiReceive();
|
||||
}
|
||||
spiSelect();
|
||||
// command to go idle in SPI mode
|
||||
for (uint8_t i = 1;; i++) {
|
||||
timeout.set(SD_INIT_TIMEOUT);
|
||||
while (true) {
|
||||
// command to go idle in SPI mode
|
||||
if (cardCommand(CMD0, 0) == R1_IDLE_STATE) {
|
||||
break;
|
||||
}
|
||||
if (i == SD_CMD0_RETRY) {
|
||||
if (timeout.timedOut()) {
|
||||
error(SD_CARD_ERROR_CMD0);
|
||||
goto fail;
|
||||
}
|
||||
// Force any active transfer to end for an already initialized card.
|
||||
for (uint8_t j = 0; j < 0XFF; j++) {
|
||||
spiSend(0XFF);
|
||||
}
|
||||
}
|
||||
#if USE_SD_CRC
|
||||
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
|
||||
|
|
@ -179,21 +167,26 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
|
|||
}
|
||||
#endif // USE_SD_CRC
|
||||
// check SD version
|
||||
if (!(cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
|
||||
type(SD_CARD_TYPE_SD2);
|
||||
while (true) {
|
||||
if (cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND) {
|
||||
type(SD_CARD_TYPE_SD1);
|
||||
break;
|
||||
}
|
||||
// Skip first three bytes.
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
m_status = spiReceive();
|
||||
}
|
||||
if (m_status != 0XAA) {
|
||||
if (m_status == 0XAA) {
|
||||
type(SD_CARD_TYPE_SD2);
|
||||
break;
|
||||
}
|
||||
if (timeout.timedOut()) {
|
||||
error(SD_CARD_ERROR_CMD8);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
type(SD_CARD_TYPE_SD1);
|
||||
}
|
||||
// initialize card and send host supports SDHC if SD2
|
||||
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
|
||||
timeout.set(SD_INIT_TIMEOUT);
|
||||
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
|
||||
// check for timeout
|
||||
if (timeout.timedOut()) {
|
||||
|
|
@ -201,7 +194,6 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// if SD2 read OCR register to check for SDHC card
|
||||
if (type() == SD_CARD_TYPE_SD2) {
|
||||
if (cardCommand(CMD58, 0)) {
|
||||
|
|
@ -220,7 +212,7 @@ bool SharedSpiCard::begin(SdSpiConfig spiConfig) {
|
|||
spiSetSckSpeed(spiConfig.maxSck);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -236,7 +228,7 @@ bool SharedSpiCard::cardCMD6(uint32_t arg, uint8_t* status) {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -267,7 +259,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
|
|||
|
||||
// send message
|
||||
spiSend(buf, 6);
|
||||
#else // USE_SD_CRC
|
||||
#else // USE_SD_CRC
|
||||
// send command
|
||||
spiSend(cmd | 0x40);
|
||||
|
||||
|
|
@ -285,7 +277,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
|
|||
spiReceive();
|
||||
|
||||
// there are 1-8 fill bytes before response. fill bytes should be 0XFF.
|
||||
uint16_t n = 0;
|
||||
uint8_t n = 0;
|
||||
do {
|
||||
m_status = spiReceive();
|
||||
} while (m_status & 0X80 && ++n < 10);
|
||||
|
|
@ -294,7 +286,7 @@ uint8_t SharedSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
|
|||
//------------------------------------------------------------------------------
|
||||
void SharedSpiCard::end() {
|
||||
if (m_beginCalled) {
|
||||
spiStop();
|
||||
syncDevice();
|
||||
spiEnd();
|
||||
m_beginCalled = false;
|
||||
}
|
||||
|
|
@ -319,9 +311,8 @@ bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
|
|||
firstSector <<= 9;
|
||||
lastSector <<= 9;
|
||||
}
|
||||
if (cardCommand(CMD32, firstSector)
|
||||
|| cardCommand(CMD33, lastSector)
|
||||
|| cardCommand(CMD38, 0)) {
|
||||
if (cardCommand(CMD32, firstSector) || cardCommand(CMD33, lastSector) ||
|
||||
cardCommand(CMD38, 0)) {
|
||||
error(SD_CARD_ERROR_ERASE);
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -332,7 +323,7 @@ bool SharedSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -357,9 +348,7 @@ bool SharedSpiCard::isBusy() {
|
|||
return rtn;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SharedSpiCard::readData(uint8_t* dst) {
|
||||
return readData(dst, 512);
|
||||
}
|
||||
bool SharedSpiCard::readData(uint8_t* dst) { return readData(dst, 512); }
|
||||
//------------------------------------------------------------------------------
|
||||
bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
|
||||
#if USE_SD_CRC
|
||||
|
|
@ -391,14 +380,14 @@ bool SharedSpiCard::readData(uint8_t* dst, size_t count) {
|
|||
error(SD_CARD_ERROR_READ_CRC);
|
||||
goto fail;
|
||||
}
|
||||
#else // USE_SD_CRC
|
||||
#else // USE_SD_CRC
|
||||
// discard crc
|
||||
spiReceive();
|
||||
spiReceive();
|
||||
#endif // USE_SD_CRC
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -412,14 +401,14 @@ bool SharedSpiCard::readOCR(uint32_t* ocr) {
|
|||
for (uint8_t i = 0; i < 4; i++) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
p[3 - i] = spiReceive();
|
||||
#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
p[i] = spiReceive();
|
||||
#endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
}
|
||||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -437,7 +426,7 @@ bool SharedSpiCard::readRegister(uint8_t cmd, void* buf) {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -454,7 +443,7 @@ bool SharedSpiCard::readSCR(scr_t* scr) {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -474,7 +463,7 @@ bool SharedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -489,7 +478,7 @@ bool SharedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
|
|||
}
|
||||
}
|
||||
return readStop();
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -504,25 +493,25 @@ bool SharedSpiCard::readStart(uint32_t sector) {
|
|||
m_state = READ_STATE;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SharedSpiCard::readStatus(SdStatus* status) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(status);
|
||||
bool SharedSpiCard::readSDS(sds_t* sds) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(sds);
|
||||
// retrun is R2 so read extra status byte.
|
||||
if (cardAcmd(ACMD13, 0) || spiReceive()) {
|
||||
error(SD_CARD_ERROR_ACMD13);
|
||||
goto fail;
|
||||
}
|
||||
if (!readData(dst, 64)) {
|
||||
if (!readData(dst, sizeof(sds_t))) {
|
||||
goto fail;
|
||||
}
|
||||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -536,7 +525,7 @@ bool SharedSpiCard::readStop() {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -547,6 +536,7 @@ uint32_t SharedSpiCard::sectorCount() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SharedSpiCard::spiStart() {
|
||||
SPI_ASSERT_NOT_ACTIVE;
|
||||
if (!m_spiActive) {
|
||||
spiActivate();
|
||||
m_spiActive = true;
|
||||
|
|
@ -557,6 +547,7 @@ void SharedSpiCard::spiStart() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SharedSpiCard::spiStop() {
|
||||
SPI_ASSERT_ACTIVE;
|
||||
if (m_spiActive) {
|
||||
spiUnselect();
|
||||
// Insure MISO goes to low Z.
|
||||
|
|
@ -597,7 +588,7 @@ bool SharedSpiCard::writeData(const uint8_t* src) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -606,7 +597,7 @@ bool SharedSpiCard::writeData(const uint8_t* src) {
|
|||
bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) {
|
||||
#if USE_SD_CRC
|
||||
uint16_t crc = CRC_CCITT(src, 512);
|
||||
#else // USE_SD_CRC
|
||||
#else // USE_SD_CRC
|
||||
uint16_t crc = 0XFFFF;
|
||||
#endif // USE_SD_CRC
|
||||
spiSend(token);
|
||||
|
|
@ -621,7 +612,7 @@ bool SharedSpiCard::writeData(uint8_t token, const uint8_t* src) {
|
|||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -655,13 +646,13 @@ bool SharedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
|
|||
spiStop();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SharedSpiCard::writeSectors(uint32_t sector,
|
||||
const uint8_t* src, size_t ns) {
|
||||
bool SharedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
|
||||
size_t ns) {
|
||||
if (!writeStart(sector)) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -672,7 +663,7 @@ bool SharedSpiCard::writeSectors(uint32_t sector,
|
|||
}
|
||||
return writeStop();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -689,7 +680,7 @@ bool SharedSpiCard::writeStart(uint32_t sector) {
|
|||
m_state = WRITE_STATE;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -703,7 +694,7 @@ bool SharedSpiCard::writeStop() {
|
|||
m_state = IDLE_STATE;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
error(SD_CARD_ERROR_STOP_TRAN);
|
||||
spiStop();
|
||||
return false;
|
||||
|
|
@ -721,8 +712,7 @@ bool DedicatedSpiCard::readSector(uint32_t sector, uint8_t* dst) {
|
|||
return readSectors(sector, dst, 1);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool DedicatedSpiCard::readSectors(
|
||||
uint32_t sector, uint8_t* dst, size_t ns) {
|
||||
bool DedicatedSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
|
||||
if (sdState() != READ_STATE || sector != m_curSector) {
|
||||
if (!readStart(sector)) {
|
||||
goto fail;
|
||||
|
|
@ -737,7 +727,7 @@ bool DedicatedSpiCard::readSectors(
|
|||
m_curSector += ns;
|
||||
return m_dedicatedSpi ? true : readStop();
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -756,8 +746,8 @@ bool DedicatedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
|
|||
return SharedSpiCard::writeSector(sector, src);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool DedicatedSpiCard::writeSectors(
|
||||
uint32_t sector, const uint8_t* src, size_t ns) {
|
||||
bool DedicatedSpiCard::writeSectors(uint32_t sector, const uint8_t* src,
|
||||
size_t ns) {
|
||||
if (sdState() != WRITE_STATE || m_curSector != sector) {
|
||||
if (!writeStart(sector)) {
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -24,25 +24,43 @@
|
|||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief SdSpiCard class for V2 SD/SDHC cards
|
||||
* \brief Classes for SPI access to SD/SDHC cards.
|
||||
*/
|
||||
#ifndef SdSpiCard_h
|
||||
#define SdSpiCard_h
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../SpiDriver/SdSpiDriver.h"
|
||||
#include "../common/SysCall.h"
|
||||
#include "SdCardInfo.h"
|
||||
#include "SdCardInterface.h"
|
||||
#include "../SpiDriver/SdSpiDriver.h"
|
||||
/** Verify correct SPI active if non-zero. */
|
||||
#define CHECK_SPI_ACTIVE 0
|
||||
#if CHECK_SPI_ACTIVE
|
||||
/** Check SPI active. */
|
||||
#define SPI_ASSERT_ACTIVE {if (!m_spiActive) {\
|
||||
Serial.print(F("SPI_ASSERTACTIVE"));\
|
||||
Serial.println(__LINE__);}}
|
||||
#define SPI_ASSERT_ACTIVE \
|
||||
{ \
|
||||
if (!m_spiActive) { \
|
||||
Serial.print(F("SPI_ASSERT_ACTIVE")); \
|
||||
Serial.println(__LINE__); \
|
||||
while (true) \
|
||||
; \
|
||||
} \
|
||||
}
|
||||
#define SPI_ASSERT_NOT_ACTIVE \
|
||||
{ \
|
||||
if (m_spiActive) { \
|
||||
Serial.print(F("SPI_ASSERT_NOT_ACTIVE")); \
|
||||
Serial.println(__LINE__); \
|
||||
while (true) \
|
||||
; \
|
||||
} \
|
||||
}
|
||||
#else // CHECK_SPI_ACTIVE
|
||||
/** Do not check SPI active. */
|
||||
/** Check for SPI active. */
|
||||
#define SPI_ASSERT_ACTIVE
|
||||
/** Check for SPI not active. */
|
||||
#define SPI_ASSERT_NOT_ACTIVE
|
||||
#endif // CHECK_SPI_ACTIVE
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -53,7 +71,7 @@
|
|||
class SharedSpiCard : public SdCardInterface {
|
||||
#elif USE_BLOCK_DEVICE_INTERFACE
|
||||
class SharedSpiCard : public FsBlockDeviceInterface {
|
||||
#else // HAS_SDIO_CLASS
|
||||
#else // HAS_SDIO_CLASS
|
||||
class SharedSpiCard {
|
||||
#endif // HAS_SDIO_CLASS
|
||||
public:
|
||||
|
|
@ -64,7 +82,7 @@ class SharedSpiCard {
|
|||
/** SD is in multi-sector write state. */
|
||||
static const uint8_t WRITE_STATE = 2;
|
||||
/** Construct an instance of SharedSpiCard. */
|
||||
SharedSpiCard() {}
|
||||
SharedSpiCard() { initSharedSpiCard(); }
|
||||
/** Initialize the SD card.
|
||||
* \param[in] spiConfig SPI card configuration.
|
||||
* \return true for success or false for failure.
|
||||
|
|
@ -103,21 +121,18 @@ class SharedSpiCard {
|
|||
* \param[in] code value for error code.
|
||||
*/
|
||||
void error(uint8_t code) {
|
||||
// (void)code;
|
||||
// (void)code;
|
||||
m_errorCode = code;
|
||||
}
|
||||
/**
|
||||
* \return code for the last error. See SdCardInfo.h for a list of error codes.
|
||||
* \return code for the last error. See SdCardInfo.h for a list of error
|
||||
* codes.
|
||||
*/
|
||||
uint8_t errorCode() const {
|
||||
return m_errorCode;
|
||||
}
|
||||
uint8_t errorCode() const { return m_errorCode; }
|
||||
/** \return error data for last error. */
|
||||
uint32_t errorData() const {
|
||||
return m_status;
|
||||
}
|
||||
uint32_t errorData() const { return m_status; }
|
||||
/** \return false for shared class. */
|
||||
bool hasDedicatedSpi() {return false;}
|
||||
bool hasDedicatedSpi() { return false; }
|
||||
/**
|
||||
* Check for busy. MISO low indicates the card is busy.
|
||||
*
|
||||
|
|
@ -125,7 +140,7 @@ class SharedSpiCard {
|
|||
*/
|
||||
bool isBusy();
|
||||
/** \return false, can't be in dedicated state. */
|
||||
bool isDedicatedSpi() {return false;}
|
||||
bool isDedicatedSpi() { return false; }
|
||||
/**
|
||||
* Read a card's CID register. The CID contains card identification
|
||||
* information such as Manufacturer ID, Product name, Product serial
|
||||
|
|
@ -135,9 +150,7 @@ class SharedSpiCard {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readCID(cid_t* cid) {
|
||||
return readRegister(CMD10, cid);
|
||||
}
|
||||
bool readCID(cid_t* cid) { return readRegister(CMD10, cid); }
|
||||
/**
|
||||
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||
* provides information regarding access to the card's contents.
|
||||
|
|
@ -146,9 +159,7 @@ class SharedSpiCard {
|
|||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readCSD(csd_t* csd) {
|
||||
return readRegister(CMD9, csd);
|
||||
}
|
||||
bool readCSD(csd_t* csd) { return readRegister(CMD9, csd); }
|
||||
/** Read one data sector in a multiple sector read sequence
|
||||
*
|
||||
* \param[out] dst Pointer to the location for the data to be read.
|
||||
|
|
@ -196,18 +207,18 @@ class SharedSpiCard {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readStart(uint32_t sector);
|
||||
/** Return the 64 byte card status
|
||||
/** Return the 64 byte SD Status register.
|
||||
* \param[out] status location for 64 status bytes.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readStatus(SdStatus* status);
|
||||
bool readSDS(sds_t* status);
|
||||
/** End a read multiple sectors sequence.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readStop();
|
||||
/** \return SD multi-sector read/write state */
|
||||
uint8_t sdState() {return m_state;}
|
||||
uint8_t sdState() { return m_state; }
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
|
|
@ -237,9 +248,7 @@ class SharedSpiCard {
|
|||
/** Return the card type: SD V1, SD V2 or SDHC/SDXC
|
||||
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC.
|
||||
*/
|
||||
uint8_t type() const {
|
||||
return m_type;
|
||||
}
|
||||
uint8_t type() const { return m_type; }
|
||||
/**
|
||||
* Write a 512 byte sector to an SD card.
|
||||
*
|
||||
|
|
@ -288,32 +297,18 @@ class SharedSpiCard {
|
|||
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||
bool readData(uint8_t* dst, size_t count);
|
||||
bool readRegister(uint8_t cmd, void* buf);
|
||||
void spiSelect() {
|
||||
sdCsWrite(m_csPin, false);
|
||||
}
|
||||
void spiSelect() { sdCsWrite(m_csPin, false); }
|
||||
void spiStart();
|
||||
void spiStop();
|
||||
void spiUnselect() {
|
||||
sdCsWrite(m_csPin, true);
|
||||
}
|
||||
void type(uint8_t value) {
|
||||
m_type = value;
|
||||
}
|
||||
void spiUnselect() { sdCsWrite(m_csPin, true); }
|
||||
void type(uint8_t value) { m_type = value; }
|
||||
bool waitReady(uint16_t ms);
|
||||
bool writeData(uint8_t token, const uint8_t* src);
|
||||
#if SPI_DRIVER_SELECT < 2
|
||||
void spiActivate() {
|
||||
m_spiDriver.activate();
|
||||
}
|
||||
void spiBegin(SdSpiConfig spiConfig) {
|
||||
m_spiDriver.begin(spiConfig);
|
||||
}
|
||||
void spiDeactivate() {
|
||||
m_spiDriver.deactivate();
|
||||
}
|
||||
void spiEnd() {
|
||||
m_spiDriver.end();
|
||||
}
|
||||
void spiActivate() { m_spiDriver.activate(); }
|
||||
void spiBegin(SdSpiConfig spiConfig) { m_spiDriver.begin(spiConfig); }
|
||||
void spiDeactivate() { m_spiDriver.deactivate(); }
|
||||
void spiEnd() { m_spiDriver.end(); }
|
||||
uint8_t spiReceive() {
|
||||
SPI_ASSERT_ACTIVE;
|
||||
return m_spiDriver.receive();
|
||||
|
|
@ -330,23 +325,13 @@ class SharedSpiCard {
|
|||
SPI_ASSERT_ACTIVE;
|
||||
m_spiDriver.send(buf, n);
|
||||
}
|
||||
void spiSetSckSpeed(uint32_t maxSck) {
|
||||
m_spiDriver.setSckSpeed(maxSck);
|
||||
}
|
||||
void spiSetSckSpeed(uint32_t maxSck) { m_spiDriver.setSckSpeed(maxSck); }
|
||||
SdSpiDriver m_spiDriver;
|
||||
#else // SPI_DRIVER_SELECT < 2
|
||||
void spiActivate() {
|
||||
m_spiDriverPtr->activate();
|
||||
}
|
||||
void spiBegin(SdSpiConfig spiConfig) {
|
||||
m_spiDriverPtr->begin(spiConfig);
|
||||
}
|
||||
void spiDeactivate() {
|
||||
m_spiDriverPtr->deactivate();
|
||||
}
|
||||
void spiEnd() {
|
||||
m_spiDriverPtr->end();
|
||||
}
|
||||
void spiActivate() { m_spiDriverPtr->activate(); }
|
||||
void spiBegin(SdSpiConfig spiConfig) { m_spiDriverPtr->begin(spiConfig); }
|
||||
void spiDeactivate() { m_spiDriverPtr->deactivate(); }
|
||||
void spiEnd() { m_spiDriverPtr->end(); }
|
||||
uint8_t spiReceive() {
|
||||
SPI_ASSERT_ACTIVE;
|
||||
return m_spiDriverPtr->receive();
|
||||
|
|
@ -363,21 +348,27 @@ class SharedSpiCard {
|
|||
SPI_ASSERT_ACTIVE;
|
||||
m_spiDriverPtr->send(buf, n);
|
||||
}
|
||||
void spiSetSckSpeed(uint32_t maxSck) {
|
||||
m_spiDriverPtr->setSckSpeed(maxSck);
|
||||
}
|
||||
void spiSetSckSpeed(uint32_t maxSck) { m_spiDriverPtr->setSckSpeed(maxSck); }
|
||||
SdSpiDriver* m_spiDriverPtr;
|
||||
|
||||
#endif // SPI_DRIVER_SELECT < 2
|
||||
bool m_beginCalled = false;
|
||||
void initSharedSpiCard() {
|
||||
m_beginCalled = false;
|
||||
m_csPin = 0;
|
||||
m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
|
||||
m_spiActive = false;
|
||||
m_state = IDLE_STATE;
|
||||
m_status = 0;
|
||||
m_type = 0;
|
||||
}
|
||||
bool m_beginCalled;
|
||||
SdCsPin_t m_csPin;
|
||||
uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
|
||||
bool m_spiActive;
|
||||
uint8_t m_errorCode;
|
||||
bool m_spiActive;
|
||||
uint8_t m_state;
|
||||
uint8_t m_status;
|
||||
uint8_t m_type = 0;
|
||||
uint8_t m_type;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class DedicatedSpiCard
|
||||
|
|
@ -386,16 +377,16 @@ class SharedSpiCard {
|
|||
class DedicatedSpiCard : public SharedSpiCard {
|
||||
public:
|
||||
/** Construct an instance of DedicatedSpiCard. */
|
||||
DedicatedSpiCard() {}
|
||||
DedicatedSpiCard() = default;
|
||||
/** Initialize the SD card.
|
||||
* \param[in] spiConfig SPI card configuration.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool begin(SdSpiConfig spiConfig);
|
||||
/** \return true, can be in dedicaded state. */
|
||||
bool hasDedicatedSpi() {return true;}
|
||||
bool hasDedicatedSpi() { return true; }
|
||||
/** \return true if in dedicated SPI state. */
|
||||
bool isDedicatedSpi() {return m_dedicatedSpi;}
|
||||
bool isDedicatedSpi() { return m_dedicatedSpi; }
|
||||
/**
|
||||
* Read a 512 byte sector from an SD card.
|
||||
*
|
||||
|
|
@ -437,7 +428,7 @@ class DedicatedSpiCard : public SharedSpiCard {
|
|||
bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns);
|
||||
|
||||
private:
|
||||
uint32_t m_curSector;
|
||||
uint32_t m_curSector = 0;
|
||||
bool m_dedicatedSpi = false;
|
||||
};
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -22,12 +22,17 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* \brief Classes for SDIO cards.
|
||||
*/
|
||||
#ifndef SdioCard_h
|
||||
#define SdioCard_h
|
||||
#include "../common/SysCall.h"
|
||||
#include "SdCardInterface.h"
|
||||
|
||||
/** Use programmed I/O with FIFO. */
|
||||
#define FIFO_SDIO 0
|
||||
/** Use programmed I/O with DMA. */
|
||||
#define DMA_SDIO 1
|
||||
/**
|
||||
* \class SdioConfig
|
||||
|
|
@ -42,9 +47,10 @@ class SdioConfig {
|
|||
*/
|
||||
explicit SdioConfig(uint8_t opt) : m_options(opt) {}
|
||||
/** \return SDIO card options. */
|
||||
uint8_t options() {return m_options;}
|
||||
uint8_t options() { return m_options; }
|
||||
/** \return true if DMA_SDIO. */
|
||||
bool useDma() {return m_options & DMA_SDIO;}
|
||||
bool useDma() { return m_options & DMA_SDIO; }
|
||||
|
||||
private:
|
||||
uint8_t m_options = FIFO_SDIO;
|
||||
};
|
||||
|
|
@ -73,7 +79,7 @@ class SdioCard : public SdCardInterface {
|
|||
void end() {}
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
|
||||
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/** Erase a range of sectors.
|
||||
*
|
||||
|
|
@ -89,7 +95,8 @@ class SdioCard : public SdCardInterface {
|
|||
*/
|
||||
bool erase(uint32_t firstSector, uint32_t lastSector);
|
||||
/**
|
||||
* \return code for the last error. See SdCardInfo.h for a list of error codes.
|
||||
* \return code for the last error. See SdCardInfo.h for a list of error
|
||||
* codes.
|
||||
*/
|
||||
uint8_t errorCode() const;
|
||||
/** \return error data for last error. */
|
||||
|
|
@ -158,7 +165,12 @@ class SdioCard : public SdCardInterface {
|
|||
* \param[out] scr Value of SCR register.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readSCR(scr_t *scr);
|
||||
bool readSCR(scr_t* scr);
|
||||
/** Return the 64 byte SD Status register.
|
||||
* \param[out] sds location for 64 status bytes.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool readSDS(sds_t* sds);
|
||||
/** Start a read multiple sectors sequence.
|
||||
*
|
||||
* \param[in] sector Address of first sector in sequence.
|
||||
|
|
@ -186,7 +198,7 @@ class SdioCard : public SdCardInterface {
|
|||
bool readStop();
|
||||
/** \return SDIO card status. */
|
||||
uint32_t status();
|
||||
/**
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
* \return The number of 512 byte data sectors in the card
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
|
||||
#include "SdioTeensy.h"
|
||||
|
||||
#include "SdCardInfo.h"
|
||||
#include "SdioCard.h"
|
||||
//==============================================================================
|
||||
|
|
@ -36,39 +37,34 @@ const uint32_t CMD8_RETRIES = 3;
|
|||
const uint32_t BUSY_TIMEOUT_MICROS = 1000000;
|
||||
//==============================================================================
|
||||
const uint32_t SDHC_IRQSTATEN_MASK =
|
||||
SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN |
|
||||
SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN |
|
||||
SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
|
||||
SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN |
|
||||
SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_DINTSEN |
|
||||
SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;
|
||||
SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN | SDHC_IRQSTATEN_DEBESEN |
|
||||
SDHC_IRQSTATEN_DCESEN | SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
|
||||
SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN | SDHC_IRQSTATEN_CTOESEN |
|
||||
SDHC_IRQSTATEN_DINTSEN | SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;
|
||||
|
||||
const uint32_t SDHC_IRQSTAT_CMD_ERROR =
|
||||
SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE |
|
||||
SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CTOE;
|
||||
SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE | SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CTOE;
|
||||
|
||||
const uint32_t SDHC_IRQSTAT_DATA_ERROR =
|
||||
SDHC_IRQSTAT_AC12E | SDHC_IRQSTAT_DEBE |
|
||||
SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE;
|
||||
const uint32_t SDHC_IRQSTAT_DATA_ERROR = SDHC_IRQSTAT_AC12E |
|
||||
SDHC_IRQSTAT_DEBE | SDHC_IRQSTAT_DCE |
|
||||
SDHC_IRQSTAT_DTOE;
|
||||
|
||||
const uint32_t SDHC_IRQSTAT_ERROR =
|
||||
SDHC_IRQSTAT_DMAE | SDHC_IRQSTAT_CMD_ERROR |
|
||||
SDHC_IRQSTAT_DATA_ERROR;
|
||||
SDHC_IRQSTAT_DMAE | SDHC_IRQSTAT_CMD_ERROR | SDHC_IRQSTAT_DATA_ERROR;
|
||||
|
||||
const uint32_t SDHC_IRQSIGEN_MASK =
|
||||
SDHC_IRQSIGEN_DMAEIEN | SDHC_IRQSIGEN_AC12EIEN |
|
||||
SDHC_IRQSIGEN_DEBEIEN | SDHC_IRQSIGEN_DCEIEN |
|
||||
SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
|
||||
SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN |
|
||||
SDHC_IRQSIGEN_CTOEIEN | SDHC_IRQSIGEN_TCIEN;
|
||||
SDHC_IRQSIGEN_DMAEIEN | SDHC_IRQSIGEN_AC12EIEN | SDHC_IRQSIGEN_DEBEIEN |
|
||||
SDHC_IRQSIGEN_DCEIEN | SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
|
||||
SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN | SDHC_IRQSIGEN_CTOEIEN |
|
||||
SDHC_IRQSIGEN_TCIEN;
|
||||
//==============================================================================
|
||||
const uint32_t CMD_RESP_NONE = SDHC_XFERTYP_RSPTYP(0);
|
||||
|
||||
const uint32_t CMD_RESP_R1 = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
|
||||
SDHC_XFERTYP_RSPTYP(2);
|
||||
const uint32_t CMD_RESP_R1 =
|
||||
SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(2);
|
||||
|
||||
const uint32_t CMD_RESP_R1b = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
|
||||
SDHC_XFERTYP_RSPTYP(3);
|
||||
const uint32_t CMD_RESP_R1b =
|
||||
SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(3);
|
||||
|
||||
const uint32_t CMD_RESP_R2 = SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(1);
|
||||
|
||||
|
|
@ -86,26 +82,23 @@ const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN;
|
|||
const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL |
|
||||
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
|
||||
|
||||
const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_XFERTYP_MSBSEL |
|
||||
SDHC_XFERTYP_BCEN;
|
||||
const uint32_t DATA_READ_MULTI_PGM =
|
||||
DATA_READ | SDHC_XFERTYP_MSBSEL | SDHC_XFERTYP_BCEN;
|
||||
|
||||
const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN;
|
||||
|
||||
const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL |
|
||||
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
|
||||
|
||||
const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_MSBSEL |
|
||||
SDHC_XFERTYP_BCEN;
|
||||
const uint32_t DATA_WRITE_MULTI_PGM =
|
||||
SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_MSBSEL | SDHC_XFERTYP_BCEN;
|
||||
|
||||
#elif defined(__IMXRT1062__)
|
||||
// Use low bits for SDHC_MIX_CTRL since bits 15-0 of SDHC_XFERTYP are reserved.
|
||||
const uint32_t SDHC_MIX_CTRL_MASK = SDHC_MIX_CTRL_DMAEN | SDHC_MIX_CTRL_BCEN |
|
||||
SDHC_MIX_CTRL_AC12EN |
|
||||
SDHC_MIX_CTRL_DDR_EN |
|
||||
SDHC_MIX_CTRL_DTDSEL |
|
||||
SDHC_MIX_CTRL_MSBSEL |
|
||||
SDHC_MIX_CTRL_NIBBLE_POS |
|
||||
SDHC_MIX_CTRL_AC23EN;
|
||||
const uint32_t SDHC_MIX_CTRL_MASK =
|
||||
SDHC_MIX_CTRL_DMAEN | SDHC_MIX_CTRL_BCEN | SDHC_MIX_CTRL_AC12EN |
|
||||
SDHC_MIX_CTRL_DDR_EN | SDHC_MIX_CTRL_DTDSEL | SDHC_MIX_CTRL_MSBSEL |
|
||||
SDHC_MIX_CTRL_NIBBLE_POS | SDHC_MIX_CTRL_AC23EN;
|
||||
|
||||
const uint32_t DATA_READ = SDHC_MIX_CTRL_DTDSEL | SDHC_XFERTYP_DPSEL;
|
||||
|
||||
|
|
@ -116,7 +109,6 @@ const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_MIX_CTRL_MSBSEL |
|
|||
|
||||
const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_MIX_CTRL_MSBSEL;
|
||||
|
||||
|
||||
const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_MIX_CTRL_DMAEN;
|
||||
|
||||
const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_MIX_CTRL_MSBSEL |
|
||||
|
|
@ -128,10 +120,13 @@ const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL | SDHC_MIX_CTRL_MSBSEL;
|
|||
|
||||
const uint32_t ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1;
|
||||
|
||||
const uint32_t ACMD13_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(ACMD13) | CMD_RESP_R1 | DATA_READ_DMA;
|
||||
|
||||
const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3;
|
||||
|
||||
const uint32_t ACMD51_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD51) | CMD_RESP_R1 |
|
||||
DATA_READ_DMA;
|
||||
const uint32_t ACMD51_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(ACMD51) | CMD_RESP_R1 | DATA_READ_DMA;
|
||||
|
||||
const uint32_t CMD0_XFERTYP = SDHC_XFERTYP_CMDINX(CMD0) | CMD_RESP_NONE;
|
||||
|
||||
|
|
@ -139,8 +134,8 @@ const uint32_t CMD2_XFERTYP = SDHC_XFERTYP_CMDINX(CMD2) | CMD_RESP_R2;
|
|||
|
||||
const uint32_t CMD3_XFERTYP = SDHC_XFERTYP_CMDINX(CMD3) | CMD_RESP_R6;
|
||||
|
||||
const uint32_t CMD6_XFERTYP = SDHC_XFERTYP_CMDINX(CMD6) | CMD_RESP_R1 |
|
||||
DATA_READ_DMA;
|
||||
const uint32_t CMD6_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD6) | CMD_RESP_R1 | DATA_READ_DMA;
|
||||
|
||||
const uint32_t CMD7_XFERTYP = SDHC_XFERTYP_CMDINX(CMD7) | CMD_RESP_R1b;
|
||||
|
||||
|
|
@ -152,28 +147,28 @@ const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2;
|
|||
|
||||
const uint32_t CMD11_XFERTYP = SDHC_XFERTYP_CMDINX(CMD11) | CMD_RESP_R1;
|
||||
|
||||
const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b |
|
||||
SDHC_XFERTYP_CMDTYP(3);
|
||||
const uint32_t CMD12_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b | SDHC_XFERTYP_CMDTYP(3);
|
||||
|
||||
const uint32_t CMD13_XFERTYP = SDHC_XFERTYP_CMDINX(CMD13) | CMD_RESP_R1;
|
||||
|
||||
const uint32_t CMD17_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 |
|
||||
DATA_READ_DMA;
|
||||
const uint32_t CMD17_DMA_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 | DATA_READ_DMA;
|
||||
|
||||
const uint32_t CMD18_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
|
||||
DATA_READ_MULTI_DMA;
|
||||
const uint32_t CMD18_DMA_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 | DATA_READ_MULTI_DMA;
|
||||
|
||||
const uint32_t CMD18_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
|
||||
DATA_READ_MULTI_PGM;
|
||||
const uint32_t CMD18_PGM_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 | DATA_READ_MULTI_PGM;
|
||||
|
||||
const uint32_t CMD24_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 |
|
||||
DATA_WRITE_DMA;
|
||||
const uint32_t CMD24_DMA_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 | DATA_WRITE_DMA;
|
||||
|
||||
const uint32_t CMD25_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
|
||||
DATA_WRITE_MULTI_DMA;
|
||||
const uint32_t CMD25_DMA_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | DATA_WRITE_MULTI_DMA;
|
||||
|
||||
const uint32_t CMD25_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
|
||||
DATA_WRITE_MULTI_PGM;
|
||||
const uint32_t CMD25_PGM_XFERTYP =
|
||||
SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 | DATA_WRITE_MULTI_PGM;
|
||||
|
||||
const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1;
|
||||
|
||||
|
|
@ -212,12 +207,20 @@ static uint32_t m_ocr;
|
|||
static cid_t m_cid;
|
||||
static csd_t m_csd;
|
||||
static scr_t m_scr;
|
||||
static sds_t m_sds;
|
||||
//==============================================================================
|
||||
#define DBG_TRACE Serial.print("TRACE."); Serial.println(__LINE__); delay(200);
|
||||
#define DBG_TRACE \
|
||||
Serial.print("TRACE."); \
|
||||
Serial.println(__LINE__); \
|
||||
delay(200);
|
||||
#define USE_DEBUG_MODE 0
|
||||
#if USE_DEBUG_MODE
|
||||
#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\
|
||||
Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);}
|
||||
#define DBG_IRQSTAT() \
|
||||
if (SDHC_IRQSTAT) { \
|
||||
Serial.print(__LINE__); \
|
||||
Serial.print(" IRQSTAT "); \
|
||||
Serial.println(SDHC_IRQSTAT, HEX); \
|
||||
}
|
||||
static void printRegs(uint32_t line) {
|
||||
uint32_t blkattr = SDHC_BLKATTR;
|
||||
uint32_t xfertyp = SDHC_XFERTYP;
|
||||
|
|
@ -234,36 +237,68 @@ static void printRegs(uint32_t line) {
|
|||
Serial.print(xfertyp >> 24);
|
||||
Serial.print(" TYP");
|
||||
Serial.print((xfertyp >> 2) & 3);
|
||||
if (xfertyp & SDHC_XFERTYP_DPSEL) {Serial.print(" DPSEL");}
|
||||
if (xfertyp & SDHC_XFERTYP_DPSEL) {
|
||||
Serial.print(" DPSEL");
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("PRSSTAT ");
|
||||
Serial.print(prsstat, HEX);
|
||||
if (prsstat & SDHC_PRSSTAT_BREN) {Serial.print(" BREN");}
|
||||
if (prsstat & SDHC_PRSSTAT_BWEN) {Serial.print(" BWEN");}
|
||||
if (prsstat & SDHC_PRSSTAT_RTA) {Serial.print(" RTA");}
|
||||
if (prsstat & SDHC_PRSSTAT_WTA) {Serial.print(" WTA");}
|
||||
if (prsstat & SDHC_PRSSTAT_SDOFF) {Serial.print(" SDOFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_PEROFF) {Serial.print(" PEROFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_HCKOFF) {Serial.print(" HCKOFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_IPGOFF) {Serial.print(" IPGOFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_SDSTB) {Serial.print(" SDSTB");}
|
||||
if (prsstat & SDHC_PRSSTAT_DLA) {Serial.print(" DLA");}
|
||||
if (prsstat & SDHC_PRSSTAT_CDIHB) {Serial.print(" CDIHB");}
|
||||
if (prsstat & SDHC_PRSSTAT_CIHB) {Serial.print(" CIHB");}
|
||||
if (prsstat & SDHC_PRSSTAT_BREN) {
|
||||
Serial.print(" BREN");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_BWEN) {
|
||||
Serial.print(" BWEN");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_RTA) {
|
||||
Serial.print(" RTA");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_WTA) {
|
||||
Serial.print(" WTA");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_SDOFF) {
|
||||
Serial.print(" SDOFF");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_PEROFF) {
|
||||
Serial.print(" PEROFF");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_HCKOFF) {
|
||||
Serial.print(" HCKOFF");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_IPGOFF) {
|
||||
Serial.print(" IPGOFF");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_SDSTB) {
|
||||
Serial.print(" SDSTB");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_DLA) {
|
||||
Serial.print(" DLA");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_CDIHB) {
|
||||
Serial.print(" CDIHB");
|
||||
}
|
||||
if (prsstat & SDHC_PRSSTAT_CIHB) {
|
||||
Serial.print(" CIHB");
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("PROCTL ");
|
||||
Serial.print(proctl, HEX);
|
||||
if (proctl & SDHC_PROCTL_SABGREQ) Serial.print(" SABGREQ");
|
||||
Serial.print(" EMODE");
|
||||
Serial.print((proctl >>4) & 3);
|
||||
Serial.print((proctl >> 4) & 3);
|
||||
Serial.print(" DWT");
|
||||
Serial.print((proctl >>1) & 3);
|
||||
Serial.print((proctl >> 1) & 3);
|
||||
Serial.println();
|
||||
Serial.print("IRQSTAT ");
|
||||
Serial.print(irqstat, HEX);
|
||||
if (irqstat & SDHC_IRQSTAT_BGE) {Serial.print(" BGE");}
|
||||
if (irqstat & SDHC_IRQSTAT_TC) {Serial.print(" TC");}
|
||||
if (irqstat & SDHC_IRQSTAT_CC) {Serial.print(" CC");}
|
||||
if (irqstat & SDHC_IRQSTAT_BGE) {
|
||||
Serial.print(" BGE");
|
||||
}
|
||||
if (irqstat & SDHC_IRQSTAT_TC) {
|
||||
Serial.print(" TC");
|
||||
}
|
||||
if (irqstat & SDHC_IRQSTAT_CC) {
|
||||
Serial.print(" CC");
|
||||
}
|
||||
Serial.print("\nm_irqstat ");
|
||||
Serial.println(m_irqstat, HEX);
|
||||
}
|
||||
|
|
@ -298,12 +333,12 @@ static void sdIrs() {
|
|||
//------------------------------------------------------------------------------
|
||||
static void enableGPIO(bool enable) {
|
||||
const uint32_t PORT_CLK = PORT_PCR_MUX(4) | PORT_PCR_DSE;
|
||||
const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PE | PORT_PCR_PS;
|
||||
const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PE | PORT_PCR_PS;
|
||||
const uint32_t PORT_PUP = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS;
|
||||
|
||||
PORTE_PCR0 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D1
|
||||
PORTE_PCR1 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D0
|
||||
PORTE_PCR2 = enable ? PORT_CLK : PORT_PUP; // SDHC_CLK
|
||||
PORTE_PCR2 = enable ? PORT_CLK : PORT_PUP; // SDHC_CLK
|
||||
PORTE_PCR3 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_CMD
|
||||
PORTE_PCR4 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D3
|
||||
PORTE_PCR5 = enable ? PORT_CMD_DATA : PORT_PUP; // SDHC_D2
|
||||
|
|
@ -317,7 +352,7 @@ static void initClock() {
|
|||
// Enable SDHC clock.
|
||||
SIM_SCGC3 |= SIM_SCGC3_SDHC;
|
||||
}
|
||||
static uint32_t baseClock() { return F_CPU;}
|
||||
static uint32_t baseClock() { return F_CPU; }
|
||||
|
||||
#elif defined(__IMXRT1062__)
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -335,13 +370,13 @@ static void enableGPIO(bool enable) {
|
|||
const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE |
|
||||
#if defined(ARDUINO_TEENSY41)
|
||||
IOMUXC_SW_PAD_CTL_PAD_DSE(7) |
|
||||
#else // defined(ARDUINO_TEENSY41)
|
||||
#else // defined(ARDUINO_TEENSY41)
|
||||
IOMUXC_SW_PAD_CTL_PAD_DSE(4) | ///// WHG
|
||||
#endif // defined(ARDUINO_TEENSY41)
|
||||
IOMUXC_SW_PAD_CTL_PAD_SPEED(2);
|
||||
|
||||
const uint32_t DATA_MASK = CLOCK_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE |
|
||||
IOMUXC_SW_PAD_CTL_PAD_PUS(1);
|
||||
const uint32_t DATA_MASK =
|
||||
CLOCK_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE | IOMUXC_SW_PAD_CTL_PAD_PUS(1);
|
||||
if (enable) {
|
||||
gpioMux(0);
|
||||
IOMUXC_SW_PAD_CTL_PAD_GPIO_SD_B0_04 = DATA_MASK; // DAT2
|
||||
|
|
@ -365,20 +400,20 @@ static void initClock() {
|
|||
/* Enable USDHC clock. */
|
||||
CCM_CCGR6 |= CCM_CCGR6_USDHC1(CCM_CCGR_ON);
|
||||
CCM_CSCDR1 &= ~(CCM_CSCDR1_USDHC1_CLK_PODF_MASK);
|
||||
CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0
|
||||
// CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); / &0x7 WHG
|
||||
CCM_CSCMR1 |= CCM_CSCMR1_USDHC1_CLK_SEL; // PLL2PFD0
|
||||
// CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((7)); / &0x7 WHG
|
||||
CCM_CSCDR1 |= CCM_CSCDR1_USDHC1_CLK_PODF((1));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static uint32_t baseClock() {
|
||||
uint32_t divider = ((CCM_CSCDR1 >> 11) & 0x7) + 1;
|
||||
return (528000000U * 3)/((CCM_ANALOG_PFD_528 & 0x3F)/6)/divider;
|
||||
return (528000000U * 3) / ((CCM_ANALOG_PFD_528 & 0x3F) / 6) / divider;
|
||||
}
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
//==============================================================================
|
||||
// Static functions.
|
||||
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
|
||||
return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
|
||||
return cardCommand(CMD55_XFERTYP, rca) && cardCommand(xfertyp, arg);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
|
||||
|
|
@ -402,8 +437,25 @@ static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
|
|||
m_irqstat = SDHC_IRQSTAT;
|
||||
SDHC_IRQSTAT = m_irqstat;
|
||||
|
||||
return (m_irqstat & SDHC_IRQSTAT_CC) &&
|
||||
!(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
|
||||
return (m_irqstat & SDHC_IRQSTAT_CC) && !(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool cardACMD13(sds_t* scr) {
|
||||
// ACMD13 returns 64 bytes.
|
||||
if (waitTimeout(isBusyCMD13)) {
|
||||
return sdError(SD_CARD_ERROR_CMD13);
|
||||
}
|
||||
enableDmaIrs();
|
||||
SDHC_DSADDR = (uint32_t)scr;
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
|
||||
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
|
||||
if (!cardAcmd(m_rca, ACMD13_XFERTYP, 0)) {
|
||||
return sdError(SD_CARD_ERROR_ACMD13);
|
||||
}
|
||||
if (!waitDmaStatus()) {
|
||||
return sdError(SD_CARD_ERROR_DMA);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool cardACMD51(scr_t* scr) {
|
||||
|
|
@ -412,7 +464,7 @@ static bool cardACMD51(scr_t* scr) {
|
|||
return sdError(SD_CARD_ERROR_CMD13);
|
||||
}
|
||||
enableDmaIrs();
|
||||
SDHC_DSADDR = (uint32_t)scr;
|
||||
SDHC_DSADDR = (uint32_t)scr;
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(8);
|
||||
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
|
||||
if (!cardAcmd(m_rca, ACMD51_XFERTYP, 0)) {
|
||||
|
|
@ -435,7 +487,7 @@ static void initSDHC() {
|
|||
// Disable GPIO clock.
|
||||
enableGPIO(false);
|
||||
|
||||
#if defined (__IMXRT1062__)
|
||||
#if defined(__IMXRT1062__)
|
||||
SDHC_MIX_CTRL |= 0x80000000;
|
||||
#endif // (__IMXRT1062__)
|
||||
|
||||
|
|
@ -454,7 +506,7 @@ static void initSDHC() {
|
|||
SDHC_IRQSTATEN = SDHC_IRQSTATEN_MASK;
|
||||
|
||||
attachInterruptVector(IRQ_SDHC, sdIrs);
|
||||
NVIC_SET_PRIORITY(IRQ_SDHC, 6*16);
|
||||
NVIC_SET_PRIORITY(IRQ_SDHC, 6 * 16);
|
||||
NVIC_ENABLE_IRQ(IRQ_SDHC);
|
||||
|
||||
// Send 80 clocks to card.
|
||||
|
|
@ -475,32 +527,22 @@ static bool isBusyCommandComplete() {
|
|||
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyCommandInhibit() {
|
||||
return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
|
||||
}
|
||||
static bool isBusyCommandInhibit() { return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB; }
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyDat() {
|
||||
return SDHC_PRSSTAT & (1 << 24) ? false : true;
|
||||
}
|
||||
static bool isBusyDat() { return SDHC_PRSSTAT & (1 << 24) ? false : true; }
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyDMA() {
|
||||
return m_dmaBusy;
|
||||
}
|
||||
static bool isBusyDMA() { return m_dmaBusy; }
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyFifoRead() {
|
||||
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN);
|
||||
}
|
||||
static bool isBusyFifoRead() { return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN); }
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyFifoWrite() {
|
||||
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN);
|
||||
}
|
||||
static bool isBusyFifoWrite() { return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN); }
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyTransferComplete() {
|
||||
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool rdWrSectors(uint32_t xfertyp,
|
||||
uint32_t sector, uint8_t* buf, size_t n) {
|
||||
static bool rdWrSectors(uint32_t xfertyp, uint32_t sector, uint8_t* buf,
|
||||
size_t n) {
|
||||
if ((3 & (uint32_t)buf) || n == 0) {
|
||||
return sdError(SD_CARD_ERROR_DMA);
|
||||
}
|
||||
|
|
@ -508,10 +550,10 @@ static bool rdWrSectors(uint32_t xfertyp,
|
|||
return sdError(SD_CARD_ERROR_CMD13);
|
||||
}
|
||||
enableDmaIrs();
|
||||
SDHC_DSADDR = (uint32_t)buf;
|
||||
SDHC_DSADDR = (uint32_t)buf;
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
|
||||
if (!cardCommand(xfertyp, m_highCapacity ? sector : 512*sector)) {
|
||||
if (!cardCommand(xfertyp, m_highCapacity ? sector : 512 * sector)) {
|
||||
return false;
|
||||
}
|
||||
return waitDmaStatus();
|
||||
|
|
@ -525,7 +567,7 @@ static bool readReg16(uint32_t xfertyp, void* data) {
|
|||
}
|
||||
uint32_t sr[] = {SDHC_CMDRSP0, SDHC_CMDRSP1, SDHC_CMDRSP2, SDHC_CMDRSP3};
|
||||
for (int i = 0; i < 15; i++) {
|
||||
d[14 - i] = sr[i/4] >> 8*(i%4);
|
||||
d[14 - i] = sr[i / 4] >> 8 * (i % 4);
|
||||
}
|
||||
d[15] = 0;
|
||||
return true;
|
||||
|
|
@ -536,16 +578,17 @@ static void setSdclk(uint32_t kHzMax) {
|
|||
const uint32_t SDCLKFS_LIMIT = 0X100;
|
||||
uint32_t dvs = 1;
|
||||
uint32_t sdclkfs = 1;
|
||||
uint32_t maxSdclk = 1000*kHzMax;
|
||||
uint32_t maxSdclk = 1000 * kHzMax;
|
||||
uint32_t base = baseClock();
|
||||
|
||||
while ((base/(sdclkfs*DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
|
||||
while ((base / (sdclkfs * DVS_LIMIT) > maxSdclk) &&
|
||||
(sdclkfs < SDCLKFS_LIMIT)) {
|
||||
sdclkfs <<= 1;
|
||||
}
|
||||
while ((base/(sdclkfs*dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
|
||||
while ((base / (sdclkfs * dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
|
||||
dvs++;
|
||||
}
|
||||
m_sdClkKhz = base/(1000*sdclkfs*dvs);
|
||||
m_sdClkKhz = base / (1000 * sdclkfs * dvs);
|
||||
sdclkfs >>= 1;
|
||||
dvs--;
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
|
|
@ -554,11 +597,12 @@ static void setSdclk(uint32_t kHzMax) {
|
|||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
|
||||
// Change dividers.
|
||||
uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK
|
||||
| SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK);
|
||||
uint32_t sysctl =
|
||||
SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK | SDHC_SYSCTL_DVS_MASK |
|
||||
SDHC_SYSCTL_SDCLKFS_MASK);
|
||||
|
||||
SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs)
|
||||
| SDHC_SYSCTL_SDCLKFS(sdclkfs);
|
||||
SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs) |
|
||||
SDHC_SYSCTL_SDCLKFS(sdclkfs);
|
||||
|
||||
// Wait until the SDHC clock is stable.
|
||||
while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) {
|
||||
|
|
@ -667,14 +711,15 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
|
|||
break;
|
||||
}
|
||||
SDHC_SYSCTL |= SDHC_SYSCTL_RSTA;
|
||||
while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {}
|
||||
while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {
|
||||
}
|
||||
}
|
||||
// Must support 3.2-3.4 Volts
|
||||
arg = m_version2 ? 0X40300000 : 0x00300000;
|
||||
int m = micros();
|
||||
do {
|
||||
if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
|
||||
((micros() - m) > BUSY_TIMEOUT_MICROS)) {
|
||||
((micros() - m) > BUSY_TIMEOUT_MICROS)) {
|
||||
return sdError(SD_CARD_ERROR_ACMD41);
|
||||
}
|
||||
} while ((SDHC_CMDRSP0 & 0x80000000) == 0);
|
||||
|
|
@ -713,11 +758,13 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
|
|||
if (!cardACMD51(&m_scr)) {
|
||||
return false;
|
||||
}
|
||||
if (!cardACMD13(&m_sds)) {
|
||||
return false;
|
||||
}
|
||||
// Determine if High Speed mode is supported and set frequency.
|
||||
// Check status[16] for error 0XF or status[16] for new mode 0X1.
|
||||
uint8_t status[64];
|
||||
if (m_scr.sdSpec() > 0 &&
|
||||
cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
|
||||
if (m_scr.sdSpec() > 0 && cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
|
||||
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
|
||||
kHzSdClk = 50000;
|
||||
} else {
|
||||
|
|
@ -741,7 +788,7 @@ bool SdioCard::cardCMD6(uint32_t arg, uint8_t* status) {
|
|||
return sdError(SD_CARD_ERROR_CMD13);
|
||||
}
|
||||
enableDmaIrs();
|
||||
SDHC_DSADDR = (uint32_t)status;
|
||||
SDHC_DSADDR = (uint32_t)status;
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
|
||||
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
|
||||
if (!cardCommand(CMD6_XFERTYP, arg)) {
|
||||
|
|
@ -774,7 +821,7 @@ bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
|
|||
return sdError(SD_CARD_ERROR_CMD32);
|
||||
}
|
||||
if (!cardCommand(CMD33_XFERTYP, lastSector)) {
|
||||
return sdError(SD_CARD_ERROR_CMD33);
|
||||
return sdError(SD_CARD_ERROR_CMD33);
|
||||
}
|
||||
if (!cardCommand(CMD38_XFERTYP, 0)) {
|
||||
return sdError(SD_CARD_ERROR_CMD38);
|
||||
|
|
@ -785,17 +832,11 @@ bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdioCard::errorCode() const {
|
||||
return m_errorCode;
|
||||
}
|
||||
uint8_t SdioCard::errorCode() const { return m_errorCode; }
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t SdioCard::errorData() const {
|
||||
return m_irqstat;
|
||||
}
|
||||
uint32_t SdioCard::errorData() const { return m_irqstat; }
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t SdioCard::errorLine() const {
|
||||
return m_errorLine;
|
||||
}
|
||||
uint32_t SdioCard::errorLine() const { return m_errorLine; }
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::isBusy() {
|
||||
if (m_sdioConfig.useDma()) {
|
||||
|
|
@ -812,7 +853,7 @@ bool SdioCard::isBusy() {
|
|||
m_transferActive = false;
|
||||
stopTransmission(false);
|
||||
return true;
|
||||
#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
return false;
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
}
|
||||
|
|
@ -821,17 +862,15 @@ bool SdioCard::isBusy() {
|
|||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t SdioCard::kHzSdClk() {
|
||||
return m_sdClkKhz;
|
||||
}
|
||||
uint32_t SdioCard::kHzSdClk() { return m_sdClkKhz; }
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::readCID(cid_t* cid) {
|
||||
memcpy(cid, &m_cid, 16);
|
||||
memcpy(cid, &m_cid, sizeof(cid_t));
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::readCSD(csd_t* csd) {
|
||||
memcpy(csd, &m_csd, 16);
|
||||
memcpy(csd, &m_csd, sizeof(csd_t));
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -849,7 +888,7 @@ bool SdioCard::readData(uint8_t* dst) {
|
|||
if (waitTimeout(isBusyFifoRead)) {
|
||||
return sdError(SD_CARD_ERROR_READ_FIFO);
|
||||
}
|
||||
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
|
||||
for (uint32_t iw = 0; iw < 512 / (4 * FIFO_WML); iw++) {
|
||||
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {
|
||||
}
|
||||
for (uint32_t i = 0; i < FIFO_WML; i++) {
|
||||
|
|
@ -871,7 +910,12 @@ bool SdioCard::readOCR(uint32_t* ocr) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::readSCR(scr_t* scr) {
|
||||
memcpy(scr, &m_scr, 8);
|
||||
memcpy(scr, &m_scr, sizeof(scr_t));
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::readSDS(sds_t* sds) {
|
||||
memcpy(sds, &m_sds, sizeof(sds_t));
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -931,7 +975,7 @@ bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n) {
|
|||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (!readSector(sector + i, dst + i*512UL)) {
|
||||
if (!readSector(sector + i, dst + i * 512UL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -949,28 +993,22 @@ bool SdioCard::readStart(uint32_t sector) {
|
|||
#if defined(__IMXRT1062__)
|
||||
// Infinite transfer.
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
|
||||
#else // defined(__IMXRT1062__)
|
||||
#else // defined(__IMXRT1062__)
|
||||
// Errata - can't do infinite transfer.
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(MAX_BLKCNT) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
#endif // defined(__IMXRT1062__)
|
||||
|
||||
if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
|
||||
if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512 * sector)) {
|
||||
return sdError(SD_CARD_ERROR_CMD18);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::readStop() {
|
||||
return transferStop();
|
||||
}
|
||||
bool SdioCard::readStop() { return transferStop(); }
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t SdioCard::sectorCount() {
|
||||
return m_csd.capacity();
|
||||
}
|
||||
uint32_t SdioCard::sectorCount() { return m_csd.capacity(); }
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t SdioCard::status() {
|
||||
return statusCMD13();
|
||||
}
|
||||
uint32_t SdioCard::status() { return statusCMD13(); }
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::stopTransmission(bool blocking) {
|
||||
m_curState = IDLE_STATE;
|
||||
|
|
@ -998,8 +1036,8 @@ bool SdioCard::syncDevice() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdioCard::type() const {
|
||||
return m_version2 ? m_highCapacity ?
|
||||
SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1;
|
||||
return m_version2 ? m_highCapacity ? SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2
|
||||
: SD_CARD_TYPE_SD1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::writeData(const uint8_t* src) {
|
||||
|
|
@ -1016,7 +1054,7 @@ bool SdioCard::writeData(const uint8_t* src) {
|
|||
if (waitTimeout(isBusyFifoWrite)) {
|
||||
return sdError(SD_CARD_ERROR_WRITE_FIFO);
|
||||
}
|
||||
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
|
||||
for (uint32_t iw = 0; iw < 512 / (4 * FIFO_WML); iw++) {
|
||||
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) {
|
||||
}
|
||||
for (uint32_t i = 0; i < FIFO_WML; i++) {
|
||||
|
|
@ -1057,7 +1095,7 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
|
|||
if (!syncDevice()) {
|
||||
return false;
|
||||
}
|
||||
if (!writeStart(sector )) {
|
||||
if (!writeStart(sector)) {
|
||||
return false;
|
||||
}
|
||||
m_curSector = sector;
|
||||
|
|
@ -1087,7 +1125,7 @@ bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t n) {
|
|||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (!writeSector(sector + i, src + i*512UL)) {
|
||||
if (!writeSector(sector + i, src + i * 512UL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1104,17 +1142,15 @@ bool SdioCard::writeStart(uint32_t sector) {
|
|||
#if defined(__IMXRT1062__)
|
||||
// Infinite transfer.
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
|
||||
#else // defined(__IMXRT1062__)
|
||||
#else // defined(__IMXRT1062__)
|
||||
// Errata - can't do infinite transfer.
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(MAX_BLKCNT) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
#endif // defined(__IMXRT1062__)
|
||||
if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
|
||||
if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512 * sector)) {
|
||||
return sdError(SD_CARD_ERROR_CMD25);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::writeStop() {
|
||||
return transferStop();
|
||||
}
|
||||
bool SdioCard::writeStop() { return transferStop(); }
|
||||
#endif // defined(__MK64FX512__) defined(__MK66FX1M0__) defined(__IMXRT1062__)
|
||||
|
|
|
|||
|
|
@ -1,277 +1,530 @@
|
|||
/**
|
||||
* \file
|
||||
* \brief Definitions for Teensy HDHC.
|
||||
*/
|
||||
|
||||
#ifndef SdioTeensy_h
|
||||
#define SdioTeensy_h
|
||||
|
||||
// From Paul's SD.h driver.
|
||||
|
||||
#if defined(__IMXRT1062__)
|
||||
#define MAKE_REG_MASK(m,s) (((uint32_t)(((uint32_t)(m) << s))))
|
||||
#define MAKE_REG_GET(x,m,s) (((uint32_t)(((uint32_t)(x)>>s) & m)))
|
||||
#define MAKE_REG_SET(x,m,s) (((uint32_t)(((uint32_t)(x) & m) << s)))
|
||||
#define MAKE_REG_MASK(m, s) (((uint32_t)(((uint32_t)(m) << s))))
|
||||
#define MAKE_REG_GET(x, m, s) (((uint32_t)(((uint32_t)(x) >> s) & m)))
|
||||
#define MAKE_REG_SET(x, m, s) (((uint32_t)(((uint32_t)(x)&m) << s)))
|
||||
|
||||
#define SDHC_BLKATTR_BLKSIZE_MASK MAKE_REG_MASK(0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask
|
||||
#define SDHC_BLKATTR_BLKSIZE(n) MAKE_REG_SET(n,0x1FFF,0) //uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size
|
||||
#define SDHC_BLKATTR_BLKCNT_MASK MAKE_REG_MASK(0x1FFF,16) //((uint32_t)0x1FFF<<16)
|
||||
#define SDHC_BLKATTR_BLKCNT(n) MAKE_REG_SET(n,0x1FFF,16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count For Current Transfer
|
||||
#define SDHC_BLKATTR_BLKSIZE_MASK \
|
||||
MAKE_REG_MASK( \
|
||||
0x1FFF, 0) // uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size Mask
|
||||
#define SDHC_BLKATTR_BLKSIZE(n) \
|
||||
MAKE_REG_SET(n, 0x1FFF, \
|
||||
0) // uint32_t)(((n) & 0x1FFF)<<0) // Transfer Block Size
|
||||
#define SDHC_BLKATTR_BLKCNT_MASK \
|
||||
MAKE_REG_MASK(0x1FFF, 16) //((uint32_t)0x1FFF<<16)
|
||||
#define SDHC_BLKATTR_BLKCNT(n) \
|
||||
MAKE_REG_SET(n, 0x1FFF, 16) //(uint32_t)(((n) & 0x1FFF)<<16) // Blocks Count
|
||||
// For Current Transfer
|
||||
|
||||
#define SDHC_XFERTYP_CMDINX(n) MAKE_REG_SET(n,0x3F,24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index
|
||||
#define SDHC_XFERTYP_CMDTYP(n) MAKE_REG_SET(n,0x3,22) //(uint32_t)(((n) & 0x3)<<22) // Command Type
|
||||
#define SDHC_XFERTYP_DPSEL MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data Present Select
|
||||
#define SDHC_XFERTYP_CICEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Command Index Check Enable
|
||||
#define SDHC_XFERTYP_CCCEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command CRC Check Enable
|
||||
#define SDHC_XFERTYP_RSPTYP(n) MAKE_REG_SET(n,0x3,16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select
|
||||
#define SDHC_XFERTYP_MSBSEL MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Multi/Single Block Select
|
||||
#define SDHC_XFERTYP_DTDSEL MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Data Transfer Direction Select
|
||||
#define SDHC_XFERTYP_AC12EN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 Enable
|
||||
#define SDHC_XFERTYP_BCEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Block Count Enable
|
||||
#define SDHC_XFERTYP_DMAEN MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000001) // DMA Enable
|
||||
#define SDHC_XFERTYP_CMDINX(n) \
|
||||
MAKE_REG_SET(n, 0x3F, 24) //(uint32_t)(((n) & 0x3F)<<24)// Command Index
|
||||
#define SDHC_XFERTYP_CMDTYP(n) \
|
||||
MAKE_REG_SET(n, 0x3, 22) //(uint32_t)(((n) & 0x3)<<22) // Command Type
|
||||
#define SDHC_XFERTYP_DPSEL \
|
||||
MAKE_REG_MASK(0x1, 21) //((uint32_t)0x00200000) // Data Present Select
|
||||
#define SDHC_XFERTYP_CICEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
20) //((uint32_t)0x00100000) // Command Index Check Enable
|
||||
#define SDHC_XFERTYP_CCCEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
19) //((uint32_t)0x00080000) // Command CRC Check Enable
|
||||
#define SDHC_XFERTYP_RSPTYP(n) \
|
||||
MAKE_REG_SET(n, 0x3, \
|
||||
16) //(uint32_t)(((n) & 0x3)<<16) // Response Type Select
|
||||
#define SDHC_XFERTYP_MSBSEL \
|
||||
MAKE_REG_MASK(0x1, 5) //((uint32_t)0x00000020) // Multi/Single Block Select
|
||||
#define SDHC_XFERTYP_DTDSEL \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 4) //((uint32_t)0x00000010) // Data Transfer Direction Select
|
||||
#define SDHC_XFERTYP_AC12EN \
|
||||
MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Auto CMD12 Enable
|
||||
#define SDHC_XFERTYP_BCEN \
|
||||
MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Block Count Enable
|
||||
#define SDHC_XFERTYP_DMAEN \
|
||||
MAKE_REG_MASK(0x3, 0) //((uint32_t)0x00000001) // DMA Enable
|
||||
|
||||
#define SDHC_PRSSTAT_DLSL_MASK MAKE_REG_MASK(0xFF,24) //((uint32_t)0xFF000000) // DAT Line Signal Level
|
||||
#define SDHC_PRSSTAT_CLSL MAKE_REG_MASK(0x1,23) //((uint32_t)0x00800000) // CMD Line Signal Level
|
||||
#define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1,19) //
|
||||
#define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1,18) //
|
||||
#define SDHC_PRSSTAT_CINS MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Card Inserted
|
||||
#define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1,15)
|
||||
#define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1,12)
|
||||
#define SDHC_PRSSTAT_BREN MAKE_REG_MASK(0x1,11) //((uint32_t)0x00000800) // Buffer Read Enable
|
||||
#define SDHC_PRSSTAT_BWEN MAKE_REG_MASK(0x1,10) //((uint32_t)0x00000400) // Buffer Write Enable
|
||||
#define SDHC_PRSSTAT_RTA MAKE_REG_MASK(0x1,9) //((uint32_t)0x00000200) // Read Transfer Active
|
||||
#define SDHC_PRSSTAT_WTA MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Write Transfer Active
|
||||
#define SDHC_PRSSTAT_SDOFF MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_PEROFF MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_HCKOFF MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // System Clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_IPGOFF MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_SDSTB MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // SD Clock Stable
|
||||
#define SDHC_PRSSTAT_DLA MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Data Line Active
|
||||
#define SDHC_PRSSTAT_CDIHB MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Command Inhibit (DAT)
|
||||
#define SDHC_PRSSTAT_CIHB MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Inhibit (CMD)
|
||||
#define SDHC_PRSSTAT_DLSL_MASK \
|
||||
MAKE_REG_MASK(0xFF, 24) //((uint32_t)0xFF000000) // DAT Line Signal Level
|
||||
#define SDHC_PRSSTAT_CLSL \
|
||||
MAKE_REG_MASK(0x1, 23) //((uint32_t)0x00800000) // CMD Line Signal Level
|
||||
#define SDHC_PRSSTAT_WPSPL MAKE_REG_MASK(0x1, 19) //
|
||||
#define SDHC_PRSSTAT_CDPL MAKE_REG_MASK(0x1, 18) //
|
||||
#define SDHC_PRSSTAT_CINS \
|
||||
MAKE_REG_MASK(0x1, 16) //((uint32_t)0x00010000) // Card Inserted
|
||||
#define SDHC_PRSSTAT_TSCD MAKE_REG_MASK(0x1, 15)
|
||||
#define SDHC_PRSSTAT_RTR MAKE_REG_MASK(0x1, 12)
|
||||
#define SDHC_PRSSTAT_BREN \
|
||||
MAKE_REG_MASK(0x1, 11) //((uint32_t)0x00000800) // Buffer Read Enable
|
||||
#define SDHC_PRSSTAT_BWEN \
|
||||
MAKE_REG_MASK(0x1, 10) //((uint32_t)0x00000400) // Buffer Write Enable
|
||||
#define SDHC_PRSSTAT_RTA \
|
||||
MAKE_REG_MASK(0x1, 9) //((uint32_t)0x00000200) // Read Transfer Active
|
||||
#define SDHC_PRSSTAT_WTA \
|
||||
MAKE_REG_MASK(0x1, 8) //((uint32_t)0x00000100) // Write Transfer Active
|
||||
#define SDHC_PRSSTAT_SDOFF \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 7) //((uint32_t)0x00000080) // SD Clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_PEROFF \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 6) //((uint32_t)0x00000040) // SDHC clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_HCKOFF \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 5) //((uint32_t)0x00000020) // System Clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_IPGOFF \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 4) //((uint32_t)0x00000010) // Bus Clock Gated Off Internally
|
||||
#define SDHC_PRSSTAT_SDSTB \
|
||||
MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // SD Clock Stable
|
||||
#define SDHC_PRSSTAT_DLA \
|
||||
MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Data Line Active
|
||||
#define SDHC_PRSSTAT_CDIHB \
|
||||
MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Command Inhibit (DAT)
|
||||
#define SDHC_PRSSTAT_CIHB \
|
||||
MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Command Inhibit (CMD)
|
||||
|
||||
#define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1,30) //
|
||||
#define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n,0x7,12) //
|
||||
#define SDHC_PROCTL_WECRM MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Wakeup Event Enable On SD Card Removal
|
||||
#define SDHC_PROCTL_WECINS MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Wakeup Event Enable On SD Card Insertion
|
||||
#define SDHC_PROCTL_WECINT MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Wakeup Event Enable On Card Interrupt
|
||||
#define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1,20) //
|
||||
#define SDHC_PROCTL_IABG MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Interrupt At Block Gap
|
||||
#define SDHC_PROCTL_RWCTL MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Read Wait Control
|
||||
#define SDHC_PROCTL_CREQ MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Continue Request
|
||||
#define SDHC_PROCTL_SABGREQ MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Stop At Block Gap Request
|
||||
#define SDHC_PROCTL_DMAS(n) MAKE_REG_SET(n,0x3,8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select
|
||||
#define SDHC_PROCTL_CDSS MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Detect Signal Selection
|
||||
#define SDHC_PROCTL_CDTL MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Detect Test Level
|
||||
#define SDHC_PROCTL_EMODE(n) MAKE_REG_SET(n,0x3,4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode
|
||||
#define SDHC_PROCTL_EMODE_MASK MAKE_REG_MASK(0x3,4) //(uint32_t)((0x3)<<4) // Endian Mode
|
||||
#define SDHC_PROCTL_D3CD MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin
|
||||
#define SDHC_PROCTL_DTW(n) MAKE_REG_SET(n,0x3,1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width, 0=1bit, 1=4bit, 2=8bit
|
||||
#define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3,1) //((uint32_t)0x00000006)
|
||||
#define SDHC_PROCTL_LCTL MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // LED Control
|
||||
#define SDHC_PROTCT_NONEXACT_BLKRD MAKE_REG_MASK(0x1, 30) //
|
||||
#define SDHC_PROTCT_BURST_LENEN(n) MAKE_REG_SET(n, 0x7, 12) //
|
||||
#define SDHC_PROCTL_WECRM \
|
||||
MAKE_REG_MASK(0x1, 26) //((uint32_t)0x04000000) // Wakeup Event Enable On
|
||||
// SD Card Removal
|
||||
#define SDHC_PROCTL_WECINS \
|
||||
MAKE_REG_MASK(0x1, 25) //((uint32_t)0x02000000) // Wakeup Event Enable On
|
||||
// SD Card Insertion
|
||||
#define SDHC_PROCTL_WECINT \
|
||||
MAKE_REG_MASK(0x1, 24) //((uint32_t)0x01000000) // Wakeup Event Enable On
|
||||
// Card Interrupt
|
||||
#define SDHC_PROCTL_RD_DONE_NOBLK MAKE_REG_MASK(0x1, 20) //
|
||||
#define SDHC_PROCTL_IABG \
|
||||
MAKE_REG_MASK(0x1, 19) //((uint32_t)0x00080000) // Interrupt At Block Gap
|
||||
#define SDHC_PROCTL_RWCTL \
|
||||
MAKE_REG_MASK(0x1, 18) //((uint32_t)0x00040000) // Read Wait Control
|
||||
#define SDHC_PROCTL_CREQ \
|
||||
MAKE_REG_MASK(0x1, 17) //((uint32_t)0x00020000) // Continue Request
|
||||
#define SDHC_PROCTL_SABGREQ \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
16) //((uint32_t)0x00010000) // Stop At Block Gap Request
|
||||
#define SDHC_PROCTL_DMAS(n) \
|
||||
MAKE_REG_SET(n, 0x3, 8) //(uint32_t)(((n) & 0x3)<<8) // DMA Select
|
||||
#define SDHC_PROCTL_CDSS \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
7) //((uint32_t)0x00000080) // Card Detect Signal Selection
|
||||
#define SDHC_PROCTL_CDTL \
|
||||
MAKE_REG_MASK(0x1, 6) //((uint32_t)0x00000040) // Card Detect Test Level
|
||||
#define SDHC_PROCTL_EMODE(n) \
|
||||
MAKE_REG_SET(n, 0x3, 4) //(uint32_t)(((n) & 0x3)<<4) // Endian Mode
|
||||
#define SDHC_PROCTL_EMODE_MASK \
|
||||
MAKE_REG_MASK(0x3, 4) //(uint32_t)((0x3)<<4) // Endian Mode
|
||||
#define SDHC_PROCTL_D3CD \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
3) //((uint32_t)0x00000008) // DAT3 As Card Detection Pin
|
||||
#define SDHC_PROCTL_DTW(n) \
|
||||
MAKE_REG_SET(n, 0x3, 1) //(uint32_t)(((n) & 0x3)<<1) // Data Transfer Width,
|
||||
// 0=1bit, 1=4bit, 2=8bit
|
||||
#define SDHC_PROCTL_DTW_MASK MAKE_REG_MASK(0x3, 1) //((uint32_t)0x00000006)
|
||||
#define SDHC_PROCTL_LCTL \
|
||||
MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // LED Control
|
||||
|
||||
#define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1,28) //
|
||||
#define SDHC_SYSCTL_INITA MAKE_REG_MASK(0x1,27) //((uint32_t)0x08000000) // Initialization Active
|
||||
#define SDHC_SYSCTL_RSTD MAKE_REG_MASK(0x1,26) //((uint32_t)0x04000000) // Software Reset For DAT Line
|
||||
#define SDHC_SYSCTL_RSTC MAKE_REG_MASK(0x1,25) //((uint32_t)0x02000000) // Software Reset For CMD Line
|
||||
#define SDHC_SYSCTL_RSTA MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Software Reset For ALL
|
||||
#define SDHC_SYSCTL_DTOCV(n) MAKE_REG_SET(n,0xF,16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value
|
||||
#define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF,16) //((uint32_t)0x000F0000)
|
||||
#define SDHC_SYSCTL_SDCLKFS(n) MAKE_REG_SET(n,0xFF,8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select
|
||||
#define SDHC_SYSCTL_SDCLKFS_MASK MAKE_REG_MASK(0xFF,8) //((uint32_t)0x0000FF00)
|
||||
#define SDHC_SYSCTL_DVS(n) MAKE_REG_SET(n,0xF,4) //(uint32_t)(((n) & 0xF)<<4) // Divisor
|
||||
#define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF,4) //((uint32_t)0x000000F0)
|
||||
#define SDHC_SYSCTL_RSTT MAKE_REG_MASK(0x1, 28) //
|
||||
#define SDHC_SYSCTL_INITA \
|
||||
MAKE_REG_MASK(0x1, 27) //((uint32_t)0x08000000) // Initialization Active
|
||||
#define SDHC_SYSCTL_RSTD \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 26) //((uint32_t)0x04000000) // Software Reset For DAT Line
|
||||
#define SDHC_SYSCTL_RSTC \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 25) //((uint32_t)0x02000000) // Software Reset For CMD Line
|
||||
#define SDHC_SYSCTL_RSTA \
|
||||
MAKE_REG_MASK(0x1, 24) //((uint32_t)0x01000000) // Software Reset For ALL
|
||||
#define SDHC_SYSCTL_DTOCV(n) \
|
||||
MAKE_REG_SET( \
|
||||
n, 0xF, \
|
||||
16) //(uint32_t)(((n) & 0xF)<<16) // Data Timeout Counter Value
|
||||
#define SDHC_SYSCTL_DTOCV_MASK MAKE_REG_MASK(0xF, 16) //((uint32_t)0x000F0000)
|
||||
#define SDHC_SYSCTL_SDCLKFS(n) \
|
||||
MAKE_REG_SET(n, 0xFF, \
|
||||
8) //(uint32_t)(((n) & 0xFF)<<8) // SDCLK Frequency Select
|
||||
#define SDHC_SYSCTL_SDCLKFS_MASK \
|
||||
MAKE_REG_MASK(0xFF, 8) //((uint32_t)0x0000FF00)
|
||||
#define SDHC_SYSCTL_DVS(n) \
|
||||
MAKE_REG_SET(n, 0xF, 4) //(uint32_t)(((n) & 0xF)<<4) // Divisor
|
||||
#define SDHC_SYSCTL_DVS_MASK MAKE_REG_MASK(0xF, 4) //((uint32_t)0x000000F0)
|
||||
|
||||
#define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable
|
||||
#define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable
|
||||
#define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable
|
||||
#define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable
|
||||
#define SDHC_SYSCTL_SDCLKEN ((uint32_t)0x00000008) // SD Clock Enable
|
||||
#define SDHC_SYSCTL_PEREN ((uint32_t)0x00000004) // Peripheral Clock Enable
|
||||
#define SDHC_SYSCTL_HCKEN ((uint32_t)0x00000002) // System Clock Enable
|
||||
#define SDHC_SYSCTL_IPGEN ((uint32_t)0x00000001) // IPG Clock Enable
|
||||
|
||||
#define SDHC_IRQSTAT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error
|
||||
#define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1,26) //
|
||||
#define SDHC_IRQSTAT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error
|
||||
#define SDHC_IRQSTAT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error
|
||||
#define SDHC_IRQSTAT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error
|
||||
#define SDHC_IRQSTAT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error
|
||||
#define SDHC_IRQSTAT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error
|
||||
#define SDHC_IRQSTAT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error
|
||||
#define SDHC_IRQSTAT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error
|
||||
#define SDHC_IRQSTAT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error
|
||||
#define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1,14) //
|
||||
#define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1,12) //
|
||||
#define SDHC_IRQSTAT_CINT MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt
|
||||
#define SDHC_IRQSTAT_CRM MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal
|
||||
#define SDHC_IRQSTAT_CINS MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion
|
||||
#define SDHC_IRQSTAT_BRR MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready
|
||||
#define SDHC_IRQSTAT_BWR MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready
|
||||
#define SDHC_IRQSTAT_DINT MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt
|
||||
#define SDHC_IRQSTAT_BGE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event
|
||||
#define SDHC_IRQSTAT_TC MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete
|
||||
#define SDHC_IRQSTAT_CC MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete
|
||||
#define SDHC_IRQSTAT_DMAE \
|
||||
MAKE_REG_MASK(0x1, 28) //((uint32_t)0x10000000) // DMA Error
|
||||
#define SDHC_IRQSTAT_TNE MAKE_REG_MASK(0x1, 26) //
|
||||
#define SDHC_IRQSTAT_AC12E \
|
||||
MAKE_REG_MASK(0x1, 24) //((uint32_t)0x01000000) // Auto CMD12 Error
|
||||
#define SDHC_IRQSTAT_DEBE \
|
||||
MAKE_REG_MASK(0x1, 22) //((uint32_t)0x00400000) // Data End Bit Error
|
||||
#define SDHC_IRQSTAT_DCE \
|
||||
MAKE_REG_MASK(0x1, 21) //((uint32_t)0x00200000) // Data CRC Error
|
||||
#define SDHC_IRQSTAT_DTOE \
|
||||
MAKE_REG_MASK(0x1, 20) //((uint32_t)0x00100000) // Data Timeout Error
|
||||
#define SDHC_IRQSTAT_CIE \
|
||||
MAKE_REG_MASK(0x1, 19) //((uint32_t)0x00080000) // Command Index Error
|
||||
#define SDHC_IRQSTAT_CEBE \
|
||||
MAKE_REG_MASK(0x1, 18) //((uint32_t)0x00040000) // Command End Bit Error
|
||||
#define SDHC_IRQSTAT_CCE \
|
||||
MAKE_REG_MASK(0x1, 17) //((uint32_t)0x00020000) // Command CRC Error
|
||||
#define SDHC_IRQSTAT_CTOE \
|
||||
MAKE_REG_MASK(0x1, 16) //((uint32_t)0x00010000) // Command Timeout Error
|
||||
#define SDHC_IRQSTAT_TP MAKE_REG_MASK(0x1, 14) //
|
||||
#define SDHC_IRQSTAT_RTE MAKE_REG_MASK(0x1, 12) //
|
||||
#define SDHC_IRQSTAT_CINT \
|
||||
MAKE_REG_MASK(0x1, 8) //((uint32_t)0x00000100) // Card Interrupt
|
||||
#define SDHC_IRQSTAT_CRM \
|
||||
MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // Card Removal
|
||||
#define SDHC_IRQSTAT_CINS \
|
||||
MAKE_REG_MASK(0x1, 6) //((uint32_t)0x00000040) // Card Insertion
|
||||
#define SDHC_IRQSTAT_BRR \
|
||||
MAKE_REG_MASK(0x1, 5) //((uint32_t)0x00000020) // Buffer Read Ready
|
||||
#define SDHC_IRQSTAT_BWR \
|
||||
MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Buffer Write Ready
|
||||
#define SDHC_IRQSTAT_DINT \
|
||||
MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // DMA Interrupt
|
||||
#define SDHC_IRQSTAT_BGE \
|
||||
MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Block Gap Event
|
||||
#define SDHC_IRQSTAT_TC \
|
||||
MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Transfer Complete
|
||||
#define SDHC_IRQSTAT_CC \
|
||||
MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Command Complete
|
||||
|
||||
#define SDHC_IRQSTATEN_DMAESEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Status Enable
|
||||
#define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1,26) //
|
||||
#define SDHC_IRQSTATEN_AC12ESEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable
|
||||
#define SDHC_IRQSTATEN_DEBESEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable
|
||||
#define SDHC_IRQSTATEN_DCESEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Status Enable
|
||||
#define SDHC_IRQSTATEN_DTOESEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CIESEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CEBESEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CCESEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CTOESEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable
|
||||
#define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1,14) //
|
||||
#define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1,12) //
|
||||
#define SDHC_IRQSTATEN_CINTSEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Status Enable
|
||||
#define SDHC_IRQSTATEN_CRMSEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Status Enable
|
||||
#define SDHC_IRQSTATEN_CINSEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Status Enable
|
||||
#define SDHC_IRQSTATEN_BRRSEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable
|
||||
#define SDHC_IRQSTATEN_BWRSEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable
|
||||
#define SDHC_IRQSTATEN_DINTSEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable
|
||||
#define SDHC_IRQSTATEN_BGESEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Status Enable
|
||||
#define SDHC_IRQSTATEN_TCSEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Status Enable
|
||||
#define SDHC_IRQSTATEN_CCSEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Status Enable
|
||||
#define SDHC_IRQSTATEN_DMAESEN \
|
||||
MAKE_REG_MASK(0x1, 28) //((uint32_t)0x10000000) // DMA Error Status Enable
|
||||
#define SDHC_IRQSTATEN_TNESEN MAKE_REG_MASK(0x1, 26) //
|
||||
#define SDHC_IRQSTATEN_AC12ESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 24) //((uint32_t)0x01000000) // Auto CMD12 Error Status Enable
|
||||
#define SDHC_IRQSTATEN_DEBESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
22) //((uint32_t)0x00400000) // Data End Bit Error Status Enable
|
||||
#define SDHC_IRQSTATEN_DCESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 21) //((uint32_t)0x00200000) // Data CRC Error Status Enable
|
||||
#define SDHC_IRQSTATEN_DTOESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
20) //((uint32_t)0x00100000) // Data Timeout Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CIESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
19) //((uint32_t)0x00080000) // Command Index Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CEBESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
18) //((uint32_t)0x00040000) // Command End Bit Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CCESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 17) //((uint32_t)0x00020000) // Command CRC Error Status Enable
|
||||
#define SDHC_IRQSTATEN_CTOESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
16) //((uint32_t)0x00010000) // Command Timeout Error Status Enable
|
||||
#define SDHC_IRQSTATEN_TPSEN MAKE_REG_MASK(0x1, 14) //
|
||||
#define SDHC_IRQSTATEN_RTESEN MAKE_REG_MASK(0x1, 12) //
|
||||
#define SDHC_IRQSTATEN_CINTSEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
8) //((uint32_t)0x00000100) // Card Interrupt Status Enable
|
||||
#define SDHC_IRQSTATEN_CRMSEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
7) //((uint32_t)0x00000080) // Card Removal Status Enable
|
||||
#define SDHC_IRQSTATEN_CINSEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
6) //((uint32_t)0x00000040) // Card Insertion Status Enable
|
||||
#define SDHC_IRQSTATEN_BRRSEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 5) //((uint32_t)0x00000020) // Buffer Read Ready Status Enable
|
||||
#define SDHC_IRQSTATEN_BWRSEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 4) //((uint32_t)0x00000010) // Buffer Write Ready Status Enable
|
||||
#define SDHC_IRQSTATEN_DINTSEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
3) //((uint32_t)0x00000008) // DMA Interrupt Status Enable
|
||||
#define SDHC_IRQSTATEN_BGESEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 2) //((uint32_t)0x00000004) // Block Gap Event Status Enable
|
||||
#define SDHC_IRQSTATEN_TCSEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 1) //((uint32_t)0x00000002) // Transfer Complete Status Enable
|
||||
#define SDHC_IRQSTATEN_CCSEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 0) //((uint32_t)0x00000001) // Command Complete Status Enable
|
||||
|
||||
#define SDHC_IRQSIGEN_DMAEIEN MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1,26) //
|
||||
#define SDHC_IRQSIGEN_AC12EIEN MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DEBEIEN MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DCEIEN MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DTOEIEN MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CIEIEN MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CEBEIEN MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Command End Bit Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CCEIEN MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CTOEIEN MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Command Timeout Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1,14) //
|
||||
#define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1,12) //
|
||||
#define SDHC_IRQSIGEN_CINTIEN MAKE_REG_MASK(0x1,8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CRMIEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CINSIEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_BRRIEN MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_BWRIEN MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DINTIEN MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_BGEIEN MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_TCIEN MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CCIEN MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DMAEIEN \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
28) //((uint32_t)0x10000000) // DMA Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_TNEIEN MAKE_REG_MASK(0x1, 26) //
|
||||
#define SDHC_IRQSIGEN_AC12EIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
24) //((uint32_t)0x01000000) // Auto CMD12 Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DEBEIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
22) //((uint32_t)0x00400000) // Data End Bit Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DCEIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 21) //((uint32_t)0x00200000) // Data CRC Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DTOEIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
20) //((uint32_t)0x00100000) // Data Timeout Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CIEIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
19) //((uint32_t)0x00080000) // Command Index Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CEBEIEN \
|
||||
MAKE_REG_MASK(0x1, 18) //((uint32_t)0x00040000) // Command End Bit Error
|
||||
// Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CCEIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
17) //((uint32_t)0x00020000) // Command CRC Error Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CTOEIEN \
|
||||
MAKE_REG_MASK(0x1, 16) //((uint32_t)0x00010000) // Command Timeout Error
|
||||
// Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_TPIEN MAKE_REG_MASK(0x1, 14) //
|
||||
#define SDHC_IRQSIGEN_RTEIEN MAKE_REG_MASK(0x1, 12) //
|
||||
#define SDHC_IRQSIGEN_CINTIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 8) //((uint32_t)0x00000100) // Card Interrupt Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CRMIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 7) //((uint32_t)0x00000080) // Card Removal Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CINSIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 6) //((uint32_t)0x00000040) // Card Insertion Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_BRRIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
5) //((uint32_t)0x00000020) // Buffer Read Ready Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_BWRIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
4) //((uint32_t)0x00000010) // Buffer Write Ready Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_DINTIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 3) //((uint32_t)0x00000008) // DMA Interrupt Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_BGEIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 2) //((uint32_t)0x00000004) // Block Gap Event Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_TCIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
1) //((uint32_t)0x00000002) // Transfer Complete Interrupt Enable
|
||||
#define SDHC_IRQSIGEN_CCIEN \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
0) //((uint32_t)0x00000001) // Command Complete Interrupt Enable
|
||||
|
||||
#define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1,23) //
|
||||
#define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1,22) //
|
||||
#define SDHC_AC12ERR_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Command Not Issued By Auto CMD12 Error
|
||||
#define SDHC_AC12ERR_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Auto CMD12 Index Error
|
||||
#define SDHC_AC12ERR_AC12CE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error
|
||||
#define SDHC_AC12ERR_AC12EBE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error
|
||||
#define SDHC_AC12ERR_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error
|
||||
#define SDHC_AC12ERR_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed
|
||||
#define SDHC_AC12ERR_SMPLCLK_SEL MAKE_REG_MASK(0x1, 23) //
|
||||
#define SDHC_AC12ERR_EXEC_TUNING MAKE_REG_MASK(0x1, 22) //
|
||||
#define SDHC_AC12ERR_CNIBAC12E \
|
||||
MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // Command Not Issued By
|
||||
// Auto CMD12 Error
|
||||
#define SDHC_AC12ERR_AC12IE \
|
||||
MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Auto CMD12 Index Error
|
||||
#define SDHC_AC12ERR_AC12CE \
|
||||
MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // Auto CMD12 CRC Error
|
||||
#define SDHC_AC12ERR_AC12EBE \
|
||||
MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004) // Auto CMD12 End Bit Error
|
||||
#define SDHC_AC12ERR_AC12TOE \
|
||||
MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Auto CMD12 Timeout Error
|
||||
#define SDHC_AC12ERR_AC12NE \
|
||||
MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Auto CMD12 Not Executed
|
||||
|
||||
#define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1,26) //
|
||||
#define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1,25) //
|
||||
#define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1,24) //
|
||||
#define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1,23) //
|
||||
#define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1,22) //
|
||||
#define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1,21) //
|
||||
#define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1,20) //
|
||||
#define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x7,16) //
|
||||
#define SDHC_HTCAPBLT_RETUN_MODE MAKE_REG_GET((USDHC1_HOST_CTRL_CAP),0x3,14) //
|
||||
#define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1,13) //
|
||||
#define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n,0xF,8) //
|
||||
#define SDHC_HTCAPBLT_VS18 MAKE_REG_MASK(0x1, 26) //
|
||||
#define SDHC_HTCAPBLT_VS30 MAKE_REG_MASK(0x1, 25) //
|
||||
#define SDHC_HTCAPBLT_VS33 MAKE_REG_MASK(0x1, 24) //
|
||||
#define SDHC_HTCAPBLT_SRS MAKE_REG_MASK(0x1, 23) //
|
||||
#define SDHC_HTCAPBLT_DMAS MAKE_REG_MASK(0x1, 22) //
|
||||
#define SDHC_HTCAPBLT_HSS MAKE_REG_MASK(0x1, 21) //
|
||||
#define SDHC_HTCAPBLT_ADMAS MAKE_REG_MASK(0x1, 20) //
|
||||
#define SDHC_HTCAPBLT_MBL_VAL MAKE_REG_GET((USDHC1_HOST_CTRL_CAP), 0x7, 16) //
|
||||
#define SDHC_HTCAPBLT_RETUN_MODE \
|
||||
MAKE_REG_GET((USDHC1_HOST_CTRL_CAP), 0x3, 14) //
|
||||
#define SDHC_HTCAPBLT_TUNE_SDR50 MAKE_REG_MASK(0x1, 13) //
|
||||
#define SDHC_HTCAPBLT_TIME_RETUN(n) MAKE_REG_SET(n, 0xF, 8) //
|
||||
|
||||
#define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F,24) //
|
||||
#define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F,8) //
|
||||
#define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF,16) //
|
||||
#define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF,0) //
|
||||
#define SDHC_WML_WR_BRSTLEN(n) MAKE_REG_SET(n,0x1F,24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len
|
||||
#define SDHC_WML_RD_BRSTLEN(n) MAKE_REG_SET(n,0x1F,8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len
|
||||
#define SDHC_WML_WR_WML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
|
||||
#define SDHC_WML_RD_WML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
|
||||
#define SDHC_WML_WRWML(n) MAKE_REG_SET(n,0xFF,16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
|
||||
#define SDHC_WML_RDWML(n) MAKE_REG_SET(n,0xFF,0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
|
||||
#define SDHC_WML_WR_BRSTLEN_MASK MAKE_REG_MASK(0x1F, 24) //
|
||||
#define SDHC_WML_RD_BRSTLEN_MASK MAKE_REG_MASK(0x1F, 8) //
|
||||
#define SDHC_WML_WR_WML_MASK MAKE_REG_MASK(0xFF, 16) //
|
||||
#define SDHC_WML_RD_WML_MASK MAKE_REG_MASK(0xFF, 0) //
|
||||
#define SDHC_WML_WR_BRSTLEN(n) \
|
||||
MAKE_REG_SET(n, 0x1F, 24) //(uint32_t)(((n) & 0x7F)<<16) // Write Burst Len
|
||||
#define SDHC_WML_RD_BRSTLEN(n) \
|
||||
MAKE_REG_SET(n, 0x1F, 8) //(uint32_t)(((n) & 0x7F)<<0) // Read Burst Len
|
||||
#define SDHC_WML_WR_WML(n) \
|
||||
MAKE_REG_SET(n, 0xFF, \
|
||||
16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
|
||||
#define SDHC_WML_RD_WML(n) \
|
||||
MAKE_REG_SET(n, 0xFF, \
|
||||
0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
|
||||
#define SDHC_WML_WRWML(n) \
|
||||
MAKE_REG_SET(n, 0xFF, \
|
||||
16) //(uint32_t)(((n) & 0x7F)<<16) // Write Watermark Level
|
||||
#define SDHC_WML_RDWML(n) \
|
||||
MAKE_REG_SET(n, 0xFF, \
|
||||
0) //(uint32_t)(((n) & 0x7F)<<0) // Read Watermark Level
|
||||
|
||||
// Teensy 4.0 only
|
||||
#define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1,0) //
|
||||
#define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1,1) //
|
||||
#define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1,2) //
|
||||
#define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1,3) //
|
||||
#define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1,4) //
|
||||
#define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1,5) //
|
||||
#define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1,6) //
|
||||
#define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1,7) //
|
||||
#define SDHC_MIX_CTRL_DMAEN MAKE_REG_MASK(0x1, 0) //
|
||||
#define SDHC_MIX_CTRL_BCEN MAKE_REG_MASK(0x1, 1) //
|
||||
#define SDHC_MIX_CTRL_AC12EN MAKE_REG_MASK(0x1, 2) //
|
||||
#define SDHC_MIX_CTRL_DDR_EN MAKE_REG_MASK(0x1, 3) //
|
||||
#define SDHC_MIX_CTRL_DTDSEL MAKE_REG_MASK(0x1, 4) //
|
||||
#define SDHC_MIX_CTRL_MSBSEL MAKE_REG_MASK(0x1, 5) //
|
||||
#define SDHC_MIX_CTRL_NIBBLE_POS MAKE_REG_MASK(0x1, 6) //
|
||||
#define SDHC_MIX_CTRL_AC23EN MAKE_REG_MASK(0x1, 7) //
|
||||
|
||||
#define SDHC_FEVT_CINT MAKE_REG_MASK(0x1,31) //((uint32_t)0x80000000) // Force Event Card Interrupt
|
||||
#define SDHC_FEVT_DMAE MAKE_REG_MASK(0x1,28) //((uint32_t)0x10000000) // Force Event DMA Error
|
||||
#define SDHC_FEVT_AC12E MAKE_REG_MASK(0x1,24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error
|
||||
#define SDHC_FEVT_DEBE MAKE_REG_MASK(0x1,22) //((uint32_t)0x00400000) // Force Event Data End Bit Error
|
||||
#define SDHC_FEVT_DCE MAKE_REG_MASK(0x1,21) //((uint32_t)0x00200000) // Force Event Data CRC Error
|
||||
#define SDHC_FEVT_DTOE MAKE_REG_MASK(0x1,20) //((uint32_t)0x00100000) // Force Event Data Timeout Error
|
||||
#define SDHC_FEVT_CIE MAKE_REG_MASK(0x1,19) //((uint32_t)0x00080000) // Force Event Command Index Error
|
||||
#define SDHC_FEVT_CEBE MAKE_REG_MASK(0x1,18) //((uint32_t)0x00040000) // Force Event Command End Bit Error
|
||||
#define SDHC_FEVT_CCE MAKE_REG_MASK(0x1,17) //((uint32_t)0x00020000) // Force Event Command CRC Error
|
||||
#define SDHC_FEVT_CTOE MAKE_REG_MASK(0x1,16) //((uint32_t)0x00010000) // Force Event Command Timeout Error
|
||||
#define SDHC_FEVT_CNIBAC12E MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // Force Event Command Not Executed By Auto Command 12 Error
|
||||
#define SDHC_FEVT_AC12IE MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Force Event Auto Command 12 Index Error
|
||||
#define SDHC_FEVT_AC12EBE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008) // Force Event Auto Command 12 End Bit Error
|
||||
#define SDHC_FEVT_AC12CE MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error
|
||||
#define SDHC_FEVT_AC12TOE MAKE_REG_MASK(0x1,1) //((uint32_t)0x00000002) // Force Event Auto Command 12 Time Out Error
|
||||
#define SDHC_FEVT_AC12NE MAKE_REG_MASK(0x1,0) //((uint32_t)0x00000001) // Force Event Auto Command 12 Not Executed
|
||||
#define SDHC_FEVT_CINT \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
31) //((uint32_t)0x80000000) // Force Event Card Interrupt
|
||||
#define SDHC_FEVT_DMAE \
|
||||
MAKE_REG_MASK(0x1, 28) //((uint32_t)0x10000000) // Force Event DMA Error
|
||||
#define SDHC_FEVT_AC12E \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 24) //((uint32_t)0x01000000) // Force Event Auto CMD12 Error
|
||||
#define SDHC_FEVT_DEBE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 22) //((uint32_t)0x00400000) // Force Event Data End Bit Error
|
||||
#define SDHC_FEVT_DCE \
|
||||
MAKE_REG_MASK(0x1, \
|
||||
21) //((uint32_t)0x00200000) // Force Event Data CRC Error
|
||||
#define SDHC_FEVT_DTOE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 20) //((uint32_t)0x00100000) // Force Event Data Timeout Error
|
||||
#define SDHC_FEVT_CIE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 19) //((uint32_t)0x00080000) // Force Event Command Index Error
|
||||
#define SDHC_FEVT_CEBE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
18) //((uint32_t)0x00040000) // Force Event Command End Bit Error
|
||||
#define SDHC_FEVT_CCE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, 17) //((uint32_t)0x00020000) // Force Event Command CRC Error
|
||||
#define SDHC_FEVT_CTOE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
16) //((uint32_t)0x00010000) // Force Event Command Timeout Error
|
||||
#define SDHC_FEVT_CNIBAC12E \
|
||||
MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // Force Event Command Not
|
||||
// Executed By Auto Command 12 Error
|
||||
#define SDHC_FEVT_AC12IE \
|
||||
MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Force Event Auto Command
|
||||
// 12 Index Error
|
||||
#define SDHC_FEVT_AC12EBE \
|
||||
MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008) // Force Event Auto Command
|
||||
// 12 End Bit Error
|
||||
#define SDHC_FEVT_AC12CE \
|
||||
MAKE_REG_MASK( \
|
||||
0x1, \
|
||||
2) //((uint32_t)0x00000004) // Force Event Auto Command 12 CRC Error
|
||||
#define SDHC_FEVT_AC12TOE \
|
||||
MAKE_REG_MASK(0x1, 1) //((uint32_t)0x00000002) // Force Event Auto Command
|
||||
// 12 Time Out Error
|
||||
#define SDHC_FEVT_AC12NE \
|
||||
MAKE_REG_MASK(0x1, 0) //((uint32_t)0x00000001) // Force Event Auto Command
|
||||
// 12 Not Executed
|
||||
|
||||
#define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1,3) //((uint32_t)0x00000008)
|
||||
#define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1,2) //((uint32_t)0x00000004)
|
||||
#define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3,0) //((uint32_t)0x00000003)
|
||||
#define SDHC_ADMAES_ADMADCE MAKE_REG_MASK(0x1, 3) //((uint32_t)0x00000008)
|
||||
#define SDHC_ADMAES_ADMALME MAKE_REG_MASK(0x1, 2) //((uint32_t)0x00000004)
|
||||
#define SDHC_ADMAES_ADMAES_MASK MAKE_REG_MASK(0x3, 0) //((uint32_t)0x00000003)
|
||||
|
||||
#define SDHC_MMCBOOT_BOOTBLKCNT(n) MAKE_REG_MASK(0xFF,16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap value of automatic mode
|
||||
#define SDHC_MMCBOOT_AUTOSABGEN MAKE_REG_MASK(0x1,7) //((uint32_t)0x00000080) // enable auto stop at block gap function
|
||||
#define SDHC_MMCBOOT_BOOTEN MAKE_REG_MASK(0x1,6) //((uint32_t)0x00000040) // Boot Mode Enable
|
||||
#define SDHC_MMCBOOT_BOOTMODE MAKE_REG_MASK(0x1,5) //((uint32_t)0x00000020) // Boot Mode Select
|
||||
#define SDHC_MMCBOOT_BOOTACK MAKE_REG_MASK(0x1,4) //((uint32_t)0x00000010) // Boot Ack Mode Select
|
||||
#define SDHC_MMCBOOT_DTOCVACK(n) MAKE_REG_MASK(0xF,0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value
|
||||
//#define SDHC_HOSTVER (*(volatile uint32_t*)0x400B10FC) // Host Controller Version
|
||||
#define SDHC_MMCBOOT_BOOTBLKCNT(n) \
|
||||
MAKE_REG_MASK(0xFF, 16) //(uint32_t)(((n) & 0xFFF)<<16) // stop at block gap
|
||||
// value of automatic mode
|
||||
#define SDHC_MMCBOOT_AUTOSABGEN \
|
||||
MAKE_REG_MASK(0x1, 7) //((uint32_t)0x00000080) // enable auto stop at
|
||||
// block gap function
|
||||
#define SDHC_MMCBOOT_BOOTEN \
|
||||
MAKE_REG_MASK(0x1, 6) //((uint32_t)0x00000040) // Boot Mode Enable
|
||||
#define SDHC_MMCBOOT_BOOTMODE \
|
||||
MAKE_REG_MASK(0x1, 5) //((uint32_t)0x00000020) // Boot Mode Select
|
||||
#define SDHC_MMCBOOT_BOOTACK \
|
||||
MAKE_REG_MASK(0x1, 4) //((uint32_t)0x00000010) // Boot Ack Mode Select
|
||||
#define SDHC_MMCBOOT_DTOCVACK(n) \
|
||||
MAKE_REG_MASK( \
|
||||
0xF, \
|
||||
0) //(uint32_t)(((n) & 0xF)<<0) // Boot ACK Time Out Counter Value
|
||||
// #define SDHC_HOSTVER (*(volatile uint32_t*)0x400B10FC) // Host Controller
|
||||
// Version
|
||||
|
||||
#define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f
|
||||
#define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f<<8)
|
||||
#define CCM_ANALOG_PFD_528_PFD1_FRAC(n) (((n)<<8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f<<16)
|
||||
#define CCM_ANALOG_PFD_528_PFD2_FRAC(n) (((n)<<16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n)&CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD1_FRAC_MASK (0x3f << 8)
|
||||
#define CCM_ANALOG_PFD_528_PFD1_FRAC(n) \
|
||||
(((n) << 8) & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD2_FRAC_MASK (0x3f << 16)
|
||||
#define CCM_ANALOG_PFD_528_PFD2_FRAC(n) \
|
||||
(((n) << 16) & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD3_FRAC_MASK ((0x3f<<24)
|
||||
#define CCM_ANALOG_PFD_528_PFD3_FRAC(n) (((n)<<24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK)
|
||||
#define CCM_ANALOG_PFD_528_PFD3_FRAC(n) \
|
||||
(((n) << 24) & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK)
|
||||
|
||||
#define SDHC_DSADDR (USDHC1_DS_ADDR ) // DMA System Address register
|
||||
#define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register
|
||||
#define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register
|
||||
#define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register
|
||||
#define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0
|
||||
#define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1
|
||||
#define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2
|
||||
#define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3
|
||||
#define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register
|
||||
#define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register
|
||||
#define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register
|
||||
#define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register
|
||||
#define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register
|
||||
#define SDHC_IRQSTATEN (USDHC1_INT_STATUS_EN) // Interrupt Status Enable register
|
||||
#define SDHC_IRQSIGEN (USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register
|
||||
#define SDHC_AC12ERR (USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register
|
||||
#define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities
|
||||
#define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register
|
||||
#define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control
|
||||
#define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register
|
||||
#define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register
|
||||
#define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister
|
||||
#define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register
|
||||
#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register
|
||||
#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register
|
||||
#define SDHC_DSADDR (USDHC1_DS_ADDR) // DMA System Address register
|
||||
#define SDHC_BLKATTR (USDHC1_BLK_ATT) // Block Attributes register
|
||||
#define SDHC_CMDARG (USDHC1_CMD_ARG) // Command Argument register
|
||||
#define SDHC_XFERTYP (USDHC1_CMD_XFR_TYP) // Transfer Type register
|
||||
#define SDHC_CMDRSP0 (USDHC1_CMD_RSP0) // Command Response 0
|
||||
#define SDHC_CMDRSP1 (USDHC1_CMD_RSP1) // Command Response 1
|
||||
#define SDHC_CMDRSP2 (USDHC1_CMD_RSP2) // Command Response 2
|
||||
#define SDHC_CMDRSP3 (USDHC1_CMD_RSP3) // Command Response 3
|
||||
#define SDHC_DATPORT (USDHC1_DATA_BUFF_ACC_PORT) // Buffer Data Port register
|
||||
#define SDHC_PRSSTAT (USDHC1_PRES_STATE) // Present State register
|
||||
#define SDHC_PROCTL (USDHC1_PROT_CTRL) // Protocol Control register
|
||||
#define SDHC_SYSCTL (USDHC1_SYS_CTRL) // System Control register
|
||||
#define SDHC_IRQSTAT (USDHC1_INT_STATUS) // Interrupt Status register
|
||||
#define SDHC_IRQSTATEN \
|
||||
(USDHC1_INT_STATUS_EN) // Interrupt Status Enable register
|
||||
#define SDHC_IRQSIGEN \
|
||||
(USDHC1_INT_SIGNAL_EN) // Interrupt Signal Enable register
|
||||
#define SDHC_AC12ERR \
|
||||
(USDHC1_AUTOCMD12_ERR_STATUS) // Auto CMD12 Error Status Register
|
||||
#define SDHC_HTCAPBLT (USDHC1_HOST_CTRL_CAP) // Host Controller Capabilities
|
||||
#define SDHC_WML (USDHC1_WTMK_LVL) // Watermark Level Register
|
||||
#define SDHC_MIX_CTRL (USDHC1_MIX_CTRL) // Mixer Control
|
||||
#define SDHC_FEVT (USDHC1_FORCE_EVENT) // Force Event register
|
||||
#define SDHC_ADMAES (USDHC1_ADMA_ERR_STATUS) // ADMA Error Status register
|
||||
#define SDHC_ADSADDR (USDHC1_ADMA_SYS_ADDR) // ADMA System Addressregister
|
||||
#define SDHC_VENDOR (USDHC1_VEND_SPEC) // Vendor Specific register
|
||||
#define SDHC_MMCBOOT (USDHC1_MMC_BOOT) // MMC Boot register
|
||||
#define SDHC_VENDOR2 (USDHC2_VEND_SPEC2) // Vendor Specific2 register
|
||||
//
|
||||
#define IRQ_SDHC IRQ_SDHC1
|
||||
#define IRQ_SDHC IRQ_SDHC1
|
||||
|
||||
#define SDHC_MAX_DVS (0xF + 1U)
|
||||
#define SDHC_MAX_CLKFS (0xFF + 1U)
|
||||
#define SDHC_PREV_DVS(x) ((x) -= 1U)
|
||||
#define SDHC_PREV_CLKFS(x, y) ((x) >>= (y))
|
||||
|
||||
#define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7<<11)
|
||||
#define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7)<<11)
|
||||
#define CCM_CSCDR1_USDHC1_CLK_PODF_MASK (0x7 << 11)
|
||||
#define CCM_CSCDR1_USDHC1_CLK_PODF(n) (((n)&0x7) << 11)
|
||||
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1<)<0)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1)<<12)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1)<<13)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1)<<16)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3)<<6)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3)<<14)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3)<<14)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7)<<3)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7)<<3)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_SRE ((0x1 <) < 0)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PKE ((0x1) << 12)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PUE ((0x1) << 13)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_HYS ((0x1) << 16)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_SPEED(n) (((n)&0x3) << 6)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PUS(n) (((n)&0x3) << 14)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_PUS_MASK ((0x3) << 14)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_DSE(n) (((n)&0x7) << 3)
|
||||
#define IOMUXC_SW_PAD_CTL_PAD_DSE_MASK ((0x7) << 3)
|
||||
#endif // defined(__IMXRT1062__)
|
||||
#endif // SdioTeensy_h
|
||||
62
src/SdFat.h
62
src/SdFat.h
|
|
@ -28,19 +28,19 @@
|
|||
* \file
|
||||
* \brief main SdFs include file.
|
||||
*/
|
||||
#include "common/SysCall.h"
|
||||
#include "SdCard/SdCard.h"
|
||||
#include "ExFatLib/ExFatLib.h"
|
||||
#include "FatLib/FatLib.h"
|
||||
#include "FsLib/FsLib.h"
|
||||
#include "SdCard/SdCard.h"
|
||||
#include "common/SysCall.h"
|
||||
#if INCLUDE_SDIOS
|
||||
#include "sdios.h"
|
||||
#endif // INCLUDE_SDIOS
|
||||
//------------------------------------------------------------------------------
|
||||
/** SdFat version for cpp use. */
|
||||
#define SD_FAT_VERSION 20200
|
||||
#define SD_FAT_VERSION 20202
|
||||
/** SdFat version as string. */
|
||||
#define SD_FAT_VERSION_STR "2.2.0"
|
||||
#define SD_FAT_VERSION_STR "2.2.2"
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class SdBase
|
||||
|
|
@ -93,7 +93,7 @@ class SdBase : public Vol {
|
|||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** \return Pointer to SD card object. */
|
||||
SdCard* card() {return m_card;}
|
||||
SdCard* card() { return m_card; }
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize SD card in SPI mode.
|
||||
*
|
||||
|
|
@ -136,7 +136,8 @@ class SdBase : public Vol {
|
|||
} else if (!Vol::fatType()) {
|
||||
pr->println(F("Check SD format."));
|
||||
}
|
||||
while (true) {}
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt.
|
||||
|
|
@ -197,7 +198,7 @@ class SdBase : public Vol {
|
|||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** \return true if can be in dedicated SPI state */
|
||||
bool hasDedicatedSpi() {return m_card ? m_card->hasDedicatedSpi() : false;}
|
||||
bool hasDedicatedSpi() { return m_card ? m_card->hasDedicatedSpi() : false; }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt.
|
||||
*
|
||||
|
|
@ -205,7 +206,8 @@ class SdBase : public Vol {
|
|||
*/
|
||||
void initErrorHalt(print_t* pr) {
|
||||
initErrorPrint(pr);
|
||||
while (true) {}
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt.
|
||||
|
|
@ -244,7 +246,7 @@ class SdBase : public Vol {
|
|||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** \return true if in dedicated SPI state. */
|
||||
bool isDedicatedSpi() {return m_card ? m_card->isDedicatedSpi() : false;}
|
||||
bool isDedicatedSpi() { return m_card ? m_card->isDedicatedSpi() : false; }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print volume FAT/exFAT type.
|
||||
*
|
||||
|
|
@ -325,7 +327,7 @@ class SdBase : public Vol {
|
|||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** \return SD card error data. */
|
||||
uint8_t sdErrorData() {return m_card ? m_card->errorData() : 0;}
|
||||
uint8_t sdErrorData() { return m_card ? m_card->errorData() : 0; }
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set SPI sharing state
|
||||
* \param[in] value desired state.
|
||||
|
|
@ -339,57 +341,51 @@ class SdBase : public Vol {
|
|||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** \return pointer to base volume */
|
||||
Vol* vol() {return reinterpret_cast<Vol*>(this);}
|
||||
Vol* vol() { return reinterpret_cast<Vol*>(this); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize file system after call to cardBegin.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool volumeBegin() {
|
||||
return Vol::begin(m_card);
|
||||
}
|
||||
bool volumeBegin() { return Vol::begin(m_card); }
|
||||
#if ENABLE_ARDUINO_SERIAL
|
||||
/** Print error details after begin() fails. */
|
||||
void initErrorPrint() {
|
||||
initErrorPrint(&Serial);
|
||||
}
|
||||
void initErrorPrint() { initErrorPrint(&Serial); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print msg to Serial and halt.
|
||||
*
|
||||
* \param[in] msg Message to print.
|
||||
*/
|
||||
void errorHalt(const __FlashStringHelper* msg) {
|
||||
errorHalt(&Serial, msg);
|
||||
}
|
||||
void errorHalt(const __FlashStringHelper* msg) { errorHalt(&Serial, msg); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info to Serial and halt. */
|
||||
void errorHalt() {errorHalt(&Serial);}
|
||||
void errorHalt() { errorHalt(&Serial); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt.
|
||||
*
|
||||
* \param[in] msg Message to print.
|
||||
*/
|
||||
void errorHalt(const char* msg) {errorHalt(&Serial, msg);}
|
||||
void errorHalt(const char* msg) { errorHalt(&Serial, msg); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt. */
|
||||
void initErrorHalt() {initErrorHalt(&Serial);}
|
||||
void initErrorHalt() { initErrorHalt(&Serial); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print msg, any SD error code.
|
||||
*
|
||||
* \param[in] msg Message to print.
|
||||
*/
|
||||
void errorPrint(const char* msg) {errorPrint(&Serial, msg);}
|
||||
/** %Print msg, any SD error code.
|
||||
void errorPrint(const char* msg) { errorPrint(&Serial, msg); }
|
||||
/** %Print msg, any SD error code.
|
||||
*
|
||||
* \param[in] msg Message to print.
|
||||
*/
|
||||
void errorPrint(const __FlashStringHelper* msg) {errorPrint(&Serial, msg);}
|
||||
void errorPrint(const __FlashStringHelper* msg) { errorPrint(&Serial, msg); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt.
|
||||
*
|
||||
* \param[in] msg Message to print.
|
||||
*/
|
||||
void initErrorHalt(const char* msg) {initErrorHalt(&Serial, msg);}
|
||||
void initErrorHalt(const char* msg) { initErrorHalt(&Serial, msg); }
|
||||
//----------------------------------------------------------------------------
|
||||
/** %Print error info and halt.
|
||||
*
|
||||
|
|
@ -473,9 +469,7 @@ class SdFile : public PrintFile<SdBaseFile> {
|
|||
* \param[in] path path for file.
|
||||
* \param[in] oflag open flags.
|
||||
*/
|
||||
SdFile(const char* path, oflag_t oflag) {
|
||||
open(path, oflag);
|
||||
}
|
||||
SdFile(const char* path, oflag_t oflag) { open(path, oflag); }
|
||||
/** Set the date/time callback function
|
||||
*
|
||||
* \param[in] dateTime The user's call back function. The callback
|
||||
|
|
@ -502,13 +496,11 @@ class SdFile : public PrintFile<SdBaseFile> {
|
|||
* sync() maintains the last access date and last modify date/time.
|
||||
*
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t* date, uint16_t* time)) {
|
||||
static void dateTimeCallback(void (*dateTime)(uint16_t* date,
|
||||
uint16_t* time)) {
|
||||
FsDateTime::setCallback(dateTime);
|
||||
}
|
||||
/** Cancel the date/time callback function. */
|
||||
static void dateTimeCallbackCancel() {
|
||||
FsDateTime::clearCallback();
|
||||
}
|
||||
static void dateTimeCallbackCancel() { FsDateTime::clearCallback(); }
|
||||
};
|
||||
#endif // SdFat_h
|
||||
|
|
|
|||
|
|
@ -122,14 +122,28 @@
|
|||
#define SPI_DRIVER_SELECT 0
|
||||
#endif // SPI_DRIVER_SELECT
|
||||
/**
|
||||
* If USE_SPI_ARRAY_TRANSFER is non-zero and the standard SPI library is
|
||||
* use, the array transfer function, transfer(buf, size), will be used.
|
||||
* This option will allocate up to a 512 byte temporary buffer for send.
|
||||
* If USE_SPI_ARRAY_TRANSFER is one and the standard SPI library is
|
||||
* use, the array transfer function, transfer(buf, count), will be used.
|
||||
* This option will allocate a 512 byte temporary buffer for send.
|
||||
* This may be faster for some boards. Do not use this with AVR boards.
|
||||
*
|
||||
* Warning: the next options are often fastest but only available for some
|
||||
* non-Arduino board packages.
|
||||
*
|
||||
* If USE_SPI_ARRAY_TRANSFER is two use transfer(nullptr, buf, count) for
|
||||
* receive and transfer(buf, nullptr, count) for send.
|
||||
*
|
||||
* If USE_SPI_ARRAY_TRANSFER is three use transfer(nullptr, buf, count) for
|
||||
* receive and transfer(buf, rxTmp, count) for send. Try this with Adafruit
|
||||
* SAMD51.
|
||||
*
|
||||
* If USE_SPI_ARRAY_TRANSFER is four use transfer(txTmp, buf, count) for
|
||||
* receive and transfer(buf, rxTmp, count) for send. Try this with STM32.
|
||||
*/
|
||||
#ifndef USE_SPI_ARRAY_TRANSFER
|
||||
#define USE_SPI_ARRAY_TRANSFER 0
|
||||
#endif // USE_SPI_ARRAY_TRANSFER
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* SD maximum initialization clock rate.
|
||||
*/
|
||||
|
|
@ -161,7 +175,8 @@
|
|||
#ifndef USE_BLOCK_DEVICE_INTERFACE
|
||||
#define USE_BLOCK_DEVICE_INTERFACE 0
|
||||
#endif // USE_BLOCK_DEVICE_INTERFACE
|
||||
/**
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* SD_CHIP_SELECT_MODE defines how the functions
|
||||
* void sdCsInit(SdCsPin_t pin) {pinMode(pin, OUTPUT);}
|
||||
* and
|
||||
|
|
@ -346,8 +361,8 @@ typedef uint8_t SdCsPin_t;
|
|||
* Set USE_SIMPLE_LITTLE_ENDIAN nonzero for little endian processors
|
||||
* with no memory alignment restrictions.
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\
|
||||
&& (defined(__AVR__) || defined(__ARM_FEATURE_UNALIGNED))
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && \
|
||||
(defined(__AVR__) || defined(__ARM_FEATURE_UNALIGNED))
|
||||
#define USE_SIMPLE_LITTLE_ENDIAN 1
|
||||
#else // __BYTE_ORDER_
|
||||
#define USE_SIMPLE_LITTLE_ENDIAN 0
|
||||
|
|
@ -394,11 +409,11 @@ typedef uint8_t SdCsPin_t;
|
|||
#endif // BUILTIN_SDCARD
|
||||
// SPI for built-in card.
|
||||
#ifndef SDCARD_SPI
|
||||
#define SDCARD_SPI SPI1
|
||||
#define SDCARD_SPI SPI1
|
||||
#define SDCARD_MISO_PIN 59
|
||||
#define SDCARD_MOSI_PIN 61
|
||||
#define SDCARD_SCK_PIN 60
|
||||
#define SDCARD_SS_PIN 62
|
||||
#define SDCARD_SCK_PIN 60
|
||||
#define SDCARD_SS_PIN 62
|
||||
#endif // SDCARD_SPI
|
||||
#define HAS_SDIO_CLASS 1
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
|
|
@ -409,15 +424,13 @@ typedef uint8_t SdCsPin_t;
|
|||
/**
|
||||
* Determine the default SPI configuration.
|
||||
*/
|
||||
#if defined(ARDUINO_ARCH_APOLLO3)\
|
||||
|| (defined(__AVR__) && defined(SPDR) && defined(SPSR) && defined(SPIF))\
|
||||
|| (defined(__AVR__) && defined(SPI0) && defined(SPI_RXCIF_bm))\
|
||||
|| defined(ESP8266) || defined(ESP32)\
|
||||
|| defined(PLATFORM_ID)\
|
||||
|| defined(ARDUINO_SAM_DUE)\
|
||||
|| defined(STM32_CORE_VERSION)\
|
||||
|| defined(__STM32F1__) || defined(__STM32F4__)\
|
||||
|| (defined(CORE_TEENSY) && defined(__arm__))
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) || \
|
||||
(defined(__AVR__) && defined(SPDR) && defined(SPSR) && defined(SPIF)) || \
|
||||
(defined(__AVR__) && defined(SPI0) && defined(SPI_RXCIF_bm)) || \
|
||||
defined(ESP8266) || defined(ESP32) || defined(PLATFORM_ID) || \
|
||||
defined(ARDUINO_SAM_DUE) || defined(STM32_CORE_VERSION) || \
|
||||
defined(__STM32F1__) || defined(__STM32F4__) || \
|
||||
(defined(CORE_TEENSY) && defined(__arm__))
|
||||
#define SD_HAS_CUSTOM_SPI 1
|
||||
#else // SD_HAS_CUSTOM_SPI
|
||||
// Use standard SPI library.
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
*/
|
||||
class SdSpiArduinoDriver {
|
||||
public:
|
||||
/** Constructor. */
|
||||
SdSpiArduinoDriver() = default;
|
||||
/** Activate SPI hardware. */
|
||||
void activate();
|
||||
/** Initialize the SPI bus.
|
||||
|
|
@ -55,12 +57,12 @@ class SdSpiArduinoDriver {
|
|||
*/
|
||||
uint8_t receive();
|
||||
/** Receive multiple bytes.
|
||||
*
|
||||
* \param[out] buf Buffer to receive the data.
|
||||
* \param[in] count Number of bytes to receive.
|
||||
*
|
||||
* \return Zero for no error or nonzero error code.
|
||||
*/
|
||||
*
|
||||
* \param[out] buf Buffer to receive the data.
|
||||
* \param[in] count Number of bytes to receive.
|
||||
*
|
||||
* \return Zero for no error or nonzero error code.
|
||||
*/
|
||||
uint8_t receive(uint8_t* buf, size_t count);
|
||||
/** Send a byte.
|
||||
*
|
||||
|
|
@ -82,7 +84,7 @@ class SdSpiArduinoDriver {
|
|||
}
|
||||
|
||||
private:
|
||||
SPIClass *m_spi;
|
||||
SPIClass* m_spi = nullptr;
|
||||
SPISettings m_spiSettings;
|
||||
};
|
||||
/** Typedef for use of SdSpiArduinoDriver */
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@
|
|||
#include "SdSpiDriver.h"
|
||||
#if defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_ARCH_APOLLO3)
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::activate() {
|
||||
m_spi->beginTransaction(m_spiSettings);
|
||||
}
|
||||
void SdSpiArduinoDriver::activate() { m_spi->beginTransaction(m_spiSettings); }
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
|
||||
if (spiConfig.spiPort) {
|
||||
|
|
@ -38,17 +36,11 @@ void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
|
|||
m_spi->begin();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::deactivate() {
|
||||
m_spi->endTransaction();
|
||||
}
|
||||
void SdSpiArduinoDriver::deactivate() { m_spi->endTransaction(); }
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::end() {
|
||||
m_spi->end();
|
||||
}
|
||||
void SdSpiArduinoDriver::end() { m_spi->end(); }
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdSpiArduinoDriver::receive() {
|
||||
return m_spi->transfer(0XFF);
|
||||
}
|
||||
uint8_t SdSpiArduinoDriver::receive() { return m_spi->transfer(0XFF); }
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
||||
memset(buf, 0XFF, count);
|
||||
|
|
@ -56,24 +48,22 @@ uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
|||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::send(uint8_t data) {
|
||||
m_spi->transfer(data);
|
||||
}
|
||||
void SdSpiArduinoDriver::send(uint8_t data) { m_spi->transfer(data); }
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
|
||||
// If not a multiple of four. Command with CRC used six byte send.
|
||||
while (count%4) {
|
||||
while (count % 4) {
|
||||
send(*buf++);
|
||||
count--;
|
||||
}
|
||||
// Convert byte array to 4 byte array.
|
||||
uint32_t myArray[count/4]; // NOLINT
|
||||
for (int x = 0; x < count/4; x++) {
|
||||
uint32_t myArray[count / 4]; // NOLINT
|
||||
for (int x = 0; x < count / 4; x++) {
|
||||
myArray[x] = ((uint32_t)buf[(x * 4) + 3] << (8 * 3)) |
|
||||
((uint32_t)buf[(x * 4) + 2] << (8 * 2)) |
|
||||
((uint32_t)buf[(x * 4) + 1] << (8 * 1)) |
|
||||
((uint32_t)buf[(x * 4) + 0] << (8 * 0));
|
||||
}
|
||||
m_spi->transfer(reinterpret_cast<void *>(myArray), count);
|
||||
m_spi->transfer(reinterpret_cast<void*>(myArray), count);
|
||||
}
|
||||
#endif // defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_ARCH_APOLLO3)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef SdSpiAvr_h
|
||||
#define SdSpiAvr_h
|
||||
// Use of in-line for AVR to save flash.
|
||||
#define nop asm volatile ("nop\n\t")
|
||||
#define nop asm volatile("nop\n\t")
|
||||
//------------------------------------------------------------------------------
|
||||
inline void SdSpiArduinoDriver::activate() {
|
||||
SPI.beginTransaction(m_spiSettings);
|
||||
|
|
@ -36,17 +36,11 @@ inline void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
|
|||
SPI.begin();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline void SdSpiArduinoDriver::deactivate() {
|
||||
SPI.endTransaction();
|
||||
}
|
||||
inline void SdSpiArduinoDriver::deactivate() { SPI.endTransaction(); }
|
||||
//------------------------------------------------------------------------------
|
||||
inline void SdSpiArduinoDriver::end() {
|
||||
SPI.end();
|
||||
}
|
||||
inline void SdSpiArduinoDriver::end() { SPI.end(); }
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint8_t SdSpiArduinoDriver::receive() {
|
||||
return SPI.transfer(0XFF);
|
||||
}
|
||||
inline uint8_t SdSpiArduinoDriver::receive() { return SPI.transfer(0XFF); }
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
||||
if (count == 0) {
|
||||
|
|
@ -58,12 +52,14 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
|||
// nops optimize loop for 16MHz CPU 8 MHz SPI
|
||||
nop;
|
||||
nop;
|
||||
while (!(SPSR & _BV(SPIF))) {}
|
||||
while (!(SPSR & _BV(SPIF))) {
|
||||
}
|
||||
uint8_t in = SPDR;
|
||||
SPDR = 0XFF;
|
||||
*buf++ = in;
|
||||
}
|
||||
while (!(SPSR & _BV(SPIF))) {}
|
||||
while (!(SPSR & _BV(SPIF))) {
|
||||
}
|
||||
*buf = SPDR;
|
||||
#elif defined(SPI_RXCIF_bm)
|
||||
SPI0.DATA = 0XFF;
|
||||
|
|
@ -73,12 +69,14 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
|||
nop;
|
||||
nop;
|
||||
nop;
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {}
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {
|
||||
}
|
||||
uint8_t in = SPI0.DATA;
|
||||
SPI0.DATA = 0XFF;
|
||||
*buf++ = in;
|
||||
}
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {}
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {
|
||||
}
|
||||
*buf = SPI0.DATA;
|
||||
#else // SPSR
|
||||
#error Unsupported AVR CPU - edit SdFatConfig.h to use standard SPI library.
|
||||
|
|
@ -86,11 +84,9 @@ inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
|||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline void SdSpiArduinoDriver::send(uint8_t data) {
|
||||
SPI.transfer(data);
|
||||
}
|
||||
inline void SdSpiArduinoDriver::send(uint8_t data) { SPI.transfer(data); }
|
||||
//------------------------------------------------------------------------------
|
||||
inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
|
||||
inline void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -101,10 +97,12 @@ inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
|
|||
// nops optimize loop for 16MHz CPU 8 MHz SPI
|
||||
nop;
|
||||
nop;
|
||||
while (!(SPSR & (1 << SPIF))) {}
|
||||
while (!(SPSR & (1 << SPIF))) {
|
||||
}
|
||||
SPDR = b;
|
||||
}
|
||||
while (!(SPSR & (1 << SPIF))) {}
|
||||
while (!(SPSR & (1 << SPIF))) {
|
||||
}
|
||||
#elif defined(SPI_RXCIF_bm)
|
||||
SPI0.DATA = *buf++;
|
||||
while (--count) {
|
||||
|
|
@ -113,10 +111,12 @@ inline void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
|
|||
nop;
|
||||
nop;
|
||||
nop;
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {}
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {
|
||||
}
|
||||
SPI0.DATA = b;
|
||||
}
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {}
|
||||
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm)) {
|
||||
}
|
||||
#else // SPSR
|
||||
#error Unsupported AVR CPU - edit SdFatConfig.h to use standard SPI library.
|
||||
#endif // SPSR
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@
|
|||
*/
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "../common/SysCall.h"
|
||||
#define nop asm volatile ("nop\n\t")
|
||||
#define nop asm volatile("nop\n\t")
|
||||
#ifndef HIGH
|
||||
#define HIGH 1
|
||||
#endif // HIGH
|
||||
|
|
@ -79,10 +80,10 @@ inline void unoPinMode(uint8_t pin, uint8_t mode) {
|
|||
sei();
|
||||
}
|
||||
|
||||
#define UNO_SS 10
|
||||
#define UNO_SS 10
|
||||
#define UNO_MOSI 11
|
||||
#define UNO_MISO 12
|
||||
#define UNO_SCK 13
|
||||
#define UNO_SCK 13
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdSpiDriverBareUno
|
||||
|
|
@ -116,16 +117,14 @@ class SdSpiDriverBareUno {
|
|||
*
|
||||
* \return The byte.
|
||||
*/
|
||||
uint8_t receive() {
|
||||
return transfer(0XFF);
|
||||
}
|
||||
uint8_t receive() { return transfer(0XFF); }
|
||||
/** Receive multiple bytes.
|
||||
*
|
||||
* \param[out] buf Buffer to receive the data.
|
||||
* \param[in] count Number of bytes to receive.
|
||||
*
|
||||
* \return Zero for no error or nonzero error code.
|
||||
*/
|
||||
*
|
||||
* \param[out] buf Buffer to receive the data.
|
||||
* \param[in] count Number of bytes to receive.
|
||||
*
|
||||
* \return Zero for no error or nonzero error code.
|
||||
*/
|
||||
uint8_t receive(uint8_t* buf, size_t count) {
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
|
|
@ -133,7 +132,8 @@ class SdSpiDriverBareUno {
|
|||
uint8_t* pr = buf;
|
||||
SPDR = 0XFF;
|
||||
while (--count > 0) {
|
||||
while (!(SPSR & _BV(SPIF))) {}
|
||||
while (!(SPSR & _BV(SPIF))) {
|
||||
}
|
||||
uint8_t in = SPDR;
|
||||
SPDR = 0XFF;
|
||||
*pr++ = in;
|
||||
|
|
@ -141,7 +141,8 @@ class SdSpiDriverBareUno {
|
|||
nop;
|
||||
nop;
|
||||
}
|
||||
while (!(SPSR & _BV(SPIF))) {}
|
||||
while (!(SPSR & _BV(SPIF))) {
|
||||
}
|
||||
*pr = SPDR;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -149,9 +150,7 @@ class SdSpiDriverBareUno {
|
|||
*
|
||||
* \param[in] data Byte to send
|
||||
*/
|
||||
void send(uint8_t data) {
|
||||
transfer(data);
|
||||
}
|
||||
void send(uint8_t data) { transfer(data); }
|
||||
/** Send multiple bytes.
|
||||
*
|
||||
* \param[in] buf Buffer for data to be sent.
|
||||
|
|
@ -164,18 +163,18 @@ class SdSpiDriverBareUno {
|
|||
SPDR = *buf++;
|
||||
while (--count > 0) {
|
||||
uint8_t b = *buf++;
|
||||
while (!(SPSR & (1 << SPIF))) {}
|
||||
while (!(SPSR & (1 << SPIF))) {
|
||||
}
|
||||
SPDR = b;
|
||||
// nops to optimize loop for 16MHz CPU 8 MHz SPI
|
||||
nop;
|
||||
nop;
|
||||
}
|
||||
while (!(SPSR & (1 << SPIF))) {}
|
||||
while (!(SPSR & (1 << SPIF))) {
|
||||
}
|
||||
}
|
||||
/** Set CS low. */
|
||||
void select() {
|
||||
unoDigitalWrite(m_csPin, LOW);
|
||||
}
|
||||
void select() { unoDigitalWrite(m_csPin, LOW); }
|
||||
/** Save high speed SPISettings after SD initialization.
|
||||
*
|
||||
* \param[in] spiConfig SPI options.
|
||||
|
|
@ -186,13 +185,12 @@ class SdSpiDriverBareUno {
|
|||
}
|
||||
static uint8_t transfer(uint8_t data) {
|
||||
SPDR = data;
|
||||
while (!(SPSR & _BV(SPIF))) {} // wait
|
||||
while (!(SPSR & _BV(SPIF))) {
|
||||
} // wait
|
||||
return SPDR;
|
||||
}
|
||||
/** Set CS high. */
|
||||
void unselect() {
|
||||
unoDigitalWrite(m_csPin, HIGH);
|
||||
}
|
||||
void unselect() { unoDigitalWrite(m_csPin, HIGH); }
|
||||
|
||||
private:
|
||||
SdCsPin_t m_csPin;
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ class SdSpiBaseClass {
|
|||
*/
|
||||
virtual uint8_t receive() = 0;
|
||||
/** Receive multiple bytes.
|
||||
*
|
||||
* \param[out] buf Buffer to receive the data.
|
||||
* \param[in] count Number of bytes to receive.
|
||||
*
|
||||
* \return Zero for no error or nonzero error code.
|
||||
*/
|
||||
*
|
||||
* \param[out] buf Buffer to receive the data.
|
||||
* \param[in] count Number of bytes to receive.
|
||||
*
|
||||
* \return Zero for no error or nonzero error code.
|
||||
*/
|
||||
virtual uint8_t receive(uint8_t* buf, size_t count) = 0;
|
||||
/** Send a byte.
|
||||
*
|
||||
|
|
@ -73,6 +73,6 @@ class SdSpiBaseClass {
|
|||
*
|
||||
* \param[in] maxSck Maximum SCK frequency.
|
||||
*/
|
||||
virtual void setSckSpeed(uint32_t maxSck) {(void)maxSck;}
|
||||
virtual void setSckSpeed(uint32_t maxSck) { (void)maxSck; }
|
||||
};
|
||||
#endif // SdSpiBaseClass_h
|
||||
|
|
|
|||
|
|
@ -26,22 +26,14 @@
|
|||
#if ENABLE_ARDUINO_FEATURES
|
||||
#if SD_CHIP_SELECT_MODE == 0
|
||||
//------------------------------------------------------------------------------
|
||||
void sdCsInit(SdCsPin_t pin) {
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
void sdCsInit(SdCsPin_t pin) { pinMode(pin, OUTPUT); }
|
||||
//------------------------------------------------------------------------------
|
||||
void sdCsWrite(SdCsPin_t pin, bool level) {
|
||||
digitalWrite(pin, level);
|
||||
}
|
||||
void sdCsWrite(SdCsPin_t pin, bool level) { digitalWrite(pin, level); }
|
||||
#elif SD_CHIP_SELECT_MODE == 1
|
||||
//------------------------------------------------------------------------------
|
||||
__attribute__((weak))
|
||||
void sdCsInit(SdCsPin_t pin) {
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
__attribute__((weak)) void sdCsInit(SdCsPin_t pin) { pinMode(pin, OUTPUT); }
|
||||
//------------------------------------------------------------------------------
|
||||
__attribute__((weak))
|
||||
void sdCsWrite(SdCsPin_t pin, bool level) {
|
||||
__attribute__((weak)) void sdCsWrite(SdCsPin_t pin, bool level) {
|
||||
digitalWrite(pin, level);
|
||||
}
|
||||
#endif // SD_CHIP_SELECT_MODE == 0
|
||||
|
|
|
|||
|
|
@ -52,19 +52,24 @@ const uint8_t DEDICATED_SPI = 1;
|
|||
* \param[in] opt option field of SdSpiConfig.
|
||||
* \return true for dedicated SPI.
|
||||
*/
|
||||
inline bool spiOptionDedicated(uint8_t opt) {return opt & DEDICATED_SPI;}
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
inline bool spiOptionDedicated(uint8_t opt) { return opt & DEDICATED_SPI; }
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
/**
|
||||
* \param[in] opt option field of SdSpiConfig.
|
||||
* \return true for dedicated SPI.
|
||||
*/
|
||||
inline bool spiOptionDedicated(uint8_t opt) {(void)opt; return false;}
|
||||
inline bool spiOptionDedicated(uint8_t opt) {
|
||||
(void)opt;
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
/** The user will call begin. Useful for custom SPI configurations. */
|
||||
const uint8_t USER_SPI_BEGIN = 2;
|
||||
//------------------------------------------------------------------------------
|
||||
/** SPISettings for SCK frequency in Hz. */
|
||||
#define SD_SCK_HZ(maxSpeed) (maxSpeed)
|
||||
/** SPISettings for SCK frequency in MHz. */
|
||||
#define SD_SCK_MHZ(maxMhz) (1000000UL*(maxMhz))
|
||||
#define SD_SCK_MHZ(maxMhz) (1000000UL * (maxMhz))
|
||||
// SPI divisor constants - obsolete.
|
||||
/** Set SCK to max rate. */
|
||||
#define SPI_FULL_SPEED SD_SCK_MHZ(50)
|
||||
|
|
@ -93,8 +98,8 @@ typedef SdSpiSoftDriver SpiPort_t;
|
|||
class SdSpiBaseClass;
|
||||
/** Port type for extrernal SPI driver. */
|
||||
typedef SdSpiBaseClass SpiPort_t;
|
||||
#else // SPI_DRIVER_SELECT
|
||||
typedef void* SpiPort_t;
|
||||
#else // SPI_DRIVER_SELECT
|
||||
typedef void* SpiPort_t;
|
||||
#endif // SPI_DRIVER_SELECT
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
|
|
@ -103,15 +108,15 @@ typedef void* SpiPort_t;
|
|||
*/
|
||||
class SdSpiConfig {
|
||||
public:
|
||||
/** SdSpiConfig constructor.
|
||||
/** SdSpiConfig constructor.
|
||||
*
|
||||
* \param[in] cs Chip select pin.
|
||||
* \param[in] opt Options.
|
||||
* \param[in] maxSpeed Maximum SCK frequency.
|
||||
* \param[in] port The SPI port to use.
|
||||
*/
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed, SpiPort_t* port) :
|
||||
csPin(cs), options(opt), maxSck(maxSpeed), spiPort(port) {}
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed, SpiPort_t* port)
|
||||
: csPin(cs), options(opt), maxSck(maxSpeed), spiPort(port) {}
|
||||
|
||||
/** SdSpiConfig constructor.
|
||||
*
|
||||
|
|
@ -119,8 +124,8 @@ class SdSpiConfig {
|
|||
* \param[in] opt Options.
|
||||
* \param[in] maxSpeed Maximum SCK frequency.
|
||||
*/
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed) :
|
||||
csPin(cs), options(opt), maxSck(maxSpeed) {}
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed)
|
||||
: csPin(cs), options(opt), maxSck(maxSpeed) {}
|
||||
/** SdSpiConfig constructor.
|
||||
*
|
||||
* \param[in] cs Chip select pin.
|
||||
|
|
|
|||
|
|
@ -42,13 +42,9 @@
|
|||
#define SPI_RX_IDX 2
|
||||
//------------------------------------------------------------------------------
|
||||
/* Disable DMA Controller. */
|
||||
static void dmac_disable() {
|
||||
DMAC->DMAC_EN &= (~DMAC_EN_ENABLE);
|
||||
}
|
||||
static void dmac_disable() { DMAC->DMAC_EN &= (~DMAC_EN_ENABLE); }
|
||||
/* Enable DMA Controller. */
|
||||
static void dmac_enable() {
|
||||
DMAC->DMAC_EN = DMAC_EN_ENABLE;
|
||||
}
|
||||
static void dmac_enable() { DMAC->DMAC_EN = DMAC_EN_ENABLE; }
|
||||
/* Disable DMA Channel. */
|
||||
static void dmac_channel_disable(uint32_t ul_num) {
|
||||
DMAC->DMAC_CHDR = DMAC_CHDR_DIS0 << ul_num;
|
||||
|
|
@ -67,14 +63,15 @@ static void spiDmaRX(uint8_t* dst, uint16_t count) {
|
|||
dmac_channel_disable(SPI_DMAC_RX_CH);
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
|
||||
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
|
||||
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA =
|
||||
count | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB =
|
||||
DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
|
||||
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
|
||||
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG =
|
||||
DMAC_CFG_SRC_PER(SPI_RX_IDX) | DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD |
|
||||
DMAC_CFG_FIFOCFG_ASAP_CFG;
|
||||
dmac_channel_enable(SPI_DMAC_RX_CH);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -89,16 +86,17 @@ static void spiDmaTX(const uint8_t* src, uint16_t count) {
|
|||
dmac_channel_disable(SPI_DMAC_TX_CH);
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
|
||||
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA =
|
||||
count | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
|
||||
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
|
||||
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB =
|
||||
DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
|
||||
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
|
||||
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
|
||||
DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
|
||||
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG =
|
||||
DMAC_CFG_DST_PER(SPI_TX_IDX) | DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD |
|
||||
DMAC_CFG_FIFOCFG_ALAP_CFG;
|
||||
|
||||
dmac_channel_enable(SPI_DMAC_TX_CH);
|
||||
}
|
||||
|
|
@ -141,39 +139,36 @@ void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
|
|||
#endif // USE_SAM3X_DMAC
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::deactivate() {
|
||||
SPI.endTransaction();
|
||||
}
|
||||
void SdSpiArduinoDriver::deactivate() { SPI.endTransaction(); }
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::end() {
|
||||
SPI.end();
|
||||
}
|
||||
void SdSpiArduinoDriver::end() { SPI.end(); }
|
||||
//------------------------------------------------------------------------------
|
||||
static inline uint8_t spiTransfer(uint8_t b) {
|
||||
Spi* pSpi = SPI0;
|
||||
|
||||
pSpi->SPI_TDR = b;
|
||||
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
|
||||
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {
|
||||
}
|
||||
b = pSpi->SPI_RDR;
|
||||
return b;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdSpiArduinoDriver::receive() {
|
||||
return spiTransfer(0XFF);
|
||||
}
|
||||
uint8_t SdSpiArduinoDriver::receive() { return spiTransfer(0XFF); }
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
||||
Spi* pSpi = SPI0;
|
||||
int rtn = 0;
|
||||
#if USE_SAM3X_DMAC
|
||||
// clear overrun error
|
||||
while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {pSpi->SPI_RDR;}
|
||||
while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {
|
||||
pSpi->SPI_RDR;
|
||||
}
|
||||
spiDmaRX(buf, count);
|
||||
spiDmaTX(0, count);
|
||||
|
||||
uint32_t m = millis();
|
||||
while (!dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
|
||||
if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
|
||||
if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
|
||||
dmac_channel_disable(SPI_DMAC_RX_CH);
|
||||
dmac_channel_disable(SPI_DMAC_TX_CH);
|
||||
rtn = 2;
|
||||
|
|
@ -183,34 +178,39 @@ uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
|||
if (pSpi->SPI_SR & SPI_SR_OVRES) {
|
||||
rtn |= 1;
|
||||
}
|
||||
#else // USE_SAM3X_DMAC
|
||||
#else // USE_SAM3X_DMAC
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
pSpi->SPI_TDR = 0XFF;
|
||||
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
|
||||
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {
|
||||
}
|
||||
buf[i] = pSpi->SPI_RDR;
|
||||
}
|
||||
#endif // USE_SAM3X_DMAC
|
||||
return rtn;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::send(uint8_t data) {
|
||||
spiTransfer(data);
|
||||
}
|
||||
void SdSpiArduinoDriver::send(uint8_t data) { spiTransfer(data); }
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
|
||||
void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
|
||||
Spi* pSpi = SPI0;
|
||||
#if USE_SAM3X_DMAC
|
||||
spiDmaTX(buf, count);
|
||||
while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
|
||||
#else // #if USE_SAM3X_DMAC
|
||||
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
|
||||
while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {
|
||||
}
|
||||
#else // #if USE_SAM3X_DMAC
|
||||
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {
|
||||
}
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
pSpi->SPI_TDR = buf[i];
|
||||
while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
|
||||
while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {
|
||||
}
|
||||
}
|
||||
#endif // #if USE_SAM3X_DMAC
|
||||
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
|
||||
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {
|
||||
}
|
||||
// leave RDR empty
|
||||
while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {pSpi->SPI_RDR;}
|
||||
while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {
|
||||
pSpi->SPI_RDR;
|
||||
}
|
||||
}
|
||||
#endif // defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_SAM_DUE)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue