diff --git a/final_project/main.c b/final_project/main.c deleted file mode 100755 index fb3e1e6..0000000 --- a/final_project/main.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -// Set up GPIO here -void pin_setup() { - -} - - -int main() { - pin_setup() - - while (1) { - - } - -} diff --git a/final_project/sd_reader/ChangeLog b/final_project/sd_reader/ChangeLog new file mode 100644 index 0000000..848c192 --- /dev/null +++ b/final_project/sd_reader/ChangeLog @@ -0,0 +1,124 @@ + +2012-06-12 sd-reader + * fix capacity readout from csd register depending on format version + * fix gcc strict-aliasing warnings (also somewhat enlarges code size) + +2011-04-23 sd-reader + * fix FAT access for cluster numbers beyond 2^15 (for FAT16) and 2^30 (for FAT32) (thanks to Darwin Engwer for testing) + * correctly return disk-full condition from fat_write_file() on certain conditions + * use byteorder memory access functions for fat_fs_get_free() + * be more specific on the return value of fat_write_file() + +2011-02-05 sd-reader + * implement renaming a file or directory + * rewrite byteorder handling to fix unaligned memory accesses on 32-bit and probably 16-bit architectures + * make fat_create_file() not return failure if the file already exists + * make the "cat" output respect the count of bytes actually read + * document how to use fat_seek_file() for retrieving the file position + +2010-10-10 sd-reader + * Fix equal file names when reading two successive 8.3 directory entries. + * Fix calculation of cluster positions beyond 4GB (32 bit integer overflow). + * Fix endless looping of directory listing (occured with valid entry at end of last cluster). + +2010-01-10 sd-reader + * Make LFN support configurable. + * Ignore LFN directory entries without 8.3 name. + * Ignore LFN directory entries which do not match the 8.3 name's checksum. + * Implement delayed directory entry updates (disabled by default) (thanks to Adam Mayer). + * Speedup search for free cluster. + * Fix memory leak when using the "init" command (thanks to Tibor Vilhan). + * Fix ATmega328P-specific pin mappings. + * Add some of the picoPower MCU variants. + +2009-03-30 sd-reader + * Make 8.3 basename and/or extension lowercase when told by Windows NT and later. + * Add ATmega328 pin configuration. + * Fix MMC/SD/SDHC distinction. + * Fix raw block read/write buffering (thanks to Kurt Sterckx). + * Fix fat size calculation for FAT16 when configured with FAT32. + * Fix compilation for read-only configurations. + * Fix card lock detection. + * Make it easier to link with a C++ application (thanks to Jérôme Despatis). + +2008-11-21 sd-reader + * Support for SDHC cards (disabled by default). + * Support for FAT32 (disabled by default). + +2008-06-08 sd-reader + * New "init" command to allow reinitialization of memory card. + * Fix searching through multi-cluster directories. + * Fix reading directory entries spanning a cluster border (backport from mega-eth). + * Do not abort the whole lfn entry when the file name is too long, just drop single characters (backport from mega-eth). + * Change fat16_get_dir_entry_of_path() to ignore a slash at the end (backport from mega-eth). + * Make listing a directory's content much faster (backport from mega-eth). + * Shrink code size by centralizing cluster offset calculation (backport from mega-eth). + * Some other small fixes and optimizations. + +2007-12-13 sd-reader + * Dual-license the major implementation modules under GPL and LGPL. + +2007-06-03 sd-reader + * Fix reading beyond cached block (by Benjamin Meier). + * Implement support for reading and writing file modification dates/times. + (Thanks to Torsten Seeboth for testing.) + +2007-03-01 sd-reader + * Avoid LFN directory entries for the "." and ".." directory references. + This prevented Windows from deleting directories. + * Handle special case where the 8.3 filename begins with 0xe5. + * Fix return value of fat16_delete_file() when deleting empty files. + * Fix fat16_clear_cluster() which was zeroing only 16 of every 32 bytes. + +2007-01-20 sd-reader + * Fix directory creation. + - Correctly create "." and ".." directory entries (8.3 <-> lfn versions). + - Correctly clear cluster containing the directory entries for new directory. + +2006-11-01 sd-reader + * Implement creation and deletion of directories. + * Clear the directory entries of new directory clusters. + * Prevent linkage against printf(). + * Make the use of malloc()/free() optional. + +2006-09-01 sd-reader + * Fix shortening files. + * Fix free disk space calculation. + +2006-08-24 sd-reader + * Improve sleep handling. + * Display extended card information on boot and + when executing the "disk" shell command. + * Correctly determine FAT type by cluster count. + * Fix cluster allocation beyond card capacity. + +2006-08-16 sd-reader + * Provide FAT16 capacity and usage information. + * Implement the backspace key in the mini shell. + * Enter idle mode when waiting for uart activity. + * Make the Card Select pin MCU dependent as well. + * Add mini shell commands to documentation. + +2006-08-08 sd-reader + * Thanks go to Torsten Seeboth for his ongoing efforts + to test changes, fix regressions and give suggestions. + Many of the changes below were initiated by him. + * Much more reliable card initialization. + * Highly improved performance + - optional write buffering + - better cluster handling + - remove unneeded SPI access when reading from buffered block + - use highest spi frequency after card initialization + * Add superfloppy support. + * Better checks when opening a FAT16 filesystem. + * Provide SPI pin mappings for commonly used ATmegas. + * Fix resizing files, hangs could occur. + * Fix overflow when creating files with names longer than 31 characters. + * Fix numerous other small things. + +2006-03-19 sd-reader + * Fix speed regressions. + +2006-03-16 sd-reader + * Initial release. + diff --git a/final_project/sd_reader/Doxyfile b/final_project/sd_reader/Doxyfile new file mode 100644 index 0000000..703ef53 --- /dev/null +++ b/final_project/sd_reader/Doxyfile @@ -0,0 +1,1525 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = sd-reader + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# 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 option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = 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. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# 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 (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 0 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated 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) + +WARN_FORMAT = "$file:$line: $text " + +# 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 stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (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 + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = doc + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# 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 one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# 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. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, 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. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +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. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = DOXYGEN=1 + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need 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. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are 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 +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +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). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES 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 this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/final_project/sd_reader/FAQ b/final_project/sd_reader/FAQ new file mode 100644 index 0000000..e709a6c --- /dev/null +++ b/final_project/sd_reader/FAQ @@ -0,0 +1,124 @@ +Frequently Asked Questions for sd-reader +======================================== + +General +------- + +Q: Which cards are supported? +A: All MMC/SD/SDHC/miniSD/microSD/microSDHC should work, although not all variants have been tested. + Some very old (low capacity) cards might be broken as well. Cards with a capacity of 16 MB or + less are usually formatted with FAT12, so these are supported in raw mode only, if at all. + +Q: What data rates can I expect? +A: See the benchmark page on the homepage. + http://www.roland-riegel.de/sd-reader/benchmarks/ + +Q: Are there boards available for purchase? +A: No. + +Hardware +-------- + +Q: Where can I find the schematic? +A: Get it on the homepage. + http://www.roland-riegel.de/sd-reader/sd-reader_circuit_latest.zip + +Q: What if my card socket has no Card-Detect and/or Card-Lock switches? +A: Change sd_raw_config.h such that it looks like + + #define configure_pin_available() /* nothing */ + #define configure_pin_locked() /* nothing */ + + #define get_pin_available() 0 + #define get_pin_locked() 1 + +Q: All attempts to write to the card fail, although reading works. What's the problem? +A: Enable write support within sd_raw_config.h. And probably, your card socket has no Card-lock + detection (see question above). + +Q: The card initialization fails. What can I do? +A: Usually this is some kind of hardware problem. + * Check the physical connections. + * Keep the signal lines to the card as short as possible. + * Do not use diodes to derive the card's supply voltage. Use a 3.3V voltage regulator instead. + * Have a stable, buffered power supply and use capacitors for correct voltage regulator + operation (see the schematics linked above). + * Use extra capacitors of 50uF and 100nF as close to the card as possible. + * When using an integrated level shifter or no level shifting at all (see the next question), + try adding a pullup of 50k from the data-out line of the card to 3.3V. + * Make sure the limiting frequency of the level shifter is not exceeded. Have a look into its + datasheet! + * Check the signals with a scope. + +Q: What alternatives to resistor level shifting exist? +A: If you want to use additional devices with SPI or the resistor solution appears too ugly, there + are two possibilities. Either operate the whole circuit with a single 3.3V supply and no level + shifting at all or use a level shifting IC which interfaces the memory card to the AVR. + Depending on your requirements, adequate devices could include MAX3378E, MAX3392E, MAX3395E, + 74LVC245 and 74HCT4050 (optionally together with 74HCT125). Please check the datasheets for the + required DC/AC characteristics! + +Software +-------- + +Q: What's the software license? +A: GPLv2 or (for most parts) LGPLv2.1. Before using a file, read its license terms included at the + beginning of the file. + +Q: What's the programming language used? +A: It's C, in compliance with the ISO C99 standard. + +Q: What are these .patch-files provided? +A: Those record the source code differences between the old and new release. If you edited your + private sd-reader version, it might be easier to apply the patch files using the "patch" utility + common on Unix-like systems, rather than manually inserting the changes by hand. For Windows + users, the GnuWin32 project provides a port of "patch". + +Q: Where can I learn more about the library interface and how to use it? +A: Look into the HTML documentation provided online or within each source distribution. Also take + the provided main.c as an example application and as a starting point. + +Q: How do I adapt it to an ATmegaXYZ and my circuit in particular? +A: Add your MCU-specific pin configuration to sd_raw_config.h. Some commonly used ones are already + included. + +Q: How do I adapt it to a different MCU clock? +A: Change the MCU_FREQ variable within the Makefile. + +Q: How do I adapt it to some different MCU architecture? +A: Change sd_raw_init(), sd_raw_send_byte(), sd_raw_rec_byte() within sd_raw.c and the pin + definitions within sd_raw_config.h appropriately. + +Q: Can the library be used with Arduino? +A: Yes. I do not have any experience with Arduino myself, but people report that it works with some + minor modifications to the library code needed due to some different compiler settings. Please + search the web for details. + +Q: Can I use software SPI? +A: Yes, but the code is not prepared for it. + +Q: My application crashes somewhere in the lib. Is there some bug hidden? +A: There might be a bug. Much more likely, however, is that you experience memory problems, + especially heap/stack collisions. The crashes can appear everywhere, but typically this is not + the place where the real problem is. Try to minimize the size of structures and other memory + blocks your application uses. Sum up the amount of memory your application allocates with global + and local variables and the memory you allocate dynamically with malloc(). The avr-nm utility + also helps a lot here. When called with the "--print-size --size-sort" parameters, it lists all + symbols and their code/memory size within the given file. See the avr-libc FAQ and the nm manual + for further information. + http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_ramoverlap + http://sourceware.org/binutils/docs/binutils/nm.html + +Q: Opening the FAT filesystem fails. What can I do? +A: Make sure there is a FAT16 or FAT32 filesystem on the card. This usually isn't possible for old + cards with 16 MB or less. For larger ones, format the cards using the OS utilities, like the + Windows Explorer, the Unix/Linux mkdosfs command or special SD card format tools. + http://panasonic.jp/support/global/cs/sd/download/sd_formatter.html + http://www.sdcard.org/consumers/formatter/ + +Q: Writing to the card returns no failure, but when checking the file's content the data is not + there. What happens? +A: For performance reasons, writing to the card is always buffered. Before pulling the card out of + its socket (or issuing a reset of the MCU), make sure sd_raw_sync() gets called such that all + buffered data is written out to permanent card storage. + diff --git a/final_project/sd_reader/Makefile b/final_project/sd_reader/Makefile new file mode 100644 index 0000000..768bb62 --- /dev/null +++ b/final_project/sd_reader/Makefile @@ -0,0 +1,52 @@ + +NAME := sd-reader +HEX := $(NAME).hex +OUT := $(NAME).out +MAP := $(NAME).map +SOURCES := $(wildcard *.c) +HEADERS := $(wildcard *.h) +OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) + +MCU := atmega168 +MCU_AVRDUDE := m168 +MCU_FREQ := 16000000UL + +CC := avr-gcc +OBJCOPY := avr-objcopy +SIZE := avr-size -A +DOXYGEN := doxygen + +CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -g -Os -DF_CPU=$(MCU_FREQ) + +all: $(HEX) + +clean: + rm -f $(HEX) $(OUT) $(MAP) $(OBJECTS) + rm -rf doc/html + +flash: $(HEX) + avrdude -y -c avr910 -p $(MCU_AVRDUDE) -U flash:w:$(HEX) + +$(HEX): $(OUT) + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +$(OUT): $(OBJECTS) + $(CC) $(CFLAGS) -o $@ -Wl,-Map,$(MAP) $^ + @echo + @$(SIZE) $@ + @echo + +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +%.pp: %.c + $(CC) $(CFLAGS) -E -o $@ $< + +%.ppo: %.c + $(CC) $(CFLAGS) -E $< + +doc: $(HEADERS) $(SOURCES) Doxyfile + $(DOXYGEN) Doxyfile + +.PHONY: all clean flash doc + diff --git a/final_project/sd_reader/byteordering.c b/final_project/sd_reader/byteordering.c new file mode 100644 index 0000000..d1c67cd --- /dev/null +++ b/final_project/sd_reader/byteordering.c @@ -0,0 +1,110 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "byteordering.h" + +/** + * \addtogroup byteordering + * + * Architecture-dependent handling of byte-ordering. + * + * @{ + */ +/** + * \file + * Byte-order handling implementation (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +#if DOXYGEN || SWAP_NEEDED + +/** + * \internal + * Swaps the bytes of a 16-bit integer. + * + * \param[in] i A 16-bit integer which to swap. + * \returns The swapped 16-bit integer. + */ +uint16_t swap16(uint16_t i) +{ + return SWAP16(i); +} + +/** + * \internal + * Swaps the bytes of a 32-bit integer. + * + * \param[in] i A 32-bit integer which to swap. + * \returns The swapped 32-bit integer. + */ +uint32_t swap32(uint32_t i) +{ + return SWAP32(i); +} + +#endif + +/** + * Reads a 16-bit integer from memory in little-endian byte order. + * + * \param[in] p Pointer from where to read the integer. + * \returns The 16-bit integer read from memory. + */ +uint16_t read16(const uint8_t* p) +{ + return (((uint16_t) p[1]) << 8) | + (((uint16_t) p[0]) << 0); +} + +/** + * Reads a 32-bit integer from memory in little-endian byte order. + * + * \param[in] p Pointer from where to read the integer. + * \returns The 32-bit integer read from memory. + */ +uint32_t read32(const uint8_t* p) +{ + return (((uint32_t) p[3]) << 24) | + (((uint32_t) p[2]) << 16) | + (((uint32_t) p[1]) << 8) | + (((uint32_t) p[0]) << 0); +} + +/** + * Writes a 16-bit integer into memory in little-endian byte order. + * + * \param[in] p Pointer where to write the integer to. + * \param[in] i The 16-bit integer to write. + */ +void write16(uint8_t* p, uint16_t i) +{ + p[1] = (uint8_t) ((i & 0xff00) >> 8); + p[0] = (uint8_t) ((i & 0x00ff) >> 0); +} + +/** + * Writes a 32-bit integer into memory in little-endian byte order. + * + * \param[in] p Pointer where to write the integer to. + * \param[in] i The 32-bit integer to write. + */ +void write32(uint8_t* p, uint32_t i) +{ + p[3] = (uint8_t) ((i & 0xff000000) >> 24); + p[2] = (uint8_t) ((i & 0x00ff0000) >> 16); + p[1] = (uint8_t) ((i & 0x0000ff00) >> 8); + p[0] = (uint8_t) ((i & 0x000000ff) >> 0); +} + +/** + * @} + */ + diff --git a/final_project/sd_reader/byteordering.h b/final_project/sd_reader/byteordering.h new file mode 100644 index 0000000..12fa571 --- /dev/null +++ b/final_project/sd_reader/byteordering.h @@ -0,0 +1,188 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef BYTEORDERING_H +#define BYTEORDERING_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup byteordering + * + * @{ + */ +/** + * \file + * Byte-order handling header (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +#define SWAP16(val) ((((uint16_t) (val)) << 8) | \ + (((uint16_t) (val)) >> 8) \ + ) +#define SWAP32(val) (((((uint32_t) (val)) & 0x000000ff) << 24) | \ + ((((uint32_t) (val)) & 0x0000ff00) << 8) | \ + ((((uint32_t) (val)) & 0x00ff0000) >> 8) | \ + ((((uint32_t) (val)) & 0xff000000) >> 24) \ + ) + +#if LITTLE_ENDIAN || __AVR__ +#define SWAP_NEEDED 0 +#elif BIG_ENDIAN +#define SWAP_NEEDED 1 +#else +#error "Endianess undefined! Please define LITTLE_ENDIAN=1 or BIG_ENDIAN=1." +#endif + +/** + * \def HTOL16(val) + * + * Converts a 16-bit integer from host byte order to little-endian byte order. + * + * Use this macro for compile time constants only. For variable values + * use the function htol16() instead. This saves code size. + * + * \param[in] val A 16-bit integer in host byte order. + * \returns The given 16-bit integer converted to little-endian byte order. + */ +/** + * \def HTOL32(val) + * + * Converts a 32-bit integer from host byte order to little-endian byte order. + * + * Use this macro for compile time constants only. For variable values + * use the function htol32() instead. This saves code size. + * + * \param[in] val A 32-bit integer in host byte order. + * \returns The given 32-bit integer converted to little-endian byte order. + */ +/** + * \def LTOH16(val) + * + * Converts a 16-bit integer from little-endian byte order to host byte order. + * + * Use this macro for compile time constants only. For variable values + * use the function ltoh16() instead. This saves code size. + * + * \param[in] val A 16-bit integer in little-endian byte order. + * \returns The given 16-bit integer converted to host byte order. + */ +/** + * \def LTOH32(val) + * + * Converts a 32-bit integer from little-endian byte order to host byte order. + * + * Use this macro for compile time constants only. For variable values + * use the function ltoh32() instead. This saves code size. + * + * \param[in] val A 32-bit integer in little-endian byte order. + * \returns The given 32-bit integer converted to host byte order. + */ + +#if SWAP_NEEDED +#define HTOL16(val) SWAP16(val) +#define HTOL32(val) SWAP32(val) +#define LTOH16(val) SWAP16(val) +#define LTOH32(val) SWAP32(val) +#else +#define HTOL16(val) (val) +#define HTOL32(val) (val) +#define LTOH16(val) (val) +#define LTOH32(val) (val) +#endif + +#if DOXYGEN + +/** + * Converts a 16-bit integer from host byte order to little-endian byte order. + * + * Use this function on variable values instead of the + * macro HTOL16(). This saves code size. + * + * \param[in] h A 16-bit integer in host byte order. + * \returns The given 16-bit integer converted to little-endian byte order. + */ +uint16_t htol16(uint16_t h); + +/** + * Converts a 32-bit integer from host byte order to little-endian byte order. + * + * Use this function on variable values instead of the + * macro HTOL32(). This saves code size. + * + * \param[in] h A 32-bit integer in host byte order. + * \returns The given 32-bit integer converted to little-endian byte order. + */ +uint32_t htol32(uint32_t h); + +/** + * Converts a 16-bit integer from little-endian byte order to host byte order. + * + * Use this function on variable values instead of the + * macro LTOH16(). This saves code size. + * + * \param[in] l A 16-bit integer in little-endian byte order. + * \returns The given 16-bit integer converted to host byte order. + */ +uint16_t ltoh16(uint16_t l); + +/** + * Converts a 32-bit integer from little-endian byte order to host byte order. + * + * Use this function on variable values instead of the + * macro LTOH32(). This saves code size. + * + * \param[in] l A 32-bit integer in little-endian byte order. + * \returns The given 32-bit integer converted to host byte order. + */ +uint32_t ltoh32(uint32_t l); + +#elif SWAP_NEEDED + +#define htol16(h) swap16(h) +#define htol32(h) swap32(h) +#define ltoh16(l) swap16(l) +#define ltoh32(l) swap32(l) + +#else + +#define htol16(h) (h) +#define htol32(h) (h) +#define ltoh16(l) (l) +#define ltoh32(l) (l) + +#endif + +uint16_t read16(const uint8_t* p); +uint32_t read32(const uint8_t* p); +void write16(uint8_t* p, uint16_t i); +void write32(uint8_t* p, uint32_t i); + +/** + * @} + */ + +#if SWAP_NEEDED +uint16_t swap16(uint16_t i); +uint32_t swap32(uint32_t i); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/byteordering.o b/final_project/sd_reader/byteordering.o new file mode 100644 index 0000000..c28ef63 Binary files /dev/null and b/final_project/sd_reader/byteordering.o differ diff --git a/final_project/sd_reader/doc/html/annotated.html b/final_project/sd_reader/doc/html/annotated.html new file mode 100644 index 0000000..a206933 --- /dev/null +++ b/final_project/sd_reader/doc/html/annotated.html @@ -0,0 +1,74 @@ + + + + + +sd-reader: Data Structures + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+
+
Data Structures
+
+
+
Here are the data structures with brief descriptions:
+ + + +
fat_dir_entry_structDescribes a directory entry
partition_structDescribes a partition
sd_raw_infoThis struct is used by sd_raw_get_info() to return manufacturing and status information of the card
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/bc_s.png b/final_project/sd_reader/doc/html/bc_s.png new file mode 100644 index 0000000..e401862 Binary files /dev/null and b/final_project/sd_reader/doc/html/bc_s.png differ diff --git a/final_project/sd_reader/doc/html/byteordering_8c.html b/final_project/sd_reader/doc/html/byteordering_8c.html new file mode 100644 index 0000000..bf7c818 --- /dev/null +++ b/final_project/sd_reader/doc/html/byteordering_8c.html @@ -0,0 +1,89 @@ + + + + + +sd-reader: byteordering.c File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
byteordering.c File Reference
+
+
+ +

Byte-order handling implementation (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + +

+Functions

uint16_t read16 (const uint8_t *p)
 Reads a 16-bit integer from memory in little-endian byte order.
uint32_t read32 (const uint8_t *p)
 Reads a 32-bit integer from memory in little-endian byte order.
void write16 (uint8_t *p, uint16_t i)
 Writes a 16-bit integer into memory in little-endian byte order.
void write32 (uint8_t *p, uint32_t i)
 Writes a 32-bit integer into memory in little-endian byte order.
+

Detailed Description

+

Byte-order handling implementation (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/byteordering_8h.html b/final_project/sd_reader/doc/html/byteordering_8h.html new file mode 100644 index 0000000..2947b21 --- /dev/null +++ b/final_project/sd_reader/doc/html/byteordering_8h.html @@ -0,0 +1,108 @@ + + + + + +sd-reader: byteordering.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
byteordering.h File Reference
+
+
+ +

Byte-order handling header (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Defines

#define HTOL16(val)
 Converts a 16-bit integer from host byte order to little-endian byte order.
#define HTOL32(val)
 Converts a 32-bit integer from host byte order to little-endian byte order.
#define LTOH16(val)
 Converts a 16-bit integer from little-endian byte order to host byte order.
#define LTOH32(val)
 Converts a 32-bit integer from little-endian byte order to host byte order.

+Functions

uint16_t htol16 (uint16_t h)
 Converts a 16-bit integer from host byte order to little-endian byte order.
uint32_t htol32 (uint32_t h)
 Converts a 32-bit integer from host byte order to little-endian byte order.
uint16_t ltoh16 (uint16_t l)
 Converts a 16-bit integer from little-endian byte order to host byte order.
uint32_t ltoh32 (uint32_t l)
 Converts a 32-bit integer from little-endian byte order to host byte order.
uint16_t read16 (const uint8_t *p)
 Reads a 16-bit integer from memory in little-endian byte order.
uint32_t read32 (const uint8_t *p)
 Reads a 32-bit integer from memory in little-endian byte order.
void write16 (uint8_t *p, uint16_t i)
 Writes a 16-bit integer into memory in little-endian byte order.
void write32 (uint8_t *p, uint32_t i)
 Writes a 32-bit integer into memory in little-endian byte order.
+

Detailed Description

+

Byte-order handling header (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/classes.html b/final_project/sd_reader/doc/html/classes.html new file mode 100644 index 0000000..1e0b536 --- /dev/null +++ b/final_project/sd_reader/doc/html/classes.html @@ -0,0 +1,80 @@ + + + + + +sd-reader: Data Structure Index + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+
+
Data Structure Index
+
+
+
F | P | S
+ + + + + +
  F  
+
  P  
+
  S  
+
fat_dir_entry_struct   partition_struct   sd_raw_info   
+
F | P | S
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/closed.png b/final_project/sd_reader/doc/html/closed.png new file mode 100644 index 0000000..b7d4bd9 Binary files /dev/null and b/final_project/sd_reader/doc/html/closed.png differ diff --git a/final_project/sd_reader/doc/html/doxygen.css b/final_project/sd_reader/doc/html/doxygen.css new file mode 100644 index 0000000..cee0d06 --- /dev/null +++ b/final_project/sd_reader/doc/html/doxygen.css @@ -0,0 +1,949 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4CFE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 2px 5px; + background-color: #FBFCFD; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/final_project/sd_reader/doc/html/doxygen.png b/final_project/sd_reader/doc/html/doxygen.png new file mode 100644 index 0000000..635ed52 Binary files /dev/null and b/final_project/sd_reader/doc/html/doxygen.png differ diff --git a/final_project/sd_reader/doc/html/fat_8c.html b/final_project/sd_reader/doc/html/fat_8c.html new file mode 100644 index 0000000..5e49587 --- /dev/null +++ b/final_project/sd_reader/doc/html/fat_8c.html @@ -0,0 +1,134 @@ + + + + + +sd-reader: fat.c File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
fat.c File Reference
+
+
+ +

FAT implementation (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

struct fat_fs_struct * fat_open (struct partition_struct *partition)
 Opens a FAT filesystem.
void fat_close (struct fat_fs_struct *fs)
 Closes a FAT filesystem.
uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct *fs, const char *path, struct fat_dir_entry_struct *dir_entry)
 Retrieves the directory entry of a path.
struct fat_file_struct * fat_open_file (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a file on a FAT filesystem.
void fat_close_file (struct fat_file_struct *fd)
 Closes a file.
intptr_t fat_read_file (struct fat_file_struct *fd, uint8_t *buffer, uintptr_t buffer_len)
 Reads data from a file.
intptr_t fat_write_file (struct fat_file_struct *fd, const uint8_t *buffer, uintptr_t buffer_len)
 Writes data to a file.
uint8_t fat_seek_file (struct fat_file_struct *fd, int32_t *offset, uint8_t whence)
 Repositions the read/write file offset.
uint8_t fat_resize_file (struct fat_file_struct *fd, uint32_t size)
 Resizes a file to have a specific size.
struct fat_dir_struct * fat_open_dir (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a directory.
void fat_close_dir (struct fat_dir_struct *dd)
 Closes a directory descriptor.
uint8_t fat_read_dir (struct fat_dir_struct *dd, struct fat_dir_entry_struct *dir_entry)
 Reads the next directory entry contained within a parent directory.
uint8_t fat_reset_dir (struct fat_dir_struct *dd)
 Resets a directory handle.
uint8_t fat_create_file (struct fat_dir_struct *parent, const char *file, struct fat_dir_entry_struct *dir_entry)
 Creates a file.
uint8_t fat_delete_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
 Deletes a file or directory.
uint8_t fat_move_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry, struct fat_dir_struct *parent_new, const char *file_new)
 Moves or renames a file.
uint8_t fat_create_dir (struct fat_dir_struct *parent, const char *dir, struct fat_dir_entry_struct *dir_entry)
 Creates a directory.
uint8_t fat_delete_dir (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
 Deletes a directory.
uint8_t fat_move_dir (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry, struct fat_dir_struct *parent_new, const char *dir_new)
 Moves or renames a directory.
void fat_get_file_modification_date (const struct fat_dir_entry_struct *dir_entry, uint16_t *year, uint8_t *month, uint8_t *day)
 Returns the modification date of a file.
void fat_get_file_modification_time (const struct fat_dir_entry_struct *dir_entry, uint8_t *hour, uint8_t *min, uint8_t *sec)
 Returns the modification time of a file.
void fat_set_file_modification_date (struct fat_dir_entry_struct *dir_entry, uint16_t year, uint8_t month, uint8_t day)
 Sets the modification time of a date.
void fat_set_file_modification_time (struct fat_dir_entry_struct *dir_entry, uint8_t hour, uint8_t min, uint8_t sec)
 Sets the modification time of a file.
offset_t fat_get_fs_size (const struct fat_fs_struct *fs)
 Returns the amount of total storage capacity of the filesystem in bytes.
offset_t fat_get_fs_free (const struct fat_fs_struct *fs)
 Returns the amount of free storage capacity on the filesystem in bytes.
+uint8_t fat_get_fs_free_32_callback (uint8_t *buffer, offset_t offset, void *p)
 Callback function used for counting free clusters in a FAT32.
+

Detailed Description

+

FAT implementation (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/fat_8h.html b/final_project/sd_reader/doc/html/fat_8h.html new file mode 100644 index 0000000..445811a --- /dev/null +++ b/final_project/sd_reader/doc/html/fat_8h.html @@ -0,0 +1,149 @@ + + + + + +sd-reader: fat.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
fat.h File Reference
+
+
+ +

FAT header (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  fat_dir_entry_struct
 Describes a directory entry. More...

+Defines

#define FAT_ATTRIB_READONLY
 The file is read-only.
#define FAT_ATTRIB_HIDDEN
 The file is hidden.
#define FAT_ATTRIB_SYSTEM
 The file is a system file.
#define FAT_ATTRIB_VOLUME
 The file is empty and has the volume label as its name.
#define FAT_ATTRIB_DIR
 The file is a directory.
#define FAT_ATTRIB_ARCHIVE
 The file has to be archived.
#define FAT_SEEK_SET
 The given offset is relative to the beginning of the file.
#define FAT_SEEK_CUR
 The given offset is relative to the current read/write position.
#define FAT_SEEK_END
 The given offset is relative to the end of the file.

+Functions

struct fat_fs_struct * fat_open (struct partition_struct *partition)
 Opens a FAT filesystem.
void fat_close (struct fat_fs_struct *fs)
 Closes a FAT filesystem.
struct fat_file_struct * fat_open_file (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a file on a FAT filesystem.
void fat_close_file (struct fat_file_struct *fd)
 Closes a file.
intptr_t fat_read_file (struct fat_file_struct *fd, uint8_t *buffer, uintptr_t buffer_len)
 Reads data from a file.
intptr_t fat_write_file (struct fat_file_struct *fd, const uint8_t *buffer, uintptr_t buffer_len)
 Writes data to a file.
uint8_t fat_seek_file (struct fat_file_struct *fd, int32_t *offset, uint8_t whence)
 Repositions the read/write file offset.
uint8_t fat_resize_file (struct fat_file_struct *fd, uint32_t size)
 Resizes a file to have a specific size.
struct fat_dir_struct * fat_open_dir (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a directory.
void fat_close_dir (struct fat_dir_struct *dd)
 Closes a directory descriptor.
uint8_t fat_read_dir (struct fat_dir_struct *dd, struct fat_dir_entry_struct *dir_entry)
 Reads the next directory entry contained within a parent directory.
uint8_t fat_reset_dir (struct fat_dir_struct *dd)
 Resets a directory handle.
uint8_t fat_create_file (struct fat_dir_struct *parent, const char *file, struct fat_dir_entry_struct *dir_entry)
 Creates a file.
uint8_t fat_delete_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
 Deletes a file or directory.
uint8_t fat_move_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry, struct fat_dir_struct *parent_new, const char *file_new)
 Moves or renames a file.
uint8_t fat_create_dir (struct fat_dir_struct *parent, const char *dir, struct fat_dir_entry_struct *dir_entry)
 Creates a directory.
void fat_get_file_modification_date (const struct fat_dir_entry_struct *dir_entry, uint16_t *year, uint8_t *month, uint8_t *day)
 Returns the modification date of a file.
void fat_get_file_modification_time (const struct fat_dir_entry_struct *dir_entry, uint8_t *hour, uint8_t *min, uint8_t *sec)
 Returns the modification time of a file.
uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct *fs, const char *path, struct fat_dir_entry_struct *dir_entry)
 Retrieves the directory entry of a path.
offset_t fat_get_fs_size (const struct fat_fs_struct *fs)
 Returns the amount of total storage capacity of the filesystem in bytes.
offset_t fat_get_fs_free (const struct fat_fs_struct *fs)
 Returns the amount of free storage capacity on the filesystem in bytes.
+

Detailed Description

+

FAT header (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/fat__config_8h.html b/final_project/sd_reader/doc/html/fat__config_8h.html new file mode 100644 index 0000000..39c7538 --- /dev/null +++ b/final_project/sd_reader/doc/html/fat__config_8h.html @@ -0,0 +1,101 @@ + + + + + +sd-reader: fat_config.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
fat_config.h File Reference
+
+
+ +

FAT configuration (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + +

+Defines

#define FAT_WRITE_SUPPORT
 Controls FAT write support.
#define FAT_LFN_SUPPORT
 Controls FAT long filename (LFN) support.
#define FAT_DATETIME_SUPPORT
 Controls FAT date and time support.
#define FAT_FAT32_SUPPORT
 Controls FAT32 support.
#define FAT_DELAY_DIRENTRY_UPDATE
 Controls updates of directory entries.
#define fat_get_datetime(year, month, day, hour, min, sec)
 Determines the function used for retrieving current date and time.
+#define FAT_FS_COUNT
 Maximum number of filesystem handles.
+#define FAT_FILE_COUNT
 Maximum number of file handles.
+#define FAT_DIR_COUNT
 Maximum number of directory handles.
+

Detailed Description

+

FAT configuration (license: GPLv2 or LGPLv2.1)

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/files.html b/final_project/sd_reader/doc/html/files.html new file mode 100644 index 0000000..d05a5a5 --- /dev/null +++ b/final_project/sd_reader/doc/html/files.html @@ -0,0 +1,83 @@ + + + + + +sd-reader: File List + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ + + + + + + + + + + + +
byteordering.cByte-order handling implementation (license: GPLv2 or LGPLv2.1)
byteordering.hByte-order handling header (license: GPLv2 or LGPLv2.1)
fat.cFAT implementation (license: GPLv2 or LGPLv2.1)
fat.hFAT header (license: GPLv2 or LGPLv2.1)
fat_config.hFAT configuration (license: GPLv2 or LGPLv2.1)
partition.cPartition table implementation (license: GPLv2 or LGPLv2.1)
partition.hPartition table header (license: GPLv2 or LGPLv2.1)
partition_config.hPartition configuration (license: GPLv2 or LGPLv2.1)
sd-reader_config.hCommon sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1)
sd_raw.cMMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1)
sd_raw.hMMC/SD/SDHC raw access header (license: GPLv2 or LGPLv2.1)
sd_raw_config.hMMC/SD support configuration (license: GPLv2 or LGPLv2.1)
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/functions.html b/final_project/sd_reader/doc/html/functions.html new file mode 100644 index 0000000..cb0cda3 --- /dev/null +++ b/final_project/sd_reader/doc/html/functions.html @@ -0,0 +1,145 @@ + + + + + +sd-reader: Data Fields + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + + +
+
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/functions_vars.html b/final_project/sd_reader/doc/html/functions_vars.html new file mode 100644 index 0000000..6faa081 --- /dev/null +++ b/final_project/sd_reader/doc/html/functions_vars.html @@ -0,0 +1,145 @@ + + + + + +sd-reader: Data Fields - Variables + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + + +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/globals.html b/final_project/sd_reader/doc/html/globals.html new file mode 100644 index 0000000..b36dc61 --- /dev/null +++ b/final_project/sd_reader/doc/html/globals.html @@ -0,0 +1,422 @@ + + + + + +sd-reader: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + + + +
+
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- d -

+ + +

- f -

+ + +

- h -

+ + +

- l -

+ + +

- p -

+ + +

- r -

+ + +

- s -

+ + +

- u -

+ + +

- w -

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/globals_defs.html b/final_project/sd_reader/doc/html/globals_defs.html new file mode 100644 index 0000000..814d6f1 --- /dev/null +++ b/final_project/sd_reader/doc/html/globals_defs.html @@ -0,0 +1,233 @@ + + + + + +sd-reader: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + + + +
+
+  + +

- f -

+ + +

- h -

+ + +

- l -

+ + +

- p -

+ + +

- s -

+ + +

- u -

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/globals_func.html b/final_project/sd_reader/doc/html/globals_func.html new file mode 100644 index 0000000..377e6bb --- /dev/null +++ b/final_project/sd_reader/doc/html/globals_func.html @@ -0,0 +1,268 @@ + + + + + +sd-reader: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + + + +
+
+  + +

- f -

+ + +

- h -

+ + +

- l -

+ + +

- p -

+ + +

- r -

+ + +

- s -

+ + +

- w -

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/globals_type.html b/final_project/sd_reader/doc/html/globals_type.html new file mode 100644 index 0000000..17e51f7 --- /dev/null +++ b/final_project/sd_reader/doc/html/globals_type.html @@ -0,0 +1,93 @@ + + + + + +sd-reader: Globals + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + + +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__byteordering.html b/final_project/sd_reader/doc/html/group__byteordering.html new file mode 100644 index 0000000..9ece1a4 --- /dev/null +++ b/final_project/sd_reader/doc/html/group__byteordering.html @@ -0,0 +1,452 @@ + + + + + +sd-reader: Byteordering + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
Byteordering
+
+
+ +

Architecture-dependent handling of byte-ordering. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Files

file  byteordering.c
 

Byte-order handling implementation (license: GPLv2 or LGPLv2.1)

+
file  byteordering.h
 

Byte-order handling header (license: GPLv2 or LGPLv2.1)

+

+Defines

#define HTOL16(val)
 Converts a 16-bit integer from host byte order to little-endian byte order.
#define HTOL32(val)
 Converts a 32-bit integer from host byte order to little-endian byte order.
#define LTOH16(val)
 Converts a 16-bit integer from little-endian byte order to host byte order.
#define LTOH32(val)
 Converts a 32-bit integer from little-endian byte order to host byte order.

+Functions

uint16_t read16 (const uint8_t *p)
 Reads a 16-bit integer from memory in little-endian byte order.
uint32_t read32 (const uint8_t *p)
 Reads a 32-bit integer from memory in little-endian byte order.
void write16 (uint8_t *p, uint16_t i)
 Writes a 16-bit integer into memory in little-endian byte order.
void write32 (uint8_t *p, uint32_t i)
 Writes a 32-bit integer into memory in little-endian byte order.
uint16_t htol16 (uint16_t h)
 Converts a 16-bit integer from host byte order to little-endian byte order.
uint32_t htol32 (uint32_t h)
 Converts a 32-bit integer from host byte order to little-endian byte order.
uint16_t ltoh16 (uint16_t l)
 Converts a 16-bit integer from little-endian byte order to host byte order.
uint32_t ltoh32 (uint32_t l)
 Converts a 32-bit integer from little-endian byte order to host byte order.
+

Detailed Description

+

Architecture-dependent handling of byte-ordering.

+

Define Documentation

+ +
+
+ + + + + + + + +
#define HTOL16( val)
+
+
+ +

Converts a 16-bit integer from host byte order to little-endian byte order.

+

Use this macro for compile time constants only. For variable values use the function htol16() instead. This saves code size.

+
Parameters:
+ + +
[in]valA 16-bit integer in host byte order.
+
+
+
Returns:
The given 16-bit integer converted to little-endian byte order.
+ +
+
+ +
+
+ + + + + + + + +
#define HTOL32( val)
+
+
+ +

Converts a 32-bit integer from host byte order to little-endian byte order.

+

Use this macro for compile time constants only. For variable values use the function htol32() instead. This saves code size.

+
Parameters:
+ + +
[in]valA 32-bit integer in host byte order.
+
+
+
Returns:
The given 32-bit integer converted to little-endian byte order.
+ +
+
+ +
+
+ + + + + + + + +
#define LTOH16( val)
+
+
+ +

Converts a 16-bit integer from little-endian byte order to host byte order.

+

Use this macro for compile time constants only. For variable values use the function ltoh16() instead. This saves code size.

+
Parameters:
+ + +
[in]valA 16-bit integer in little-endian byte order.
+
+
+
Returns:
The given 16-bit integer converted to host byte order.
+ +
+
+ +
+
+ + + + + + + + +
#define LTOH32( val)
+
+
+ +

Converts a 32-bit integer from little-endian byte order to host byte order.

+

Use this macro for compile time constants only. For variable values use the function ltoh32() instead. This saves code size.

+
Parameters:
+ + +
[in]valA 32-bit integer in little-endian byte order.
+
+
+
Returns:
The given 32-bit integer converted to host byte order.
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
uint16_t htol16 (uint16_t h)
+
+
+ +

Converts a 16-bit integer from host byte order to little-endian byte order.

+

Use this function on variable values instead of the macro HTOL16(). This saves code size.

+
Parameters:
+ + +
[in]hA 16-bit integer in host byte order.
+
+
+
Returns:
The given 16-bit integer converted to little-endian byte order.
+ +
+
+ +
+
+ + + + + + + + +
uint32_t htol32 (uint32_t h)
+
+
+ +

Converts a 32-bit integer from host byte order to little-endian byte order.

+

Use this function on variable values instead of the macro HTOL32(). This saves code size.

+
Parameters:
+ + +
[in]hA 32-bit integer in host byte order.
+
+
+
Returns:
The given 32-bit integer converted to little-endian byte order.
+ +
+
+ +
+
+ + + + + + + + +
uint16_t ltoh16 (uint16_t l)
+
+
+ +

Converts a 16-bit integer from little-endian byte order to host byte order.

+

Use this function on variable values instead of the macro LTOH16(). This saves code size.

+
Parameters:
+ + +
[in]lA 16-bit integer in little-endian byte order.
+
+
+
Returns:
The given 16-bit integer converted to host byte order.
+ +
+
+ +
+
+ + + + + + + + +
uint32_t ltoh32 (uint32_t l)
+
+
+ +

Converts a 32-bit integer from little-endian byte order to host byte order.

+

Use this function on variable values instead of the macro LTOH32(). This saves code size.

+
Parameters:
+ + +
[in]lA 32-bit integer in little-endian byte order.
+
+
+
Returns:
The given 32-bit integer converted to host byte order.
+ +
+
+ +
+
+ + + + + + + + +
uint16_t read16 (const uint8_t * p)
+
+
+ +

Reads a 16-bit integer from memory in little-endian byte order.

+
Parameters:
+ + +
[in]pPointer from where to read the integer.
+
+
+
Returns:
The 16-bit integer read from memory.
+ +
+
+ +
+
+ + + + + + + + +
uint32_t read32 (const uint8_t * p)
+
+
+ +

Reads a 32-bit integer from memory in little-endian byte order.

+
Parameters:
+ + +
[in]pPointer from where to read the integer.
+
+
+
Returns:
The 32-bit integer read from memory.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void write16 (uint8_t * p,
uint16_t i 
)
+
+
+ +

Writes a 16-bit integer into memory in little-endian byte order.

+
Parameters:
+ + + +
[in]pPointer where to write the integer to.
[in]iThe 16-bit integer to write.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void write32 (uint8_t * p,
uint32_t i 
)
+
+
+ +

Writes a 32-bit integer into memory in little-endian byte order.

+
Parameters:
+ + + +
[in]pPointer where to write the integer to.
[in]iThe 32-bit integer to write.
+
+
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__config.html b/final_project/sd_reader/doc/html/group__config.html new file mode 100644 index 0000000..154600d --- /dev/null +++ b/final_project/sd_reader/doc/html/group__config.html @@ -0,0 +1,94 @@ + + + + + +sd-reader: Sd-reader configuration + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
Sd-reader configuration
+
+
+ + + + + + + +

+Files

file  sd-reader_config.h
 

Common sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1)

+

+Defines

#define USE_DYNAMIC_MEMORY
 Controls allocation of memory.
+

Define Documentation

+ +
+
+ + + + +
#define USE_DYNAMIC_MEMORY
+
+
+ +

Controls allocation of memory.

+

Set to 1 to use malloc()/free() for allocation of structures like file and directory handles, set to 0 to use pre-allocated fixed-size handle arrays.

+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__fat.html b/final_project/sd_reader/doc/html/group__fat.html new file mode 100644 index 0000000..6edbc42 --- /dev/null +++ b/final_project/sd_reader/doc/html/group__fat.html @@ -0,0 +1,989 @@ + + + + + +sd-reader: FAT support + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
FAT support
+
+
+ +

This module implements FAT16/FAT32 read and write access. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  fat_dir_entry_struct
 Describes a directory entry. More...

+Modules

 FAT configuration
 

Preprocessor defines to configure the FAT implementation.

+
 FAT access
 

Basic functions for handling a FAT filesystem.

+
 FAT file functions
 

Functions for managing files.

+
 FAT directory functions
 

Functions for managing directories.

+

+Files

file  fat.c
 

FAT implementation (license: GPLv2 or LGPLv2.1)

+
file  fat.h
 

FAT header (license: GPLv2 or LGPLv2.1)

+
file  fat_config.h
 

FAT configuration (license: GPLv2 or LGPLv2.1)

+

+Functions

struct fat_fs_struct * fat_open (struct partition_struct *partition)
 Opens a FAT filesystem.
void fat_close (struct fat_fs_struct *fs)
 Closes a FAT filesystem.
struct fat_file_struct * fat_open_file (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a file on a FAT filesystem.
void fat_close_file (struct fat_file_struct *fd)
 Closes a file.
intptr_t fat_read_file (struct fat_file_struct *fd, uint8_t *buffer, uintptr_t buffer_len)
 Reads data from a file.
intptr_t fat_write_file (struct fat_file_struct *fd, const uint8_t *buffer, uintptr_t buffer_len)
 Writes data to a file.
uint8_t fat_seek_file (struct fat_file_struct *fd, int32_t *offset, uint8_t whence)
 Repositions the read/write file offset.
uint8_t fat_resize_file (struct fat_file_struct *fd, uint32_t size)
 Resizes a file to have a specific size.
struct fat_dir_struct * fat_open_dir (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a directory.
void fat_close_dir (struct fat_dir_struct *dd)
 Closes a directory descriptor.
uint8_t fat_read_dir (struct fat_dir_struct *dd, struct fat_dir_entry_struct *dir_entry)
 Reads the next directory entry contained within a parent directory.
uint8_t fat_reset_dir (struct fat_dir_struct *dd)
 Resets a directory handle.
uint8_t fat_create_file (struct fat_dir_struct *parent, const char *file, struct fat_dir_entry_struct *dir_entry)
 Creates a file.
uint8_t fat_delete_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
 Deletes a file or directory.
uint8_t fat_move_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry, struct fat_dir_struct *parent_new, const char *file_new)
 Moves or renames a file.
uint8_t fat_create_dir (struct fat_dir_struct *parent, const char *dir, struct fat_dir_entry_struct *dir_entry)
 Creates a directory.
void fat_get_file_modification_date (const struct fat_dir_entry_struct *dir_entry, uint16_t *year, uint8_t *month, uint8_t *day)
 Returns the modification date of a file.
void fat_get_file_modification_time (const struct fat_dir_entry_struct *dir_entry, uint8_t *hour, uint8_t *min, uint8_t *sec)
 Returns the modification time of a file.
uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct *fs, const char *path, struct fat_dir_entry_struct *dir_entry)
 Retrieves the directory entry of a path.
offset_t fat_get_fs_size (const struct fat_fs_struct *fs)
 Returns the amount of total storage capacity of the filesystem in bytes.
offset_t fat_get_fs_free (const struct fat_fs_struct *fs)
 Returns the amount of free storage capacity on the filesystem in bytes.
+

Detailed Description

+

This module implements FAT16/FAT32 read and write access.

+

The following features are supported:

+
    +
  • File names up to 31 characters long.
  • +
  • Unlimited depth of subdirectories.
  • +
  • Short 8.3 and long filenames.
  • +
  • Creating and deleting files.
  • +
  • Reading and writing from and to files.
  • +
  • File resizing.
  • +
  • File sizes of up to 4 gigabytes.
  • +
+

Function Documentation

+ +
+
+ + + + + + + + +
void fat_close (struct fat_fs_struct * fs)
+
+
+ +

Closes a FAT filesystem.

+

When this function returns, the given filesystem descriptor will be invalid.

+
Parameters:
+ + +
[in]fsThe filesystem to close.
+
+
+
See also:
fat_open
+ +
+
+ +
+
+ + + + + + + + +
void fat_close_dir (struct fat_dir_struct * dd)
+
+
+ +

Closes a directory descriptor.

+

This function destroys a directory descriptor which was previously obtained by calling fat_open_dir(). When this function returns, the given descriptor will be invalid.

+
Parameters:
+ + +
[in]ddThe directory descriptor to close.
+
+
+
See also:
fat_open_dir
+ +
+
+ +
+
+ + + + + + + + +
void fat_close_file (struct fat_file_struct * fd)
+
+
+ +

Closes a file.

+
Parameters:
+ + +
[in]fdThe file handle of the file to close.
+
+
+
See also:
fat_open_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_create_dir (struct fat_dir_struct * parent,
const char * dir,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Creates a directory.

+

Creates a directory and obtains its directory entry. If the directory to create already exists, its directory entry will be returned within the dir_entry parameter.

+
Note:
The notes which apply to fat_create_file() also apply to this function.
+
Parameters:
+ + + + +
[in]parentThe handle of the parent directory of the new directory.
[in]dirThe name of the directory to create.
[out]dir_entryThe directory entry to fill for the new directory.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_delete_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_create_file (struct fat_dir_struct * parent,
const char * file,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Creates a file.

+

Creates a file and obtains the directory entry of the new file. If the file to create already exists, the directory entry of the existing file will be returned within the dir_entry parameter.

+
Note:
The file name is not checked for invalid characters.
+
+The generation of the short 8.3 file name is quite simple. The first eight characters are used for the filename. The extension, if any, is made up of the first three characters following the last dot within the long filename. If the filename (without the extension) is longer than eight characters, the lower byte of the cluster number replaces the last two characters to avoid name clashes. In any other case, it is your responsibility to avoid name clashes.
+
Parameters:
+ + + + +
[in]parentThe handle of the directory in which to create the file.
[in]fileThe name of the file to create.
[out]dir_entryThe directory entry to fill for the new (or existing) file.
+
+
+
Returns:
0 on failure, 1 on success, 2 if the file already existed.
+
See also:
fat_delete_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_delete_file (struct fat_fs_struct * fs,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Deletes a file or directory.

+

If a directory is deleted without first deleting its subdirectories and files, disk space occupied by these files will get wasted as there is no chance to release it and mark it as free.

+
Parameters:
+ + + +
[in]fsThe filesystem on which to operate.
[in]dir_entryThe directory entry of the file to delete.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_create_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct * fs,
const char * path,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Retrieves the directory entry of a path.

+

The given path may both describe a file or a directory.

+
Parameters:
+ + + + +
[in]fsThe FAT filesystem on which to search.
[in]pathThe path of which to read the directory entry.
[out]dir_entryThe directory entry to fill.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_read_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void fat_get_file_modification_date (const struct fat_dir_entry_structdir_entry,
uint16_t * year,
uint8_t * month,
uint8_t * day 
)
+
+
+ +

Returns the modification date of a file.

+
Parameters:
+ + + + + +
[in]dir_entryThe directory entry of which to return the modification date.
[out]yearThe year the file was last modified.
[out]monthThe month the file was last modified.
[out]dayThe day the file was last modified.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void fat_get_file_modification_time (const struct fat_dir_entry_structdir_entry,
uint8_t * hour,
uint8_t * min,
uint8_t * sec 
)
+
+
+ +

Returns the modification time of a file.

+
Parameters:
+ + + + + +
[in]dir_entryThe directory entry of which to return the modification time.
[out]hourThe hour the file was last modified.
[out]minThe min the file was last modified.
[out]secThe sec the file was last modified.
+
+
+ +
+
+ +
+
+ + + + + + + + +
offset_t fat_get_fs_free (const struct fat_fs_struct * fs)
+
+
+ +

Returns the amount of free storage capacity on the filesystem in bytes.

+
Note:
As the FAT filesystem is cluster based, this function does not return continuous values but multiples of the cluster size.
+
Parameters:
+ + +
[in]fsThe filesystem on which to operate.
+
+
+
Returns:
0 on failure, the free filesystem space in bytes otherwise.
+ +
+
+ +
+
+ + + + + + + + +
offset_t fat_get_fs_size (const struct fat_fs_struct * fs)
+
+
+ +

Returns the amount of total storage capacity of the filesystem in bytes.

+
Parameters:
+ + +
[in]fsThe filesystem on which to operate.
+
+
+
Returns:
0 on failure, the filesystem size in bytes otherwise.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_move_file (struct fat_fs_struct * fs,
struct fat_dir_entry_structdir_entry,
struct fat_dir_struct * parent_new,
const char * file_new 
)
+
+
+ +

Moves or renames a file.

+

Changes a file's name, optionally moving it into another directory as well. Before calling this function, the target file name must not exist. Moving a file to a different filesystem (i.e. parent_new doesn't lie on fs) is not supported.

+

After successfully renaming (and moving) the file, the given directory entry is updated such that it points to the file's new location.

+
Note:
The notes which apply to fat_create_file() also apply to this function.
+
Parameters:
+ + + + + +
[in]fsThe filesystem on which to operate.
[in,out]dir_entryThe directory entry of the file to move.
[in]parent_newThe handle of the new parent directory of the file.
[in]file_newThe file's new name.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_create_file, fat_delete_file, fat_move_dir
+ +
+
+ +
+
+ + + + + + + + +
struct fat_fs_struct* fat_open (struct partition_structpartition) [read]
+
+
+ +

Opens a FAT filesystem.

+
Parameters:
+ + +
[in]partitionDiscriptor of partition on which the filesystem resides.
+
+
+
Returns:
0 on error, a FAT filesystem descriptor on success.
+
See also:
fat_close
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
struct fat_dir_struct* fat_open_dir (struct fat_fs_struct * fs,
const struct fat_dir_entry_structdir_entry 
) [read]
+
+
+ +

Opens a directory.

+
Parameters:
+ + + +
[in]fsThe filesystem on which the directory to open resides.
[in]dir_entryThe directory entry which stands for the directory to open.
+
+
+
Returns:
An opaque directory descriptor on success, 0 on failure.
+
See also:
fat_close_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
struct fat_file_struct* fat_open_file (struct fat_fs_struct * fs,
const struct fat_dir_entry_structdir_entry 
) [read]
+
+
+ +

Opens a file on a FAT filesystem.

+
Parameters:
+ + + +
[in]fsThe filesystem on which the file to open lies.
[in]dir_entryThe directory entry of the file to open.
+
+
+
Returns:
The file handle, or 0 on failure.
+
See also:
fat_close_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_read_dir (struct fat_dir_struct * dd,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Reads the next directory entry contained within a parent directory.

+
Parameters:
+ + + +
[in]ddThe descriptor of the parent directory from which to read the entry.
[out]dir_entryPointer to a buffer into which to write the directory entry information.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_reset_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
intptr_t fat_read_file (struct fat_file_struct * fd,
uint8_t * buffer,
uintptr_t buffer_len 
)
+
+
+ +

Reads data from a file.

+

The data requested is read from the current file location.

+
Parameters:
+ + + + +
[in]fdThe file handle of the file from which to read.
[out]bufferThe buffer into which to write.
[in]buffer_lenThe amount of data to read.
+
+
+
Returns:
The number of bytes read, 0 on end of file, or -1 on failure.
+
See also:
fat_write_file
+ +
+
+ +
+
+ + + + + + + + +
uint8_t fat_reset_dir (struct fat_dir_struct * dd)
+
+
+ +

Resets a directory handle.

+

Resets the directory handle such that reading restarts with the first directory entry.

+
Parameters:
+ + +
[in]ddThe directory handle to reset.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_read_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_resize_file (struct fat_file_struct * fd,
uint32_t size 
)
+
+
+ +

Resizes a file to have a specific size.

+

Enlarges or shrinks the file pointed to by the file descriptor to have exactly the specified size.

+

If the file is truncated, all bytes having an equal or larger offset than the given size are lost. If the file is expanded, the additional bytes are allocated.

+
Note:
Please be aware that this function just allocates or deallocates disk space, it does not explicitely clear it. To avoid data leakage, this must be done manually.
+
Parameters:
+ + + +
[in]fdThe file decriptor of the file which to resize.
[in]sizeThe new size of the file.
+
+
+
Returns:
0 on failure, 1 on success.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_seek_file (struct fat_file_struct * fd,
int32_t * offset,
uint8_t whence 
)
+
+
+ +

Repositions the read/write file offset.

+

Changes the file offset where the next call to fat_read_file() or fat_write_file() starts reading/writing.

+

If the new offset is beyond the end of the file, fat_resize_file() is implicitly called, i.e. the file is expanded.

+

The new offset can be given in different ways determined by the whence parameter:

+
    +
  • FAT_SEEK_SET: *offset is relative to the beginning of the file.
  • +
  • FAT_SEEK_CUR: *offset is relative to the current file position.
  • +
  • FAT_SEEK_END: *offset is relative to the end of the file.
  • +
+

The resulting absolute offset is written to the location the offset parameter points to.

+

Calling this function can also be used to retrieve the current file position:

+
   int32_t file_pos = 0;
+   if(!fat_seek_file(fd, &file_pos, FAT_SEEK_CUR))
+   {
+       // error
+   }
+   // file_pos now contains the absolute file position
+
Parameters:
+ + + + +
[in]fdThe file decriptor of the file on which to seek.
[in,out]offsetA pointer to the new offset, as affected by the whence parameter. The function writes the new absolute offset to this location before it returns.
[in]whenceAffects the way offset is interpreted, see above.
+
+
+
Returns:
0 on failure, 1 on success.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
intptr_t fat_write_file (struct fat_file_struct * fd,
const uint8_t * buffer,
uintptr_t buffer_len 
)
+
+
+ +

Writes data to a file.

+

The data is written to the current file location.

+
Parameters:
+ + + + +
[in]fdThe file handle of the file to which to write.
[in]bufferThe buffer from which to read the data to be written.
[in]buffer_lenThe amount of data to write.
+
+
+
Returns:
The number of bytes written (0 or something less than buffer_len on disk full) or -1 on failure.
+
See also:
fat_read_file
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__fat__config.html b/final_project/sd_reader/doc/html/group__fat__config.html new file mode 100644 index 0000000..6a756d7 --- /dev/null +++ b/final_project/sd_reader/doc/html/group__fat__config.html @@ -0,0 +1,242 @@ + + + + + +sd-reader: FAT configuration + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
FAT configuration
+
+
+ +

Preprocessor defines to configure the FAT implementation. +More...

+ + + + + + + + + + + + + + + + + + + + +

+Defines

#define FAT_WRITE_SUPPORT
 Controls FAT write support.
#define FAT_LFN_SUPPORT
 Controls FAT long filename (LFN) support.
#define FAT_DATETIME_SUPPORT
 Controls FAT date and time support.
#define FAT_FAT32_SUPPORT
 Controls FAT32 support.
#define FAT_DELAY_DIRENTRY_UPDATE
 Controls updates of directory entries.
#define fat_get_datetime(year, month, day, hour, min, sec)
 Determines the function used for retrieving current date and time.
+#define FAT_FS_COUNT
 Maximum number of filesystem handles.
+#define FAT_FILE_COUNT
 Maximum number of file handles.
+#define FAT_DIR_COUNT
 Maximum number of directory handles.
+

Detailed Description

+

Preprocessor defines to configure the FAT implementation.

+

Define Documentation

+ +
+
+ + + + +
#define FAT_DATETIME_SUPPORT
+
+
+ +

Controls FAT date and time support.

+

Set to 1 to enable FAT date and time stamping support.

+ +
+
+ +
+
+ + + + +
#define FAT_DELAY_DIRENTRY_UPDATE
+
+
+ +

Controls updates of directory entries.

+

Set to 1 to delay directory entry updates until the file is closed. This can boost performance significantly, but may cause data loss if the file is not properly closed.

+ +
+
+ +
+
+ + + + +
#define FAT_FAT32_SUPPORT
+
+
+ +

Controls FAT32 support.

+

Set to 1 to enable FAT32 support.

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#define fat_get_datetime( year,
 month,
 day,
 hour,
 min,
 sec 
)
+
+
+ +

Determines the function used for retrieving current date and time.

+

Define this to the function call which shall be used to retrieve current date and time.

+
Note:
Used only when FAT_DATETIME_SUPPORT is 1.
+
Parameters:
+ + + + + + + +
[out]yearPointer to a uint16_t which receives the current year.
[out]monthPointer to a uint8_t which receives the current month.
[out]dayPointer to a uint8_t which receives the current day.
[out]hourPointer to a uint8_t which receives the current hour.
[out]minPointer to a uint8_t which receives the current minute.
[out]secPointer to a uint8_t which receives the current sec.
+
+
+ +
+
+ +
+
+ + + + +
#define FAT_LFN_SUPPORT
+
+
+ +

Controls FAT long filename (LFN) support.

+

Set to 1 to enable LFN support, set to 0 to disable it.

+ +
+
+ +
+
+ + + + +
#define FAT_WRITE_SUPPORT
+
+
+ +

Controls FAT write support.

+

Set to 1 to enable FAT write support, set to 0 to disable it.

+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__fat__dir.html b/final_project/sd_reader/doc/html/group__fat__dir.html new file mode 100644 index 0000000..9c3b972 --- /dev/null +++ b/final_project/sd_reader/doc/html/group__fat__dir.html @@ -0,0 +1,359 @@ + + + + + +sd-reader: FAT directory functions + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
FAT directory functions
+
+
+ +

Functions for managing directories. +More...

+ + + + + + + + + + + + + + + + +

+Functions

struct fat_dir_struct * fat_open_dir (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a directory.
void fat_close_dir (struct fat_dir_struct *dd)
 Closes a directory descriptor.
uint8_t fat_read_dir (struct fat_dir_struct *dd, struct fat_dir_entry_struct *dir_entry)
 Reads the next directory entry contained within a parent directory.
uint8_t fat_reset_dir (struct fat_dir_struct *dd)
 Resets a directory handle.
uint8_t fat_create_dir (struct fat_dir_struct *parent, const char *dir, struct fat_dir_entry_struct *dir_entry)
 Creates a directory.
uint8_t fat_delete_dir (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
 Deletes a directory.
uint8_t fat_move_dir (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry, struct fat_dir_struct *parent_new, const char *dir_new)
 Moves or renames a directory.
+

Detailed Description

+

Functions for managing directories.

+

Function Documentation

+ +
+
+ + + + + + + + +
void fat_close_dir (struct fat_dir_struct * dd)
+
+
+ +

Closes a directory descriptor.

+

This function destroys a directory descriptor which was previously obtained by calling fat_open_dir(). When this function returns, the given descriptor will be invalid.

+
Parameters:
+ + +
[in]ddThe directory descriptor to close.
+
+
+
See also:
fat_open_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_create_dir (struct fat_dir_struct * parent,
const char * dir,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Creates a directory.

+

Creates a directory and obtains its directory entry. If the directory to create already exists, its directory entry will be returned within the dir_entry parameter.

+
Note:
The notes which apply to fat_create_file() also apply to this function.
+
Parameters:
+ + + + +
[in]parentThe handle of the parent directory of the new directory.
[in]dirThe name of the directory to create.
[out]dir_entryThe directory entry to fill for the new directory.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_delete_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_delete_dir (struct fat_fs_struct * fs,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Deletes a directory.

+

This is just a synonym for fat_delete_file(). If a directory is deleted without first deleting its subdirectories and files, disk space occupied by these files will get wasted as there is no chance to release it and mark it as free.

+
Parameters:
+ + + +
[in]fsThe filesystem on which to operate.
[in]dir_entryThe directory entry of the directory to delete.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_create_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_move_dir (struct fat_fs_struct * fs,
struct fat_dir_entry_structdir_entry,
struct fat_dir_struct * parent_new,
const char * dir_new 
)
+
+
+ +

Moves or renames a directory.

+

This is just a synonym for fat_move_file().

+
Parameters:
+ + + + + +
[in]fsThe filesystem on which to operate.
[in,out]dir_entryThe directory entry of the directory to move.
[in]parent_newThe handle of the new parent directory.
[in]dir_newThe directory's new name.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_create_dir, fat_delete_dir, fat_move_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
struct fat_dir_struct* fat_open_dir (struct fat_fs_struct * fs,
const struct fat_dir_entry_structdir_entry 
) [read]
+
+
+ +

Opens a directory.

+
Parameters:
+ + + +
[in]fsThe filesystem on which the directory to open resides.
[in]dir_entryThe directory entry which stands for the directory to open.
+
+
+
Returns:
An opaque directory descriptor on success, 0 on failure.
+
See also:
fat_close_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_read_dir (struct fat_dir_struct * dd,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Reads the next directory entry contained within a parent directory.

+
Parameters:
+ + + +
[in]ddThe descriptor of the parent directory from which to read the entry.
[out]dir_entryPointer to a buffer into which to write the directory entry information.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_reset_dir
+ +
+
+ +
+
+ + + + + + + + +
uint8_t fat_reset_dir (struct fat_dir_struct * dd)
+
+
+ +

Resets a directory handle.

+

Resets the directory handle such that reading restarts with the first directory entry.

+
Parameters:
+ + +
[in]ddThe directory handle to reset.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_read_dir
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__fat__file.html b/final_project/sd_reader/doc/html/group__fat__file.html new file mode 100644 index 0000000..f89a4fd --- /dev/null +++ b/final_project/sd_reader/doc/html/group__fat__file.html @@ -0,0 +1,910 @@ + + + + + +sd-reader: FAT file functions + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
FAT file functions
+
+
+ +

Functions for managing files. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  fat_dir_entry_struct
 Describes a directory entry. More...

+Defines

#define FAT_ATTRIB_READONLY
 The file is read-only.
#define FAT_ATTRIB_HIDDEN
 The file is hidden.
#define FAT_ATTRIB_SYSTEM
 The file is a system file.
#define FAT_ATTRIB_VOLUME
 The file is empty and has the volume label as its name.
#define FAT_ATTRIB_DIR
 The file is a directory.
#define FAT_ATTRIB_ARCHIVE
 The file has to be archived.
#define FAT_SEEK_SET
 The given offset is relative to the beginning of the file.
#define FAT_SEEK_CUR
 The given offset is relative to the current read/write position.
#define FAT_SEEK_END
 The given offset is relative to the end of the file.

+Functions

uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct *fs, const char *path, struct fat_dir_entry_struct *dir_entry)
 Retrieves the directory entry of a path.
struct fat_file_struct * fat_open_file (struct fat_fs_struct *fs, const struct fat_dir_entry_struct *dir_entry)
 Opens a file on a FAT filesystem.
void fat_close_file (struct fat_file_struct *fd)
 Closes a file.
intptr_t fat_read_file (struct fat_file_struct *fd, uint8_t *buffer, uintptr_t buffer_len)
 Reads data from a file.
intptr_t fat_write_file (struct fat_file_struct *fd, const uint8_t *buffer, uintptr_t buffer_len)
 Writes data to a file.
uint8_t fat_seek_file (struct fat_file_struct *fd, int32_t *offset, uint8_t whence)
 Repositions the read/write file offset.
uint8_t fat_resize_file (struct fat_file_struct *fd, uint32_t size)
 Resizes a file to have a specific size.
uint8_t fat_create_file (struct fat_dir_struct *parent, const char *file, struct fat_dir_entry_struct *dir_entry)
 Creates a file.
uint8_t fat_delete_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry)
 Deletes a file or directory.
uint8_t fat_move_file (struct fat_fs_struct *fs, struct fat_dir_entry_struct *dir_entry, struct fat_dir_struct *parent_new, const char *file_new)
 Moves or renames a file.
void fat_get_file_modification_date (const struct fat_dir_entry_struct *dir_entry, uint16_t *year, uint8_t *month, uint8_t *day)
 Returns the modification date of a file.
void fat_get_file_modification_time (const struct fat_dir_entry_struct *dir_entry, uint8_t *hour, uint8_t *min, uint8_t *sec)
 Returns the modification time of a file.
void fat_set_file_modification_date (struct fat_dir_entry_struct *dir_entry, uint16_t year, uint8_t month, uint8_t day)
 Sets the modification time of a date.
void fat_set_file_modification_time (struct fat_dir_entry_struct *dir_entry, uint8_t hour, uint8_t min, uint8_t sec)
 Sets the modification time of a file.
+

Detailed Description

+

Functions for managing files.

+

Define Documentation

+ +
+
+ + + + +
#define FAT_ATTRIB_ARCHIVE
+
+
+ +

The file has to be archived.

+ +
+
+ +
+
+ + + + +
#define FAT_ATTRIB_DIR
+
+
+ +

The file is a directory.

+ +
+
+ +
+
+ + + + +
#define FAT_ATTRIB_HIDDEN
+
+
+ +

The file is hidden.

+ +
+
+ +
+
+ + + + +
#define FAT_ATTRIB_READONLY
+
+
+ +

The file is read-only.

+ +
+
+ +
+
+ + + + +
#define FAT_ATTRIB_SYSTEM
+
+
+ +

The file is a system file.

+ +
+
+ +
+
+ + + + +
#define FAT_ATTRIB_VOLUME
+
+
+ +

The file is empty and has the volume label as its name.

+ +
+
+ +
+
+ + + + +
#define FAT_SEEK_CUR
+
+
+ +

The given offset is relative to the current read/write position.

+ +
+
+ +
+
+ + + + +
#define FAT_SEEK_END
+
+
+ +

The given offset is relative to the end of the file.

+ +
+
+ +
+
+ + + + +
#define FAT_SEEK_SET
+
+
+ +

The given offset is relative to the beginning of the file.

+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
void fat_close_file (struct fat_file_struct * fd)
+
+
+ +

Closes a file.

+
Parameters:
+ + +
[in]fdThe file handle of the file to close.
+
+
+
See also:
fat_open_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_create_file (struct fat_dir_struct * parent,
const char * file,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Creates a file.

+

Creates a file and obtains the directory entry of the new file. If the file to create already exists, the directory entry of the existing file will be returned within the dir_entry parameter.

+
Note:
The file name is not checked for invalid characters.
+
+The generation of the short 8.3 file name is quite simple. The first eight characters are used for the filename. The extension, if any, is made up of the first three characters following the last dot within the long filename. If the filename (without the extension) is longer than eight characters, the lower byte of the cluster number replaces the last two characters to avoid name clashes. In any other case, it is your responsibility to avoid name clashes.
+
Parameters:
+ + + + +
[in]parentThe handle of the directory in which to create the file.
[in]fileThe name of the file to create.
[out]dir_entryThe directory entry to fill for the new (or existing) file.
+
+
+
Returns:
0 on failure, 1 on success, 2 if the file already existed.
+
See also:
fat_delete_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_delete_file (struct fat_fs_struct * fs,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Deletes a file or directory.

+

If a directory is deleted without first deleting its subdirectories and files, disk space occupied by these files will get wasted as there is no chance to release it and mark it as free.

+
Parameters:
+ + + +
[in]fsThe filesystem on which to operate.
[in]dir_entryThe directory entry of the file to delete.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_create_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_get_dir_entry_of_path (struct fat_fs_struct * fs,
const char * path,
struct fat_dir_entry_structdir_entry 
)
+
+
+ +

Retrieves the directory entry of a path.

+

The given path may both describe a file or a directory.

+
Parameters:
+ + + + +
[in]fsThe FAT filesystem on which to search.
[in]pathThe path of which to read the directory entry.
[out]dir_entryThe directory entry to fill.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_read_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void fat_get_file_modification_date (const struct fat_dir_entry_structdir_entry,
uint16_t * year,
uint8_t * month,
uint8_t * day 
)
+
+
+ +

Returns the modification date of a file.

+
Parameters:
+ + + + + +
[in]dir_entryThe directory entry of which to return the modification date.
[out]yearThe year the file was last modified.
[out]monthThe month the file was last modified.
[out]dayThe day the file was last modified.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void fat_get_file_modification_time (const struct fat_dir_entry_structdir_entry,
uint8_t * hour,
uint8_t * min,
uint8_t * sec 
)
+
+
+ +

Returns the modification time of a file.

+
Parameters:
+ + + + + +
[in]dir_entryThe directory entry of which to return the modification time.
[out]hourThe hour the file was last modified.
[out]minThe min the file was last modified.
[out]secThe sec the file was last modified.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_move_file (struct fat_fs_struct * fs,
struct fat_dir_entry_structdir_entry,
struct fat_dir_struct * parent_new,
const char * file_new 
)
+
+
+ +

Moves or renames a file.

+

Changes a file's name, optionally moving it into another directory as well. Before calling this function, the target file name must not exist. Moving a file to a different filesystem (i.e. parent_new doesn't lie on fs) is not supported.

+

After successfully renaming (and moving) the file, the given directory entry is updated such that it points to the file's new location.

+
Note:
The notes which apply to fat_create_file() also apply to this function.
+
Parameters:
+ + + + + +
[in]fsThe filesystem on which to operate.
[in,out]dir_entryThe directory entry of the file to move.
[in]parent_newThe handle of the new parent directory of the file.
[in]file_newThe file's new name.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
fat_create_file, fat_delete_file, fat_move_dir
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
struct fat_file_struct* fat_open_file (struct fat_fs_struct * fs,
const struct fat_dir_entry_structdir_entry 
) [read]
+
+
+ +

Opens a file on a FAT filesystem.

+
Parameters:
+ + + +
[in]fsThe filesystem on which the file to open lies.
[in]dir_entryThe directory entry of the file to open.
+
+
+
Returns:
The file handle, or 0 on failure.
+
See also:
fat_close_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
intptr_t fat_read_file (struct fat_file_struct * fd,
uint8_t * buffer,
uintptr_t buffer_len 
)
+
+
+ +

Reads data from a file.

+

The data requested is read from the current file location.

+
Parameters:
+ + + + +
[in]fdThe file handle of the file from which to read.
[out]bufferThe buffer into which to write.
[in]buffer_lenThe amount of data to read.
+
+
+
Returns:
The number of bytes read, 0 on end of file, or -1 on failure.
+
See also:
fat_write_file
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
uint8_t fat_resize_file (struct fat_file_struct * fd,
uint32_t size 
)
+
+
+ +

Resizes a file to have a specific size.

+

Enlarges or shrinks the file pointed to by the file descriptor to have exactly the specified size.

+

If the file is truncated, all bytes having an equal or larger offset than the given size are lost. If the file is expanded, the additional bytes are allocated.

+
Note:
Please be aware that this function just allocates or deallocates disk space, it does not explicitely clear it. To avoid data leakage, this must be done manually.
+
Parameters:
+ + + +
[in]fdThe file decriptor of the file which to resize.
[in]sizeThe new size of the file.
+
+
+
Returns:
0 on failure, 1 on success.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t fat_seek_file (struct fat_file_struct * fd,
int32_t * offset,
uint8_t whence 
)
+
+
+ +

Repositions the read/write file offset.

+

Changes the file offset where the next call to fat_read_file() or fat_write_file() starts reading/writing.

+

If the new offset is beyond the end of the file, fat_resize_file() is implicitly called, i.e. the file is expanded.

+

The new offset can be given in different ways determined by the whence parameter:

+
    +
  • FAT_SEEK_SET: *offset is relative to the beginning of the file.
  • +
  • FAT_SEEK_CUR: *offset is relative to the current file position.
  • +
  • FAT_SEEK_END: *offset is relative to the end of the file.
  • +
+

The resulting absolute offset is written to the location the offset parameter points to.

+

Calling this function can also be used to retrieve the current file position:

+
   int32_t file_pos = 0;
+   if(!fat_seek_file(fd, &file_pos, FAT_SEEK_CUR))
+   {
+       // error
+   }
+   // file_pos now contains the absolute file position
+
Parameters:
+ + + + +
[in]fdThe file decriptor of the file on which to seek.
[in,out]offsetA pointer to the new offset, as affected by the whence parameter. The function writes the new absolute offset to this location before it returns.
[in]whenceAffects the way offset is interpreted, see above.
+
+
+
Returns:
0 on failure, 1 on success.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void fat_set_file_modification_date (struct fat_dir_entry_structdir_entry,
uint16_t year,
uint8_t month,
uint8_t day 
)
+
+
+ +

Sets the modification time of a date.

+
Parameters:
+ + + + + +
[in]dir_entryThe directory entry for which to set the modification date.
[in]yearThe year the file was last modified.
[in]monthThe month the file was last modified.
[in]dayThe day the file was last modified.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void fat_set_file_modification_time (struct fat_dir_entry_structdir_entry,
uint8_t hour,
uint8_t min,
uint8_t sec 
)
+
+
+ +

Sets the modification time of a file.

+
Parameters:
+ + + + + +
[in]dir_entryThe directory entry for which to set the modification time.
[in]hourThe year the file was last modified.
[in]minThe month the file was last modified.
[in]secThe day the file was last modified.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
intptr_t fat_write_file (struct fat_file_struct * fd,
const uint8_t * buffer,
uintptr_t buffer_len 
)
+
+
+ +

Writes data to a file.

+

The data is written to the current file location.

+
Parameters:
+ + + + +
[in]fdThe file handle of the file to which to write.
[in]bufferThe buffer from which to read the data to be written.
[in]buffer_lenThe amount of data to write.
+
+
+
Returns:
The number of bytes written (0 or something less than buffer_len on disk full) or -1 on failure.
+
See also:
fat_read_file
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__fat__fs.html b/final_project/sd_reader/doc/html/group__fat__fs.html new file mode 100644 index 0000000..b2de2b9 --- /dev/null +++ b/final_project/sd_reader/doc/html/group__fat__fs.html @@ -0,0 +1,193 @@ + + + + + +sd-reader: FAT access + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
FAT access
+
+
+ +

Basic functions for handling a FAT filesystem. +More...

+ + + + + + + + + + + + +

+Functions

struct fat_fs_struct * fat_open (struct partition_struct *partition)
 Opens a FAT filesystem.
void fat_close (struct fat_fs_struct *fs)
 Closes a FAT filesystem.
offset_t fat_get_fs_size (const struct fat_fs_struct *fs)
 Returns the amount of total storage capacity of the filesystem in bytes.
offset_t fat_get_fs_free (const struct fat_fs_struct *fs)
 Returns the amount of free storage capacity on the filesystem in bytes.
+uint8_t fat_get_fs_free_32_callback (uint8_t *buffer, offset_t offset, void *p)
 Callback function used for counting free clusters in a FAT32.
+

Detailed Description

+

Basic functions for handling a FAT filesystem.

+

Function Documentation

+ +
+
+ + + + + + + + +
void fat_close (struct fat_fs_struct * fs)
+
+
+ +

Closes a FAT filesystem.

+

When this function returns, the given filesystem descriptor will be invalid.

+
Parameters:
+ + +
[in]fsThe filesystem to close.
+
+
+
See also:
fat_open
+ +
+
+ +
+
+ + + + + + + + +
offset_t fat_get_fs_free (const struct fat_fs_struct * fs)
+
+
+ +

Returns the amount of free storage capacity on the filesystem in bytes.

+
Note:
As the FAT filesystem is cluster based, this function does not return continuous values but multiples of the cluster size.
+
Parameters:
+ + +
[in]fsThe filesystem on which to operate.
+
+
+
Returns:
0 on failure, the free filesystem space in bytes otherwise.
+ +
+
+ +
+
+ + + + + + + + +
offset_t fat_get_fs_size (const struct fat_fs_struct * fs)
+
+
+ +

Returns the amount of total storage capacity of the filesystem in bytes.

+
Parameters:
+ + +
[in]fsThe filesystem on which to operate.
+
+
+
Returns:
0 on failure, the filesystem size in bytes otherwise.
+ +
+
+ +
+
+ + + + + + + + +
struct fat_fs_struct* fat_open (struct partition_structpartition) [read]
+
+
+ +

Opens a FAT filesystem.

+
Parameters:
+ + +
[in]partitionDiscriptor of partition on which the filesystem resides.
+
+
+
Returns:
0 on error, a FAT filesystem descriptor on success.
+
See also:
fat_close
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__partition.html b/final_project/sd_reader/doc/html/group__partition.html new file mode 100644 index 0000000..63904de --- /dev/null +++ b/final_project/sd_reader/doc/html/group__partition.html @@ -0,0 +1,394 @@ + + + + + +sd-reader: Partition table support + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
Partition table support
+
+
+ +

Support for reading partition tables and access to partitions. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  partition_struct
 Describes a partition. More...

+Modules

 Configuration of partition table support
 

Preprocessor defines to configure the partition support.

+

+Files

file  partition.c
 

Partition table implementation (license: GPLv2 or LGPLv2.1)

+
file  partition.h
 

Partition table header (license: GPLv2 or LGPLv2.1)

+
file  partition_config.h
 

Partition configuration (license: GPLv2 or LGPLv2.1)

+

+Defines

+#define PARTITION_TYPE_FREE
 The partition table entry is not used.
+#define PARTITION_TYPE_FAT12
 The partition contains a FAT12 filesystem.
+#define PARTITION_TYPE_FAT16_32MB
 The partition contains a FAT16 filesystem with 32MB maximum.
+#define PARTITION_TYPE_EXTENDED
 The partition is an extended partition with its own partition table.
+#define PARTITION_TYPE_FAT16
 The partition contains a FAT16 filesystem.
+#define PARTITION_TYPE_FAT32
 The partition contains a FAT32 filesystem.
+#define PARTITION_TYPE_FAT32_LBA
 The partition contains a FAT32 filesystem with LBA.
+#define PARTITION_TYPE_FAT16_LBA
 The partition contains a FAT16 filesystem with LBA.
+#define PARTITION_TYPE_EXTENDED_LBA
 The partition is an extended partition with LBA.
+#define PARTITION_TYPE_UNKNOWN
 The partition has an unknown type.

+Typedefs

typedef uint8_t(* device_read_t )(offset_t offset, uint8_t *buffer, uintptr_t length)
 A function pointer used to read from the partition.
typedef uint8_t(* device_read_callback_t )(uint8_t *buffer, offset_t offset, void *p)
 A function pointer passed to a device_read_interval_t.
typedef uint8_t(* device_read_interval_t )(offset_t offset, uint8_t *buffer, uintptr_t interval, uintptr_t length, device_read_callback_t callback, void *p)
 A function pointer used to continuously read units of interval bytes and call a callback function.
typedef uint8_t(* device_write_t )(offset_t offset, const uint8_t *buffer, uintptr_t length)
 A function pointer used to write to the partition.
typedef uintptr_t(* device_write_callback_t )(uint8_t *buffer, offset_t offset, void *p)
 A function pointer passed to a device_write_interval_t.
typedef uint8_t(* device_write_interval_t )(offset_t offset, uint8_t *buffer, uintptr_t length, device_write_callback_t callback, void *p)
 A function pointer used to continuously write a data stream obtained from a callback function.

+Functions

struct partition_structpartition_open (device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index)
 Opens a partition.
uint8_t partition_close (struct partition_struct *partition)
 Closes a partition.
+

Detailed Description

+

Support for reading partition tables and access to partitions.

+

Typedef Documentation

+ +
+
+ + + + +
typedef uint8_t(* device_read_callback_t)(uint8_t *buffer, offset_t offset, void *p)
+
+
+ +

A function pointer passed to a device_read_interval_t.

+
Parameters:
+ + + + +
[in]bufferThe buffer which contains the data just read.
[in]offsetThe offset from which the data in buffer was read.
[in]pAn opaque pointer.
+
+
+
See also:
device_read_interval_t
+ +
+
+ +
+
+ + + + +
typedef uint8_t(* device_read_interval_t)(offset_t offset, uint8_t *buffer, uintptr_t interval, uintptr_t length, device_read_callback_t callback, void *p)
+
+
+ +

A function pointer used to continuously read units of interval bytes and call a callback function.

+

This function starts reading at the specified offset. Every interval bytes, it calls the callback function with the associated data buffer.

+

By returning zero, the callback may stop reading.

+
Parameters:
+ + + + + + + +
[in]offsetOffset from which to start reading.
[in]bufferPointer to a buffer which is at least interval bytes in size.
[in]intervalNumber of bytes to read before calling the callback function.
[in]lengthNumber of bytes to read altogether.
[in]callbackThe function to call every interval bytes.
[in]pAn opaque pointer directly passed to the callback function.
+
+
+
Returns:
0 on failure, 1 on success
+
See also:
device_read_t
+ +
+
+ +
+
+ + + + +
typedef uint8_t(* device_read_t)(offset_t offset, uint8_t *buffer, uintptr_t length)
+
+
+ +

A function pointer used to read from the partition.

+
Parameters:
+ + + + +
[in]offsetThe offset on the device where to start reading.
[out]bufferThe buffer into which to place the data.
[in]lengthThe count of bytes to read.
+
+
+ +
+
+ +
+
+ + + + +
typedef uintptr_t(* device_write_callback_t)(uint8_t *buffer, offset_t offset, void *p)
+
+
+ +

A function pointer passed to a device_write_interval_t.

+
Parameters:
+ + + + +
[in]bufferThe buffer which receives the data to write.
[in]offsetThe offset to which the data in buffer will be written.
[in]pAn opaque pointer.
+
+
+
Returns:
The number of bytes put into buffer
+
See also:
device_write_interval_t
+ +
+
+ +
+
+ + + + +
typedef uint8_t(* device_write_interval_t)(offset_t offset, uint8_t *buffer, uintptr_t length, device_write_callback_t callback, void *p)
+
+
+ +

A function pointer used to continuously write a data stream obtained from a callback function.

+

This function starts writing at the specified offset. To obtain the next bytes to write, it calls the callback function. The callback fills the provided data buffer and returns the number of bytes it has put into the buffer.

+

By returning zero, the callback may stop writing.

+
Parameters:
+ + + + + + +
[in]offsetOffset where to start writing.
[in]bufferPointer to a buffer which is used for the callback function.
[in]lengthNumber of bytes to write in total. May be zero for endless writes.
[in]callbackThe function used to obtain the bytes to write.
[in]pAn opaque pointer directly passed to the callback function.
+
+
+
Returns:
0 on failure, 1 on success
+
See also:
device_write_t
+ +
+
+ +
+
+ + + + +
typedef uint8_t(* device_write_t)(offset_t offset, const uint8_t *buffer, uintptr_t length)
+
+
+ +

A function pointer used to write to the partition.

+
Parameters:
+ + + + +
[in]offsetThe offset on the device where to start writing.
[in]bufferThe buffer which to write.
[in]lengthThe count of bytes to write.
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + +
uint8_t partition_close (struct partition_structpartition)
+
+
+ +

Closes a partition.

+

This function destroys a partition descriptor which was previously obtained from a call to partition_open(). When this function returns, the given descriptor will be invalid.

+
Parameters:
+ + +
[in]partitionThe partition descriptor to destroy.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
partition_open
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
struct partition_struct * partition_open (device_read_t device_read,
device_read_interval_t device_read_interval,
device_write_t device_write,
device_write_interval_t device_write_interval,
int8_t index 
) [read]
+
+
+ +

Opens a partition.

+

Opens a partition by its index number and returns a partition handle which describes the opened partition.

+
Note:
This function does not support extended partitions.
+
Parameters:
+ + + + + + +
[in]device_readA function pointer which is used to read from the disk.
[in]device_read_intervalA function pointer which is used to read in constant intervals from the disk.
[in]device_writeA function pointer which is used to write to the disk.
[in]device_write_intervalA function pointer which is used to write a data stream to disk.
[in]indexThe index of the partition which should be opened, range 0 to 3. A negative value is allowed as well. In this case, the partition opened is not checked for existance, begins at offset zero, has a length of zero and is of an unknown type. Use this in case you want to open the whole device as a single partition (e.g. for "super floppy" use).
+
+
+
Returns:
0 on failure, a partition descriptor on success.
+
See also:
partition_close
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__partition__config.html b/final_project/sd_reader/doc/html/group__partition__config.html new file mode 100644 index 0000000..7e02967 --- /dev/null +++ b/final_project/sd_reader/doc/html/group__partition__config.html @@ -0,0 +1,77 @@ + + + + + +sd-reader: Configuration of partition table support + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
Configuration of partition table support
+
+
+ +

Preprocessor defines to configure the partition support. +More...

+ + + + +

+Defines

+#define PARTITION_COUNT
 Maximum number of partition handles.
+

Detailed Description

+

Preprocessor defines to configure the partition support.

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__sd__raw.html b/final_project/sd_reader/doc/html/group__sd__raw.html new file mode 100644 index 0000000..ee8dace --- /dev/null +++ b/final_project/sd_reader/doc/html/group__sd__raw.html @@ -0,0 +1,465 @@ + + + + + +sd-reader: MMC/SD/SDHC card raw access + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
MMC/SD/SDHC card raw access
+
+
+ +

This module implements read and write access to MMC, SD and SDHC cards. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  sd_raw_info
 This struct is used by sd_raw_get_info() to return manufacturing and status information of the card. More...

+Modules

 MMC/SD configuration
 

Preprocessor defines to configure the MMC/SD support.

+

+Files

file  sd_raw.c
 

MMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1)

+
file  sd_raw.h
 

MMC/SD/SDHC raw access header (license: GPLv2 or LGPLv2.1)

+
file  sd_raw_config.h
 

MMC/SD support configuration (license: GPLv2 or LGPLv2.1)

+

+Defines

+#define SD_RAW_FORMAT_HARDDISK
 The card's layout is harddisk-like, which means it contains a master boot record with a partition table.
+#define SD_RAW_FORMAT_SUPERFLOPPY
 The card contains a single filesystem and no partition table.
+#define SD_RAW_FORMAT_UNIVERSAL
 The card's layout follows the Universal File Format.
+#define SD_RAW_FORMAT_UNKNOWN
 The card's layout is unknown.

+Functions

uint8_t sd_raw_init ()
 Initializes memory card communication.
uint8_t sd_raw_available ()
 Checks wether a memory card is located in the slot.
uint8_t sd_raw_locked ()
 Checks wether the memory card is locked for write access.
uint8_t sd_raw_read (offset_t offset, uint8_t *buffer, uintptr_t length)
 Reads raw data from the card.
uint8_t sd_raw_read_interval (offset_t offset, uint8_t *buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void *p)
 Continuously reads units of interval bytes and calls a callback function.
uint8_t sd_raw_write (offset_t offset, const uint8_t *buffer, uintptr_t length)
 Writes raw data to the card.
uint8_t sd_raw_write_interval (offset_t offset, uint8_t *buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void *p)
 Writes a continuous data stream obtained from a callback function.
uint8_t sd_raw_sync ()
 Writes the write buffer's content to the card.
uint8_t sd_raw_get_info (struct sd_raw_info *info)
 Reads informational data from the card.
+

Detailed Description

+

This module implements read and write access to MMC, SD and SDHC cards.

+

It serves as a low-level driver for the higher level modules such as partition and file system access.

+

Function Documentation

+ +
+
+ + + + + + + +
uint8_t sd_raw_available ()
+
+
+ +

Checks wether a memory card is located in the slot.

+
Returns:
1 if the card is available, 0 if it is not.
+ +
+
+ +
+
+ + + + + + + + +
uint8_t sd_raw_get_info (struct sd_raw_infoinfo)
+
+
+ +

Reads informational data from the card.

+

This function reads and returns the card's registers containing manufacturing and status information.

+
Note:
: The information retrieved by this function is not required in any way to operate on the card, but it might be nice to display some of the data to the user.
+
Parameters:
+ + +
[in]infoA pointer to the structure into which to save the information.
+
+
+
Returns:
0 on failure, 1 on success.
+ +
+
+ +
+
+ + + + + + + +
uint8_t sd_raw_init ()
+
+
+ +

Initializes memory card communication.

+
Returns:
0 on failure, 1 on success.
+ +
+
+ +
+
+ + + + + + + +
uint8_t sd_raw_locked ()
+
+
+ +

Checks wether the memory card is locked for write access.

+
Returns:
1 if the card is locked, 0 if it is not.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t sd_raw_read (offset_t offset,
uint8_t * buffer,
uintptr_t length 
)
+
+
+ +

Reads raw data from the card.

+
Parameters:
+ + + + +
[in]offsetThe offset from which to read.
[out]bufferThe buffer into which to write the data.
[in]lengthThe number of bytes to read.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
sd_raw_read_interval, sd_raw_write, sd_raw_write_interval
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t sd_raw_read_interval (offset_t offset,
uint8_t * buffer,
uintptr_t interval,
uintptr_t length,
sd_raw_read_interval_handler_t callback,
void * p 
)
+
+
+ +

Continuously reads units of interval bytes and calls a callback function.

+

This function starts reading at the specified offset. Every interval bytes, it calls the callback function with the associated data buffer.

+

By returning zero, the callback may stop reading.

+
Note:
Within the callback function, you can not start another read or write operation.
+
+This function only works if the following conditions are met:
    +
  • (offset - (offset % 512)) % interval == 0
  • +
  • length % interval == 0
  • +
+
+
Parameters:
+ + + + + + + +
[in]offsetOffset from which to start reading.
[in]bufferPointer to a buffer which is at least interval bytes in size.
[in]intervalNumber of bytes to read before calling the callback function.
[in]lengthNumber of bytes to read altogether.
[in]callbackThe function to call every interval bytes.
[in]pAn opaque pointer directly passed to the callback function.
+
+
+
Returns:
0 on failure, 1 on success
+
See also:
sd_raw_write_interval, sd_raw_read, sd_raw_write
+ +
+
+ +
+
+ + + + + + + +
uint8_t sd_raw_sync ()
+
+
+ +

Writes the write buffer's content to the card.

+
Note:
When write buffering is enabled, you should call this function before disconnecting the card to ensure all remaining data has been written.
+
Returns:
0 on failure, 1 on success.
+
See also:
sd_raw_write
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t sd_raw_write (offset_t offset,
const uint8_t * buffer,
uintptr_t length 
)
+
+
+ +

Writes raw data to the card.

+
Note:
If write buffering is enabled, you might have to call sd_raw_sync() before disconnecting the card to ensure all remaining data has been written.
+
Parameters:
+ + + + +
[in]offsetThe offset where to start writing.
[in]bufferThe buffer containing the data to be written.
[in]lengthThe number of bytes to write.
+
+
+
Returns:
0 on failure, 1 on success.
+
See also:
sd_raw_write_interval, sd_raw_read, sd_raw_read_interval
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
uint8_t sd_raw_write_interval (offset_t offset,
uint8_t * buffer,
uintptr_t length,
sd_raw_write_interval_handler_t callback,
void * p 
)
+
+
+ +

Writes a continuous data stream obtained from a callback function.

+

This function starts writing at the specified offset. To obtain the next bytes to write, it calls the callback function. The callback fills the provided data buffer and returns the number of bytes it has put into the buffer.

+

By returning zero, the callback may stop writing.

+
Parameters:
+ + + + + + +
[in]offsetOffset where to start writing.
[in]bufferPointer to a buffer which is used for the callback function.
[in]lengthNumber of bytes to write in total. May be zero for endless writes.
[in]callbackThe function used to obtain the bytes to write.
[in]pAn opaque pointer directly passed to the callback function.
+
+
+
Returns:
0 on failure, 1 on success
+
See also:
sd_raw_read_interval, sd_raw_write, sd_raw_read
+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/group__sd__raw__config.html b/final_project/sd_reader/doc/html/group__sd__raw__config.html new file mode 100644 index 0000000..2d3ebef --- /dev/null +++ b/final_project/sd_reader/doc/html/group__sd__raw__config.html @@ -0,0 +1,168 @@ + + + + + +sd-reader: MMC/SD configuration + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+ +
+
MMC/SD configuration
+
+
+ +

Preprocessor defines to configure the MMC/SD support. +More...

+ + + + + + + + + + + + +

+Defines

#define SD_RAW_WRITE_SUPPORT
 Controls MMC/SD write support.
#define SD_RAW_WRITE_BUFFERING
 Controls MMC/SD write buffering.
#define SD_RAW_SAVE_RAM
 Controls MMC/SD access buffering.
#define SD_RAW_SAVE_RAM
 Controls MMC/SD access buffering.
#define SD_RAW_SDHC
 Controls support for SDHC cards.
+

Detailed Description

+

Preprocessor defines to configure the MMC/SD support.

+

Define Documentation

+ +
+
+ + + + +
#define SD_RAW_SAVE_RAM
+
+
+ +

Controls MMC/SD access buffering.

+

Set to 1 to save static RAM, but be aware that you will lose performance.

+
Note:
When SD_RAW_WRITE_SUPPORT is 1, SD_RAW_SAVE_RAM will be reset to 0.
+ +
+
+ +
+
+ + + + +
#define SD_RAW_SAVE_RAM
+
+
+ +

Controls MMC/SD access buffering.

+

Set to 1 to save static RAM, but be aware that you will lose performance.

+
Note:
When SD_RAW_WRITE_SUPPORT is 1, SD_RAW_SAVE_RAM will be reset to 0.
+ +
+
+ +
+
+ + + + +
#define SD_RAW_SDHC
+
+
+ +

Controls support for SDHC cards.

+

Set to 1 to support so-called SDHC memory cards, i.e. SD cards with more than 2 gigabytes of memory.

+ +
+
+ +
+
+ + + + +
#define SD_RAW_WRITE_BUFFERING
+
+
+ +

Controls MMC/SD write buffering.

+

Set to 1 to buffer write accesses, set to 0 to disable it.

+
Note:
This option has no effect when SD_RAW_WRITE_SUPPORT is 0.
+ +
+
+ +
+
+ + + + +
#define SD_RAW_WRITE_SUPPORT
+
+
+ +

Controls MMC/SD write support.

+

Set to 1 to enable MMC/SD write support, set to 0 to disable it.

+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/index.html b/final_project/sd_reader/doc/html/index.html new file mode 100644 index 0000000..4881aa0 --- /dev/null +++ b/final_project/sd_reader/doc/html/index.html @@ -0,0 +1,210 @@ + + + + + +sd-reader: MMC/SD/SDHC card library + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+
+
MMC/SD/SDHC card library
+
+
+

This project provides a general purpose library which implements read and write support for MMC, SD and SDHC memory cards. It includes

+ +

+The circuit

+

The circuit which was mainly used during development consists of an Atmel AVR microcontroller with some passive components. It is quite simple and provides an easy test environment. The circuit which can be downloaded on the project homepage has been improved with regard to operation stability.

+

I used different microcontrollers during development, the ATmega8 with 8kBytes of flash, and its pin-compatible alternative, the ATmega168 with 16kBytes flash. The first one is the one I started with, but when I implemented FAT16 write support, I ran out of flash space and switched to the ATmega168. For FAT32, an ATmega328 is required.

+

The circuit board is a self-made and self-soldered board consisting of a single copper layer and standard DIL components, except of the MMC/SD card connector.

+

The connector is soldered to the bottom side of the board. It has a simple eject button which, when a card is inserted, needs some space beyond the connector itself. As an additional feature the connector has two electrical switches to detect wether a card is inserted and wether this card is write-protected.

+

+Pictures

+
+pic01.jpg +
+The circuit board used to implement and test this application.
+
+pic02.jpg +
+The MMC/SD card connector on the soldering side of the circuit board.
+

+The software

+

The software is written in C (ISO C99). It might not be the smallest or the fastest one, but I think it is quite flexible. See the project's benchmark page to get an idea of the possible data rates.

+

I implemented an example application providing a simple command prompt which is accessible via the UART at 9600 Baud. With commands similiar to the Unix shell you can browse different directories, read and write files, create new ones and delete them again. Not all commands are available in all software configurations.

+
    +
  • cat <file>
    + Writes a hexdump of <file> to the terminal.
  • +
  • cd <directory>
    + Changes current working directory to <directory>.
  • +
  • disk
    + Shows card manufacturer, status, filesystem capacity and free storage space.
  • +
  • init
    + Reinitializes and reopens the memory card.
  • +
  • ls
    + Shows the content of the current directory.
  • +
  • mkdir <directory>
    + Creates a directory called <directory>.
  • +
  • mv <file> <file_new>
    + Renames <file> to <file_new>.
  • +
  • rm <file>
    + Deletes <file>.
  • +
  • sync
    + Ensures all buffered data is written to the card.
  • +
  • touch <file>
    + Creates <file>.
  • +
  • write <file> <offset>
    + Writes text to <file>, starting from <offset>. The text is read from the UART, line by line. Finish with an empty line.
  • +
+ +

+ The following table shows some typical code sizes in bytes, using the 20090330 release with a + buffered read-write MMC/SD configuration, FAT16 and static memory allocation: +

+ + + + + + + + + + + + + + + + + + + + + + +
layercode sizestatic RAM usage
MMC/SD2410518
Partition45617
FAT167928188
+ +

+ The static RAM is mostly used for buffering memory card access, which + improves performance and reduces implementation complexity. +

+ +

+ Please note that the numbers above do not include the C library functions + used, e.g. some string functions. These will raise the numbers somewhat + if they are not already used in other program parts. +

+ +

+ When opening a partition, filesystem, file or directory, a little amount + of RAM is used, as listed in the following table. Depending on the library + configuration, the memory is either allocated statically or dynamically. +

+ + + + + + + + + + + + + + + + + + + + + + +
descriptordynamic/static RAM
partition17
filesystem26
file53
directory49
+ +

+Adapting the software to your needs

+

The only hardware dependent part is the communication layer talking to the memory card. The other parts like partition table and FAT support are completely independent, you could use them even for managing Compact Flash cards or standard ATAPI hard disks.

+

By changing the MCU* variables in the Makefile, you can use other Atmel microcontrollers or different clock speeds. You might also want to change the configuration defines in the files fat_config.h, partition_config.h, sd_raw_config.h and sd-reader_config.h. For example, you could disable write support completely if you only need read support.

+

For further information, visit the project's FAQ page.

+

+Bugs or comments?

+

If you have comments or found a bug in the software - there might be some of them - you may contact me per mail at feedback@roland-riegel.de.

+

+Acknowledgements

+

Thanks go to Ulrich Radig, who explained on his homepage how to interface MMC cards to the Atmel microcontroller (http://www.ulrichradig.de/). I adapted his work for my circuit.

+

+Copyright 2006-2012 by Roland Riegel

+

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation (http://www.gnu.org/copyleft/gpl.html). At your option, you can alternatively redistribute and/or modify the following files under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation (http://www.gnu.org/copyleft/lgpl.html):

+ +
+ + + + + + diff --git a/final_project/sd_reader/doc/html/modules.html b/final_project/sd_reader/doc/html/modules.html new file mode 100644 index 0000000..977ea81 --- /dev/null +++ b/final_project/sd_reader/doc/html/modules.html @@ -0,0 +1,82 @@ + + + + + +sd-reader: Modules + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + +
+
+
+
Modules
+
+ + + + + + + diff --git a/final_project/sd_reader/doc/html/nav_f.png b/final_project/sd_reader/doc/html/nav_f.png new file mode 100644 index 0000000..1b07a16 Binary files /dev/null and b/final_project/sd_reader/doc/html/nav_f.png differ diff --git a/final_project/sd_reader/doc/html/nav_h.png b/final_project/sd_reader/doc/html/nav_h.png new file mode 100644 index 0000000..01f5fa6 Binary files /dev/null and b/final_project/sd_reader/doc/html/nav_h.png differ diff --git a/final_project/sd_reader/doc/html/open.png b/final_project/sd_reader/doc/html/open.png new file mode 100644 index 0000000..7b35d2c Binary files /dev/null and b/final_project/sd_reader/doc/html/open.png differ diff --git a/final_project/sd_reader/doc/html/partition_8c.html b/final_project/sd_reader/doc/html/partition_8c.html new file mode 100644 index 0000000..783028d --- /dev/null +++ b/final_project/sd_reader/doc/html/partition_8c.html @@ -0,0 +1,85 @@ + + + + + +sd-reader: partition.c File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
partition.c File Reference
+
+
+ +

Partition table implementation (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + +

+Functions

struct partition_structpartition_open (device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index)
 Opens a partition.
uint8_t partition_close (struct partition_struct *partition)
 Closes a partition.
+

Detailed Description

+

Partition table implementation (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/partition_8h.html b/final_project/sd_reader/doc/html/partition_8h.html new file mode 100644 index 0000000..9f3380c --- /dev/null +++ b/final_project/sd_reader/doc/html/partition_8h.html @@ -0,0 +1,138 @@ + + + + + +sd-reader: partition.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
partition.h File Reference
+
+
+ +

Partition table header (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  partition_struct
 Describes a partition. More...

+Defines

+#define PARTITION_TYPE_FREE
 The partition table entry is not used.
+#define PARTITION_TYPE_FAT12
 The partition contains a FAT12 filesystem.
+#define PARTITION_TYPE_FAT16_32MB
 The partition contains a FAT16 filesystem with 32MB maximum.
+#define PARTITION_TYPE_EXTENDED
 The partition is an extended partition with its own partition table.
+#define PARTITION_TYPE_FAT16
 The partition contains a FAT16 filesystem.
+#define PARTITION_TYPE_FAT32
 The partition contains a FAT32 filesystem.
+#define PARTITION_TYPE_FAT32_LBA
 The partition contains a FAT32 filesystem with LBA.
+#define PARTITION_TYPE_FAT16_LBA
 The partition contains a FAT16 filesystem with LBA.
+#define PARTITION_TYPE_EXTENDED_LBA
 The partition is an extended partition with LBA.
+#define PARTITION_TYPE_UNKNOWN
 The partition has an unknown type.

+Typedefs

typedef uint8_t(* device_read_t )(offset_t offset, uint8_t *buffer, uintptr_t length)
 A function pointer used to read from the partition.
typedef uint8_t(* device_read_callback_t )(uint8_t *buffer, offset_t offset, void *p)
 A function pointer passed to a device_read_interval_t.
typedef uint8_t(* device_read_interval_t )(offset_t offset, uint8_t *buffer, uintptr_t interval, uintptr_t length, device_read_callback_t callback, void *p)
 A function pointer used to continuously read units of interval bytes and call a callback function.
typedef uint8_t(* device_write_t )(offset_t offset, const uint8_t *buffer, uintptr_t length)
 A function pointer used to write to the partition.
typedef uintptr_t(* device_write_callback_t )(uint8_t *buffer, offset_t offset, void *p)
 A function pointer passed to a device_write_interval_t.
typedef uint8_t(* device_write_interval_t )(offset_t offset, uint8_t *buffer, uintptr_t length, device_write_callback_t callback, void *p)
 A function pointer used to continuously write a data stream obtained from a callback function.

+Functions

struct partition_structpartition_open (device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index)
 Opens a partition.
uint8_t partition_close (struct partition_struct *partition)
 Closes a partition.
+

Detailed Description

+

Partition table header (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/partition__config_8h.html b/final_project/sd_reader/doc/html/partition__config_8h.html new file mode 100644 index 0000000..b1fbf70 --- /dev/null +++ b/final_project/sd_reader/doc/html/partition__config_8h.html @@ -0,0 +1,83 @@ + + + + + +sd-reader: partition_config.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
partition_config.h File Reference
+
+
+ +

Partition configuration (license: GPLv2 or LGPLv2.1) +More...

+ + + + +

+Defines

+#define PARTITION_COUNT
 Maximum number of partition handles.
+

Detailed Description

+

Partition configuration (license: GPLv2 or LGPLv2.1)

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/pic01.jpg b/final_project/sd_reader/doc/html/pic01.jpg new file mode 100644 index 0000000..7eb9383 Binary files /dev/null and b/final_project/sd_reader/doc/html/pic01.jpg differ diff --git a/final_project/sd_reader/doc/html/pic02.jpg b/final_project/sd_reader/doc/html/pic02.jpg new file mode 100644 index 0000000..e490c4d Binary files /dev/null and b/final_project/sd_reader/doc/html/pic02.jpg differ diff --git a/final_project/sd_reader/doc/html/sd-reader__config_8h.html b/final_project/sd_reader/doc/html/sd-reader__config_8h.html new file mode 100644 index 0000000..a751d18 --- /dev/null +++ b/final_project/sd_reader/doc/html/sd-reader__config_8h.html @@ -0,0 +1,83 @@ + + + + + +sd-reader: sd-reader_config.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
sd-reader_config.h File Reference
+
+
+ +

Common sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1) +More...

+ + + + +

+Defines

#define USE_DYNAMIC_MEMORY
 Controls allocation of memory.
+

Detailed Description

+

Common sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1)

+
Note:
This file contains only configuration items relevant to all sd-reader implementation files. For module specific configuration options, please see the files fat_config.h, partition_config.h and sd_raw_config.h.
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/sd__raw_8c.html b/final_project/sd_reader/doc/html/sd__raw_8c.html new file mode 100644 index 0000000..03b1888 --- /dev/null +++ b/final_project/sd_reader/doc/html/sd__raw_8c.html @@ -0,0 +1,99 @@ + + + + + +sd-reader: sd_raw.c File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
sd_raw.c File Reference
+
+
+ +

MMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + +

+Functions

uint8_t sd_raw_init ()
 Initializes memory card communication.
uint8_t sd_raw_available ()
 Checks wether a memory card is located in the slot.
uint8_t sd_raw_locked ()
 Checks wether the memory card is locked for write access.
uint8_t sd_raw_read (offset_t offset, uint8_t *buffer, uintptr_t length)
 Reads raw data from the card.
uint8_t sd_raw_read_interval (offset_t offset, uint8_t *buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void *p)
 Continuously reads units of interval bytes and calls a callback function.
uint8_t sd_raw_write (offset_t offset, const uint8_t *buffer, uintptr_t length)
 Writes raw data to the card.
uint8_t sd_raw_write_interval (offset_t offset, uint8_t *buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void *p)
 Writes a continuous data stream obtained from a callback function.
uint8_t sd_raw_sync ()
 Writes the write buffer's content to the card.
uint8_t sd_raw_get_info (struct sd_raw_info *info)
 Reads informational data from the card.
+

Detailed Description

+

MMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/sd__raw_8h.html b/final_project/sd_reader/doc/html/sd__raw_8h.html new file mode 100644 index 0000000..701d9d8 --- /dev/null +++ b/final_project/sd_reader/doc/html/sd__raw_8h.html @@ -0,0 +1,119 @@ + + + + + +sd-reader: sd_raw.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
sd_raw.h File Reference
+
+
+ +

MMC/SD/SDHC raw access header (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Structures

struct  sd_raw_info
 This struct is used by sd_raw_get_info() to return manufacturing and status information of the card. More...

+Defines

+#define SD_RAW_FORMAT_HARDDISK
 The card's layout is harddisk-like, which means it contains a master boot record with a partition table.
+#define SD_RAW_FORMAT_SUPERFLOPPY
 The card contains a single filesystem and no partition table.
+#define SD_RAW_FORMAT_UNIVERSAL
 The card's layout follows the Universal File Format.
+#define SD_RAW_FORMAT_UNKNOWN
 The card's layout is unknown.

+Functions

uint8_t sd_raw_init ()
 Initializes memory card communication.
uint8_t sd_raw_available ()
 Checks wether a memory card is located in the slot.
uint8_t sd_raw_locked ()
 Checks wether the memory card is locked for write access.
uint8_t sd_raw_read (offset_t offset, uint8_t *buffer, uintptr_t length)
 Reads raw data from the card.
uint8_t sd_raw_read_interval (offset_t offset, uint8_t *buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void *p)
 Continuously reads units of interval bytes and calls a callback function.
uint8_t sd_raw_write (offset_t offset, const uint8_t *buffer, uintptr_t length)
 Writes raw data to the card.
uint8_t sd_raw_write_interval (offset_t offset, uint8_t *buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void *p)
 Writes a continuous data stream obtained from a callback function.
uint8_t sd_raw_sync ()
 Writes the write buffer's content to the card.
uint8_t sd_raw_get_info (struct sd_raw_info *info)
 Reads informational data from the card.
+

Detailed Description

+

MMC/SD/SDHC raw access header (license: GPLv2 or LGPLv2.1)

+
Author:
Roland Riegel
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/sd__raw__config_8h.html b/final_project/sd_reader/doc/html/sd__raw__config_8h.html new file mode 100644 index 0000000..e382d00 --- /dev/null +++ b/final_project/sd_reader/doc/html/sd__raw__config_8h.html @@ -0,0 +1,90 @@ + + + + + +sd-reader: sd_raw_config.h File Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
sd_raw_config.h File Reference
+
+
+ +

MMC/SD support configuration (license: GPLv2 or LGPLv2.1) +More...

+ + + + + + + + + + + + +

+Defines

#define SD_RAW_WRITE_SUPPORT
 Controls MMC/SD write support.
#define SD_RAW_WRITE_BUFFERING
 Controls MMC/SD write buffering.
#define SD_RAW_SAVE_RAM
 Controls MMC/SD access buffering.
#define SD_RAW_SDHC
 Controls support for SDHC cards.
#define SD_RAW_SAVE_RAM
 Controls MMC/SD access buffering.
+

Detailed Description

+

MMC/SD support configuration (license: GPLv2 or LGPLv2.1)

+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/structfat__dir__entry__struct.html b/final_project/sd_reader/doc/html/structfat__dir__entry__struct.html new file mode 100644 index 0000000..e659a70 --- /dev/null +++ b/final_project/sd_reader/doc/html/structfat__dir__entry__struct.html @@ -0,0 +1,167 @@ + + + + + +sd-reader: fat_dir_entry_struct Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
fat_dir_entry_struct Struct Reference
+
+
+ +

Describes a directory entry. + More...

+ + + + + + + + + + + + +

+Data Fields

char long_name [32]
 The file's name, truncated to 31 characters.
uint8_t attributes
 The file's attributes.
cluster_t cluster
 The cluster in which the file's first byte resides.
uint32_t file_size
 The file's size.
offset_t entry_offset
 The total disk offset of this directory entry.
+

Detailed Description

+

Describes a directory entry.

+

Field Documentation

+ +
+ +
+ +

The file's attributes.

+

Mask of the FAT_ATTRIB_* constants.

+ +
+
+ +
+
+ + + + +
cluster_t fat_dir_entry_struct::cluster
+
+
+ +

The cluster in which the file's first byte resides.

+ +
+
+ +
+ +
+ +

The total disk offset of this directory entry.

+ +
+
+ +
+
+ + + + +
uint32_t fat_dir_entry_struct::file_size
+
+
+ +

The file's size.

+ +
+
+ +
+
+ + + + +
char fat_dir_entry_struct::long_name[32]
+
+
+ +

The file's name, truncated to 31 characters.

+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/structpartition__struct.html b/final_project/sd_reader/doc/html/structpartition__struct.html new file mode 100644 index 0000000..06c8df2 --- /dev/null +++ b/final_project/sd_reader/doc/html/structpartition__struct.html @@ -0,0 +1,177 @@ + + + + + +sd-reader: partition_struct Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
partition_struct Struct Reference
+
+
+ +

Describes a partition. + More...

+ + + + + + + + + + + + + + + + +

+Data Fields

device_read_t device_read
 The function which reads data from the partition.
device_read_interval_t device_read_interval
 The function which repeatedly reads a constant amount of data from the partition.
device_write_t device_write
 The function which writes data to the partition.
device_write_interval_t device_write_interval
 The function which repeatedly writes data to the partition.
uint8_t type
 The type of the partition.
+uint32_t offset
 The offset in blocks on the disk where this partition starts.
+uint32_t length
 The length in blocks of this partition.
+

Detailed Description

+

Describes a partition.

+

Field Documentation

+ +
+ +
+ +

The function which reads data from the partition.

+
Note:
The offset given to this function is relative to the whole disk, not to the start of the partition.
+ +
+
+ +
+ +
+ +

The function which repeatedly reads a constant amount of data from the partition.

+
Note:
The offset given to this function is relative to the whole disk, not to the start of the partition.
+ +
+
+ +
+ +
+ +

The function which writes data to the partition.

+
Note:
The offset given to this function is relative to the whole disk, not to the start of the partition.
+ +
+
+ +
+ +
+ +

The function which repeatedly writes data to the partition.

+
Note:
The offset given to this function is relative to the whole disk, not to the start of the partition.
+ +
+
+ +
+
+ + + + +
uint8_t partition_struct::type
+
+
+ +

The type of the partition.

+

Compare this value to the PARTITION_TYPE_* constants.

+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/structsd__raw__info.html b/final_project/sd_reader/doc/html/structsd__raw__info.html new file mode 100644 index 0000000..014718b --- /dev/null +++ b/final_project/sd_reader/doc/html/structsd__raw__info.html @@ -0,0 +1,208 @@ + + + + + +sd-reader: sd_raw_info Struct Reference + + + + + + + + +
+ + +
+ + + + + + + + + + + +
+
sd-reader + +
+ +
+
+ + + + +
+
+ +
+
sd_raw_info Struct Reference
+
+
+ +

This struct is used by sd_raw_get_info() to return manufacturing and status information of the card. + More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+Data Fields

+uint8_t manufacturer
 A manufacturer code globally assigned by the SD card organization.
+uint8_t oem [3]
 A string describing the card's OEM or content, globally assigned by the SD card organization.
+uint8_t product [6]
 A product name.
uint8_t revision
 The card's revision, coded in packed BCD.
+uint32_t serial
 A serial number assigned by the manufacturer.
uint8_t manufacturing_year
 The year of manufacturing.
+uint8_t manufacturing_month
 The month of manufacturing.
+offset_t capacity
 The card's total capacity in bytes.
uint8_t flag_copy
 Defines wether the card's content is original or copied.
uint8_t flag_write_protect
 Defines wether the card's content is write-protected.
uint8_t flag_write_protect_temp
 Defines wether the card's content is temporarily write-protected.
uint8_t format
 The card's data layout.
+

Detailed Description

+

This struct is used by sd_raw_get_info() to return manufacturing and status information of the card.

+

Field Documentation

+ +
+
+ + + + +
uint8_t sd_raw_info::flag_copy
+
+
+ +

Defines wether the card's content is original or copied.

+

A value of 0 means original, 1 means copied.

+ +
+
+ +
+
+ + + + +
uint8_t sd_raw_info::flag_write_protect
+
+
+ +

Defines wether the card's content is write-protected.

+
Note:
This is an internal flag and does not represent the state of the card's mechanical write-protect switch.
+ +
+
+ +
+ +
+ +

Defines wether the card's content is temporarily write-protected.

+
Note:
This is an internal flag and does not represent the state of the card's mechanical write-protect switch.
+ +
+
+ +
+
+ + + + +
uint8_t sd_raw_info::format
+
+
+ +

The card's data layout.

+

See the SD_RAW_FORMAT_* constants for details.

+
Note:
This value is not guaranteed to match reality.
+ +
+
+ +
+
+ + + + +
uint8_t sd_raw_info::manufacturing_year
+
+
+ +

The year of manufacturing.

+

A value of zero means year 2000.

+ +
+
+ +
+
+ + + + +
uint8_t sd_raw_info::revision
+
+
+ +

The card's revision, coded in packed BCD.

+

For example, the revision value 0x32 means "3.2".

+ +
+
+
+ + + + + + diff --git a/final_project/sd_reader/doc/html/tab_a.png b/final_project/sd_reader/doc/html/tab_a.png new file mode 100644 index 0000000..2d99ef2 Binary files /dev/null and b/final_project/sd_reader/doc/html/tab_a.png differ diff --git a/final_project/sd_reader/doc/html/tab_b.png b/final_project/sd_reader/doc/html/tab_b.png new file mode 100644 index 0000000..b2c3d2b Binary files /dev/null and b/final_project/sd_reader/doc/html/tab_b.png differ diff --git a/final_project/sd_reader/doc/html/tab_h.png b/final_project/sd_reader/doc/html/tab_h.png new file mode 100644 index 0000000..c11f48f Binary files /dev/null and b/final_project/sd_reader/doc/html/tab_h.png differ diff --git a/final_project/sd_reader/doc/html/tab_s.png b/final_project/sd_reader/doc/html/tab_s.png new file mode 100644 index 0000000..978943a Binary files /dev/null and b/final_project/sd_reader/doc/html/tab_s.png differ diff --git a/final_project/sd_reader/doc/html/tabs.css b/final_project/sd_reader/doc/html/tabs.css new file mode 100644 index 0000000..2192056 --- /dev/null +++ b/final_project/sd_reader/doc/html/tabs.css @@ -0,0 +1,59 @@ +.tabs, .tabs2, .tabs3 { + background-image: url('tab_b.png'); + width: 100%; + z-index: 101; + font-size: 13px; +} + +.tabs2 { + font-size: 10px; +} +.tabs3 { + font-size: 9px; +} + +.tablist { + margin: 0; + padding: 0; + display: table; +} + +.tablist li { + float: left; + display: table-cell; + background-image: url('tab_b.png'); + line-height: 36px; + list-style: none; +} + +.tablist a { + display: block; + padding: 0 20px; + font-weight: bold; + background-image:url('tab_s.png'); + background-repeat:no-repeat; + background-position:right; + color: #283A5D; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; + outline: none; +} + +.tabs3 .tablist a { + padding: 0 10px; +} + +.tablist a:hover { + background-image: url('tab_h.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); + text-decoration: none; +} + +.tablist li.current a { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} diff --git a/final_project/sd_reader/doc/pic01.jpg b/final_project/sd_reader/doc/pic01.jpg new file mode 100644 index 0000000..7eb9383 Binary files /dev/null and b/final_project/sd_reader/doc/pic01.jpg differ diff --git a/final_project/sd_reader/doc/pic02.jpg b/final_project/sd_reader/doc/pic02.jpg new file mode 100644 index 0000000..e490c4d Binary files /dev/null and b/final_project/sd_reader/doc/pic02.jpg differ diff --git a/final_project/sd_reader/fat.c b/final_project/sd_reader/fat.c new file mode 100644 index 0000000..e62f4cf --- /dev/null +++ b/final_project/sd_reader/fat.c @@ -0,0 +1,2551 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "byteordering.h" +#include "partition.h" +#include "fat.h" +#include "fat_config.h" +#include "sd-reader_config.h" + +#include + +#if USE_DYNAMIC_MEMORY + #include +#endif + +/** + * \addtogroup fat FAT support + * + * This module implements FAT16/FAT32 read and write access. + * + * The following features are supported: + * - File names up to 31 characters long. + * - Unlimited depth of subdirectories. + * - Short 8.3 and long filenames. + * - Creating and deleting files. + * - Reading and writing from and to files. + * - File resizing. + * - File sizes of up to 4 gigabytes. + * + * @{ + */ +/** + * \file + * FAT implementation (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +/** + * \addtogroup fat_config FAT configuration + * Preprocessor defines to configure the FAT implementation. + */ + +/** + * \addtogroup fat_fs FAT access + * Basic functions for handling a FAT filesystem. + */ + +/** + * \addtogroup fat_file FAT file functions + * Functions for managing files. + */ + +/** + * \addtogroup fat_dir FAT directory functions + * Functions for managing directories. + */ + +/** + * @} + */ + +#define FAT16_CLUSTER_FREE 0x0000 +#define FAT16_CLUSTER_RESERVED_MIN 0xfff0 +#define FAT16_CLUSTER_RESERVED_MAX 0xfff6 +#define FAT16_CLUSTER_BAD 0xfff7 +#define FAT16_CLUSTER_LAST_MIN 0xfff8 +#define FAT16_CLUSTER_LAST_MAX 0xffff + +#define FAT32_CLUSTER_FREE 0x00000000 +#define FAT32_CLUSTER_RESERVED_MIN 0x0ffffff0 +#define FAT32_CLUSTER_RESERVED_MAX 0x0ffffff6 +#define FAT32_CLUSTER_BAD 0x0ffffff7 +#define FAT32_CLUSTER_LAST_MIN 0x0ffffff8 +#define FAT32_CLUSTER_LAST_MAX 0x0fffffff + +#define FAT_DIRENTRY_DELETED 0xe5 +#define FAT_DIRENTRY_LFNLAST (1 << 6) +#define FAT_DIRENTRY_LFNSEQMASK ((1 << 6) - 1) + +/* Each entry within the directory table has a size of 32 bytes + * and either contains a 8.3 DOS-style file name or a part of a + * long file name, which may consist of several directory table + * entries at once. + * + * multi-byte integer values are stored little-endian! + * + * 8.3 file name entry: + * ==================== + * offset length description + * 0 8 name (space padded) + * 8 3 extension (space padded) + * 11 1 attributes (FAT_ATTRIB_*) + * + * long file name (lfn) entry ordering for a single file name: + * =========================================================== + * LFN entry n + * ... + * LFN entry 2 + * LFN entry 1 + * 8.3 entry (see above) + * + * lfn entry: + * ========== + * offset length description + * 0 1 ordinal field + * 1 2 unicode character 1 + * 3 3 unicode character 2 + * 5 3 unicode character 3 + * 7 3 unicode character 4 + * 9 3 unicode character 5 + * 11 1 attribute (always 0x0f) + * 12 1 type (reserved, always 0) + * 13 1 checksum + * 14 2 unicode character 6 + * 16 2 unicode character 7 + * 18 2 unicode character 8 + * 20 2 unicode character 9 + * 22 2 unicode character 10 + * 24 2 unicode character 11 + * 26 2 cluster (unused, always 0) + * 28 2 unicode character 12 + * 30 2 unicode character 13 + * + * The ordinal field contains a descending number, from n to 1. + * For the n'th lfn entry the ordinal field is or'ed with 0x40. + * For deleted lfn entries, the ordinal field is set to 0xe5. + */ + +struct fat_header_struct +{ + offset_t size; + + offset_t fat_offset; + uint32_t fat_size; + + uint16_t sector_size; + uint16_t cluster_size; + + offset_t cluster_zero_offset; + + offset_t root_dir_offset; +#if FAT_FAT32_SUPPORT + cluster_t root_dir_cluster; +#endif +}; + +struct fat_fs_struct +{ + struct partition_struct* partition; + struct fat_header_struct header; + cluster_t cluster_free; +}; + +struct fat_file_struct +{ + struct fat_fs_struct* fs; + struct fat_dir_entry_struct dir_entry; + offset_t pos; + cluster_t pos_cluster; +}; + +struct fat_dir_struct +{ + struct fat_fs_struct* fs; + struct fat_dir_entry_struct dir_entry; + cluster_t entry_cluster; + uint16_t entry_offset; +}; + +struct fat_read_dir_callback_arg +{ + struct fat_dir_entry_struct* dir_entry; + uintptr_t bytes_read; +#if FAT_LFN_SUPPORT + uint8_t checksum; +#endif + uint8_t finished; +}; + +struct fat_usage_count_callback_arg +{ + cluster_t cluster_count; + uintptr_t buffer_size; +}; + +#if !USE_DYNAMIC_MEMORY +static struct fat_fs_struct fat_fs_handles[FAT_FS_COUNT]; +static struct fat_file_struct fat_file_handles[FAT_FILE_COUNT]; +static struct fat_dir_struct fat_dir_handles[FAT_DIR_COUNT]; +#endif + +static uint8_t fat_read_header(struct fat_fs_struct* fs); +static cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num); +static offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num); +static uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p); +#if FAT_LFN_SUPPORT +static uint8_t fat_calc_83_checksum(const uint8_t* file_name_83); +#endif + +static uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p); +#if FAT_FAT32_SUPPORT +static uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p); +#endif + +#if FAT_WRITE_SUPPORT +static cluster_t fat_append_clusters(struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count); +static uint8_t fat_free_clusters(struct fat_fs_struct* fs, cluster_t cluster_num); +static uint8_t fat_terminate_clusters(struct fat_fs_struct* fs, cluster_t cluster_num); +static uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num); +static uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p); +static offset_t fat_find_offset_for_dir_entry(struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry); +static uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry); +#if FAT_DATETIME_SUPPORT +static void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day); +static void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec); +#endif +#endif + +/** + * \ingroup fat_fs + * Opens a FAT filesystem. + * + * \param[in] partition Discriptor of partition on which the filesystem resides. + * \returns 0 on error, a FAT filesystem descriptor on success. + * \see fat_close + */ +struct fat_fs_struct* fat_open(struct partition_struct* partition) +{ + if(!partition || +#if FAT_WRITE_SUPPORT + !partition->device_write || + !partition->device_write_interval +#else + 0 +#endif + ) + return 0; + +#if USE_DYNAMIC_MEMORY + struct fat_fs_struct* fs = malloc(sizeof(*fs)); + if(!fs) + return 0; +#else + struct fat_fs_struct* fs = fat_fs_handles; + uint8_t i; + for(i = 0; i < FAT_FS_COUNT; ++i) + { + if(!fs->partition) + break; + + ++fs; + } + if(i >= FAT_FS_COUNT) + return 0; +#endif + + memset(fs, 0, sizeof(*fs)); + + fs->partition = partition; + if(!fat_read_header(fs)) + { +#if USE_DYNAMIC_MEMORY + free(fs); +#else + fs->partition = 0; +#endif + return 0; + } + + return fs; +} + +/** + * \ingroup fat_fs + * Closes a FAT filesystem. + * + * When this function returns, the given filesystem descriptor + * will be invalid. + * + * \param[in] fs The filesystem to close. + * \see fat_open + */ +void fat_close(struct fat_fs_struct* fs) +{ + if(!fs) + return; + +#if USE_DYNAMIC_MEMORY + free(fs); +#else + fs->partition = 0; +#endif +} + +/** + * \ingroup fat_fs + * Reads and parses the header of a FAT filesystem. + * + * \param[in,out] fs The filesystem for which to parse the header. + * \returns 0 on failure, 1 on success. + */ +uint8_t fat_read_header(struct fat_fs_struct* fs) +{ + if(!fs) + return 0; + + struct partition_struct* partition = fs->partition; + if(!partition) + return 0; + + /* read fat parameters */ +#if FAT_FAT32_SUPPORT + uint8_t buffer[37]; +#else + uint8_t buffer[25]; +#endif + offset_t partition_offset = (offset_t) partition->offset * 512; + if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer))) + return 0; + + uint16_t bytes_per_sector = read16(&buffer[0x00]); + uint16_t reserved_sectors = read16(&buffer[0x03]); + uint8_t sectors_per_cluster = buffer[0x02]; + uint8_t fat_copies = buffer[0x05]; + uint16_t max_root_entries = read16(&buffer[0x06]); + uint16_t sector_count_16 = read16(&buffer[0x08]); + uint16_t sectors_per_fat = read16(&buffer[0x0b]); + uint32_t sector_count = read32(&buffer[0x15]); +#if FAT_FAT32_SUPPORT + uint32_t sectors_per_fat32 = read32(&buffer[0x19]); + uint32_t cluster_root_dir = read32(&buffer[0x21]); +#endif + + if(sector_count == 0) + { + if(sector_count_16 == 0) + /* illegal volume size */ + return 0; + else + sector_count = sector_count_16; + } +#if FAT_FAT32_SUPPORT + if(sectors_per_fat != 0) + sectors_per_fat32 = sectors_per_fat; + else if(sectors_per_fat32 == 0) + /* this is neither FAT16 nor FAT32 */ + return 0; +#else + if(sectors_per_fat == 0) + /* this is not a FAT16 */ + return 0; +#endif + + /* determine the type of FAT we have here */ + uint32_t data_sector_count = sector_count + - reserved_sectors +#if FAT_FAT32_SUPPORT + - sectors_per_fat32 * fat_copies +#else + - (uint32_t) sectors_per_fat * fat_copies +#endif + - ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector); + uint32_t data_cluster_count = data_sector_count / sectors_per_cluster; + if(data_cluster_count < 4085) + /* this is a FAT12, not supported */ + return 0; + else if(data_cluster_count < 65525) + /* this is a FAT16 */ + partition->type = PARTITION_TYPE_FAT16; + else + /* this is a FAT32 */ + partition->type = PARTITION_TYPE_FAT32; + + /* fill header information */ + struct fat_header_struct* header = &fs->header; + memset(header, 0, sizeof(*header)); + + header->size = (offset_t) sector_count * bytes_per_sector; + + header->fat_offset = /* jump to partition */ + partition_offset + + /* jump to fat */ + (offset_t) reserved_sectors * bytes_per_sector; + header->fat_size = (data_cluster_count + 2) * (partition->type == PARTITION_TYPE_FAT16 ? 2 : 4); + + header->sector_size = bytes_per_sector; + header->cluster_size = (uint16_t) bytes_per_sector * sectors_per_cluster; + +#if FAT_FAT32_SUPPORT + if(partition->type == PARTITION_TYPE_FAT16) +#endif + { + header->root_dir_offset = /* jump to fats */ + header->fat_offset + + /* jump to root directory entries */ + (offset_t) fat_copies * sectors_per_fat * bytes_per_sector; + + header->cluster_zero_offset = /* jump to root directory entries */ + header->root_dir_offset + + /* skip root directory entries */ + (offset_t) max_root_entries * 32; + } +#if FAT_FAT32_SUPPORT + else + { + header->cluster_zero_offset = /* jump to fats */ + header->fat_offset + + /* skip fats */ + (offset_t) fat_copies * sectors_per_fat32 * bytes_per_sector; + + header->root_dir_cluster = cluster_root_dir; + } +#endif + + return 1; +} + +/** + * \ingroup fat_fs + * Retrieves the next following cluster of a given cluster. + * + * Using the filesystem file allocation table, this function returns + * the number of the cluster containing the data directly following + * the data within the cluster with the given number. + * + * \param[in] fs The filesystem for which to determine the next cluster. + * \param[in] cluster_num The number of the cluster for which to determine its successor. + * \returns The wanted cluster number, or 0 on error. + */ +cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num) +{ + if(!fs || cluster_num < 2) + return 0; + +#if FAT_FAT32_SUPPORT + if(fs->partition->type == PARTITION_TYPE_FAT32) + { + /* read appropriate fat entry */ + uint32_t fat_entry; + if(!fs->partition->device_read(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) + return 0; + + /* determine next cluster from fat */ + cluster_num = ltoh32(fat_entry); + + if(cluster_num == FAT32_CLUSTER_FREE || + cluster_num == FAT32_CLUSTER_BAD || + (cluster_num >= FAT32_CLUSTER_RESERVED_MIN && cluster_num <= FAT32_CLUSTER_RESERVED_MAX) || + (cluster_num >= FAT32_CLUSTER_LAST_MIN && cluster_num <= FAT32_CLUSTER_LAST_MAX)) + return 0; + } + else +#endif + { + /* read appropriate fat entry */ + uint16_t fat_entry; + if(!fs->partition->device_read(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) + return 0; + + /* determine next cluster from fat */ + cluster_num = ltoh16(fat_entry); + + if(cluster_num == FAT16_CLUSTER_FREE || + cluster_num == FAT16_CLUSTER_BAD || + (cluster_num >= FAT16_CLUSTER_RESERVED_MIN && cluster_num <= FAT16_CLUSTER_RESERVED_MAX) || + (cluster_num >= FAT16_CLUSTER_LAST_MIN && cluster_num <= FAT16_CLUSTER_LAST_MAX)) + return 0; + } + + return cluster_num; +} + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Appends a new cluster chain to an existing one. + * + * Set cluster_num to zero to create a completely new one. + * + * \param[in] fs The file system on which to operate. + * \param[in] cluster_num The cluster to which to append the new chain. + * \param[in] count The number of clusters to allocate. + * \returns 0 on failure, the number of the first new cluster on success. + */ +cluster_t fat_append_clusters(struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count) +{ + if(!fs) + return 0; + + device_read_t device_read = fs->partition->device_read; + device_write_t device_write = fs->partition->device_write; + offset_t fat_offset = fs->header.fat_offset; + cluster_t count_left = count; + cluster_t cluster_current = fs->cluster_free; + cluster_t cluster_next = 0; + cluster_t cluster_count; + uint16_t fat_entry16; +#if FAT_FAT32_SUPPORT + uint32_t fat_entry32; + uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32); + + if(is_fat32) + cluster_count = fs->header.fat_size / sizeof(fat_entry32); + else +#endif + cluster_count = fs->header.fat_size / sizeof(fat_entry16); + + fs->cluster_free = 0; + for(cluster_t cluster_left = cluster_count; cluster_left > 0; --cluster_left, ++cluster_current) + { + if(cluster_current < 2 || cluster_current >= cluster_count) + cluster_current = 2; + +#if FAT_FAT32_SUPPORT + if(is_fat32) + { + if(!device_read(fat_offset + (offset_t) cluster_current * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32))) + return 0; + } + else +#endif + { + if(!device_read(fat_offset + (offset_t) cluster_current * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16))) + return 0; + } + +#if FAT_FAT32_SUPPORT + if(is_fat32) + { + /* check if this is a free cluster */ + if(fat_entry32 != HTOL32(FAT32_CLUSTER_FREE)) + continue; + + /* If we don't need this free cluster for the + * current allocation, we keep it in mind for + * the next time. + */ + if(count_left == 0) + { + fs->cluster_free = cluster_current; + break; + } + + /* allocate cluster */ + if(cluster_next == 0) + fat_entry32 = HTOL32(FAT32_CLUSTER_LAST_MAX); + else + fat_entry32 = htol32(cluster_next); + + if(!device_write(fat_offset + (offset_t) cluster_current * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32))) + break; + } + else +#endif + { + /* check if this is a free cluster */ + if(fat_entry16 != HTOL16(FAT16_CLUSTER_FREE)) + continue; + + /* If we don't need this free cluster for the + * current allocation, we keep it in mind for + * the next time. + */ + if(count_left == 0) + { + fs->cluster_free = cluster_current; + break; + } + + /* allocate cluster */ + if(cluster_next == 0) + fat_entry16 = HTOL16(FAT16_CLUSTER_LAST_MAX); + else + fat_entry16 = htol16((uint16_t) cluster_next); + + if(!device_write(fat_offset + (offset_t) cluster_current * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16))) + break; + } + + cluster_next = cluster_current; + --count_left; + } + + do + { + if(count_left > 0) + break; + + /* We allocated a new cluster chain. Now join + * it with the existing one (if any). + */ + if(cluster_num >= 2) + { +#if FAT_FAT32_SUPPORT + if(is_fat32) + { + fat_entry32 = htol32(cluster_next); + + if(!device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32))) + break; + } + else +#endif + { + fat_entry16 = htol16((uint16_t) cluster_next); + + if(!device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16))) + break; + } + } + + return cluster_next; + + } while(0); + + /* No space left on device or writing error. + * Free up all clusters already allocated. + */ + fat_free_clusters(fs, cluster_next); + + return 0; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Frees a cluster chain, or a part thereof. + * + * Marks the specified cluster and all clusters which are sequentially + * referenced by it as free. They may then be used again for future + * file allocations. + * + * \note If this function is used for freeing just a part of a cluster + * chain, the new end of the chain is not correctly terminated + * within the FAT. Use fat_terminate_clusters() instead. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] cluster_num The starting cluster of the chain which to free. + * \returns 0 on failure, 1 on success. + * \see fat_terminate_clusters + */ +uint8_t fat_free_clusters(struct fat_fs_struct* fs, cluster_t cluster_num) +{ + if(!fs || cluster_num < 2) + return 0; + + offset_t fat_offset = fs->header.fat_offset; +#if FAT_FAT32_SUPPORT + if(fs->partition->type == PARTITION_TYPE_FAT32) + { + uint32_t fat_entry; + while(cluster_num) + { + if(!fs->partition->device_read(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) + return 0; + + /* get next cluster of current cluster before freeing current cluster */ + uint32_t cluster_num_next = ltoh32(fat_entry); + + if(cluster_num_next == FAT32_CLUSTER_FREE) + return 1; + if(cluster_num_next == FAT32_CLUSTER_BAD || + (cluster_num_next >= FAT32_CLUSTER_RESERVED_MIN && + cluster_num_next <= FAT32_CLUSTER_RESERVED_MAX + ) + ) + return 0; + if(cluster_num_next >= FAT32_CLUSTER_LAST_MIN && cluster_num_next <= FAT32_CLUSTER_LAST_MAX) + cluster_num_next = 0; + + /* We know we will free the cluster, so remember it as + * free for the next allocation. + */ + if(!fs->cluster_free) + fs->cluster_free = cluster_num; + + /* free cluster */ + fat_entry = HTOL32(FAT32_CLUSTER_FREE); + fs->partition->device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)); + + /* We continue in any case here, even if freeing the cluster failed. + * The cluster is lost, but maybe we can still free up some later ones. + */ + + cluster_num = cluster_num_next; + } + } + else +#endif + { + uint16_t fat_entry; + while(cluster_num) + { + if(!fs->partition->device_read(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) + return 0; + + /* get next cluster of current cluster before freeing current cluster */ + uint16_t cluster_num_next = ltoh16(fat_entry); + + if(cluster_num_next == FAT16_CLUSTER_FREE) + return 1; + if(cluster_num_next == FAT16_CLUSTER_BAD || + (cluster_num_next >= FAT16_CLUSTER_RESERVED_MIN && + cluster_num_next <= FAT16_CLUSTER_RESERVED_MAX + ) + ) + return 0; + if(cluster_num_next >= FAT16_CLUSTER_LAST_MIN && cluster_num_next <= FAT16_CLUSTER_LAST_MAX) + cluster_num_next = 0; + + /* free cluster */ + fat_entry = HTOL16(FAT16_CLUSTER_FREE); + fs->partition->device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)); + + /* We continue in any case here, even if freeing the cluster failed. + * The cluster is lost, but maybe we can still free up some later ones. + */ + + cluster_num = cluster_num_next; + } + } + + return 1; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Frees a part of a cluster chain and correctly terminates the rest. + * + * Marks the specified cluster as the new end of a cluster chain and + * frees all following clusters. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] cluster_num The new end of the cluster chain. + * \returns 0 on failure, 1 on success. + * \see fat_free_clusters + */ +uint8_t fat_terminate_clusters(struct fat_fs_struct* fs, cluster_t cluster_num) +{ + if(!fs || cluster_num < 2) + return 0; + + /* fetch next cluster before overwriting the cluster entry */ + cluster_t cluster_num_next = fat_get_next_cluster(fs, cluster_num); + + /* mark cluster as the last one */ +#if FAT_FAT32_SUPPORT + if(fs->partition->type == PARTITION_TYPE_FAT32) + { + uint32_t fat_entry = HTOL32(FAT32_CLUSTER_LAST_MAX); + if(!fs->partition->device_write(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) + return 0; + } + else +#endif + { + uint16_t fat_entry = HTOL16(FAT16_CLUSTER_LAST_MAX); + if(!fs->partition->device_write(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) + return 0; + } + + /* free remaining clusters */ + if(cluster_num_next) + return fat_free_clusters(fs, cluster_num_next); + else + return 1; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Clears a single cluster. + * + * The complete cluster is filled with zeros. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] cluster_num The cluster to clear. + * \returns 0 on failure, 1 on success. + */ +uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num) +{ + if(cluster_num < 2) + return 0; + + offset_t cluster_offset = fat_cluster_offset(fs, cluster_num); + + uint8_t zero[16]; + memset(zero, 0, sizeof(zero)); + return fs->partition->device_write_interval(cluster_offset, + zero, + fs->header.cluster_size, + fat_clear_cluster_callback, + 0 + ); +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Callback function for clearing a cluster. + */ +uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p) +{ + return 16; +} +#endif + +/** + * \ingroup fat_fs + * Calculates the offset of the specified cluster. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] cluster_num The cluster whose offset to calculate. + * \returns The cluster offset. + */ +offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num) +{ + if(!fs || cluster_num < 2) + return 0; + + return fs->header.cluster_zero_offset + (offset_t) (cluster_num - 2) * fs->header.cluster_size; +} + +/** + * \ingroup fat_file + * Retrieves the directory entry of a path. + * + * The given path may both describe a file or a directory. + * + * \param[in] fs The FAT filesystem on which to search. + * \param[in] path The path of which to read the directory entry. + * \param[out] dir_entry The directory entry to fill. + * \returns 0 on failure, 1 on success. + * \see fat_read_dir + */ +uint8_t fat_get_dir_entry_of_path(struct fat_fs_struct* fs, const char* path, struct fat_dir_entry_struct* dir_entry) +{ + if(!fs || !path || path[0] == '\0' || !dir_entry) + return 0; + + if(path[0] == '/') + ++path; + + /* begin with the root directory */ + memset(dir_entry, 0, sizeof(*dir_entry)); + dir_entry->attributes = FAT_ATTRIB_DIR; + + while(1) + { + if(path[0] == '\0') + return 1; + + struct fat_dir_struct* dd = fat_open_dir(fs, dir_entry); + if(!dd) + break; + + /* extract the next hierarchy we will search for */ + const char* sub_path = strchr(path, '/'); + uint8_t length_to_sep; + if(sub_path) + { + length_to_sep = sub_path - path; + ++sub_path; + } + else + { + length_to_sep = strlen(path); + sub_path = path + length_to_sep; + } + + /* read directory entries */ + while(fat_read_dir(dd, dir_entry)) + { + /* check if we have found the next hierarchy */ + if((strlen(dir_entry->long_name) != length_to_sep || + strncmp(path, dir_entry->long_name, length_to_sep) != 0)) + continue; + + fat_close_dir(dd); + dd = 0; + + if(path[length_to_sep] == '\0') + /* we iterated through the whole path and have found the file */ + return 1; + + if(dir_entry->attributes & FAT_ATTRIB_DIR) + { + /* we found a parent directory of the file we are searching for */ + path = sub_path; + break; + } + + /* a parent of the file exists, but not the file itself */ + return 0; + } + + fat_close_dir(dd); + } + + return 0; +} + +/** + * \ingroup fat_file + * Opens a file on a FAT filesystem. + * + * \param[in] fs The filesystem on which the file to open lies. + * \param[in] dir_entry The directory entry of the file to open. + * \returns The file handle, or 0 on failure. + * \see fat_close_file + */ +struct fat_file_struct* fat_open_file(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry) +{ + if(!fs || !dir_entry || (dir_entry->attributes & FAT_ATTRIB_DIR)) + return 0; + +#if USE_DYNAMIC_MEMORY + struct fat_file_struct* fd = malloc(sizeof(*fd)); + if(!fd) + return 0; +#else + struct fat_file_struct* fd = fat_file_handles; + uint8_t i; + for(i = 0; i < FAT_FILE_COUNT; ++i) + { + if(!fd->fs) + break; + + ++fd; + } + if(i >= FAT_FILE_COUNT) + return 0; +#endif + + memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry)); + fd->fs = fs; + fd->pos = 0; + fd->pos_cluster = dir_entry->cluster; + + return fd; +} + +/** + * \ingroup fat_file + * Closes a file. + * + * \param[in] fd The file handle of the file to close. + * \see fat_open_file + */ +void fat_close_file(struct fat_file_struct* fd) +{ + if(fd) + { +#if FAT_DELAY_DIRENTRY_UPDATE + /* write directory entry */ + fat_write_dir_entry(fd->fs, &fd->dir_entry); +#endif + +#if USE_DYNAMIC_MEMORY + free(fd); +#else + fd->fs = 0; +#endif + } +} + +/** + * \ingroup fat_file + * Reads data from a file. + * + * The data requested is read from the current file location. + * + * \param[in] fd The file handle of the file from which to read. + * \param[out] buffer The buffer into which to write. + * \param[in] buffer_len The amount of data to read. + * \returns The number of bytes read, 0 on end of file, or -1 on failure. + * \see fat_write_file + */ +intptr_t fat_read_file(struct fat_file_struct* fd, uint8_t* buffer, uintptr_t buffer_len) +{ + /* check arguments */ + if(!fd || !buffer || buffer_len < 1) + return -1; + + /* determine number of bytes to read */ + if(fd->pos + buffer_len > fd->dir_entry.file_size) + buffer_len = fd->dir_entry.file_size - fd->pos; + if(buffer_len == 0) + return 0; + + uint16_t cluster_size = fd->fs->header.cluster_size; + cluster_t cluster_num = fd->pos_cluster; + uintptr_t buffer_left = buffer_len; + uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1)); + + /* find cluster in which to start reading */ + if(!cluster_num) + { + cluster_num = fd->dir_entry.cluster; + + if(!cluster_num) + { + if(!fd->pos) + return 0; + else + return -1; + } + + if(fd->pos) + { + uint32_t pos = fd->pos; + while(pos >= cluster_size) + { + pos -= cluster_size; + cluster_num = fat_get_next_cluster(fd->fs, cluster_num); + if(!cluster_num) + return -1; + } + } + } + + /* read data */ + do + { + /* calculate data size to copy from cluster */ + offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset; + uint16_t copy_length = cluster_size - first_cluster_offset; + if(copy_length > buffer_left) + copy_length = buffer_left; + + /* read data */ + if(!fd->fs->partition->device_read(cluster_offset, buffer, copy_length)) + return buffer_len - buffer_left; + + /* calculate new file position */ + buffer += copy_length; + buffer_left -= copy_length; + fd->pos += copy_length; + + if(first_cluster_offset + copy_length >= cluster_size) + { + /* we are on a cluster boundary, so get the next cluster */ + if((cluster_num = fat_get_next_cluster(fd->fs, cluster_num))) + { + first_cluster_offset = 0; + } + else + { + fd->pos_cluster = 0; + return buffer_len - buffer_left; + } + } + + fd->pos_cluster = cluster_num; + + } while(buffer_left > 0); /* check if we are done */ + + return buffer_len; +} + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_file + * Writes data to a file. + * + * The data is written to the current file location. + * + * \param[in] fd The file handle of the file to which to write. + * \param[in] buffer The buffer from which to read the data to be written. + * \param[in] buffer_len The amount of data to write. + * \returns The number of bytes written (0 or something less than \c buffer_len on disk full) or -1 on failure. + * \see fat_read_file + */ +intptr_t fat_write_file(struct fat_file_struct* fd, const uint8_t* buffer, uintptr_t buffer_len) +{ + /* check arguments */ + if(!fd || !buffer || buffer_len < 1) + return -1; + if(fd->pos > fd->dir_entry.file_size) + return -1; + + uint16_t cluster_size = fd->fs->header.cluster_size; + cluster_t cluster_num = fd->pos_cluster; + uintptr_t buffer_left = buffer_len; + uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1)); + + /* find cluster in which to start writing */ + if(!cluster_num) + { + cluster_num = fd->dir_entry.cluster; + + if(!cluster_num) + { + if(!fd->pos) + { + /* empty file */ + fd->dir_entry.cluster = cluster_num = fat_append_clusters(fd->fs, 0, 1); + if(!cluster_num) + return 0; + } + else + { + return -1; + } + } + + if(fd->pos) + { + uint32_t pos = fd->pos; + cluster_t cluster_num_next; + while(pos >= cluster_size) + { + pos -= cluster_size; + cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num); + if(!cluster_num_next) + { + if(pos != 0) + return -1; /* current file position points beyond end of file */ + + /* the file exactly ends on a cluster boundary, and we append to it */ + cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1); + if(!cluster_num_next) + return 0; + } + + cluster_num = cluster_num_next; + } + } + } + + /* write data */ + do + { + /* calculate data size to write to cluster */ + offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset; + uint16_t write_length = cluster_size - first_cluster_offset; + if(write_length > buffer_left) + write_length = buffer_left; + + /* write data which fits into the current cluster */ + if(!fd->fs->partition->device_write(cluster_offset, buffer, write_length)) + break; + + /* calculate new file position */ + buffer += write_length; + buffer_left -= write_length; + fd->pos += write_length; + + if(first_cluster_offset + write_length >= cluster_size) + { + /* we are on a cluster boundary, so get the next cluster */ + cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num); + if(!cluster_num_next && buffer_left > 0) + /* we reached the last cluster, append a new one */ + cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1); + if(!cluster_num_next) + { + fd->pos_cluster = 0; + break; + } + + cluster_num = cluster_num_next; + first_cluster_offset = 0; + } + + fd->pos_cluster = cluster_num; + + } while(buffer_left > 0); /* check if we are done */ + + /* update directory entry */ + if(fd->pos > fd->dir_entry.file_size) + { +#if !FAT_DELAY_DIRENTRY_UPDATE + uint32_t size_old = fd->dir_entry.file_size; +#endif + + /* update file size */ + fd->dir_entry.file_size = fd->pos; + +#if !FAT_DELAY_DIRENTRY_UPDATE + /* write directory entry */ + if(!fat_write_dir_entry(fd->fs, &fd->dir_entry)) + { + /* We do not return an error here since we actually wrote + * some data to disk. So we calculate the amount of data + * we wrote to disk and which lies within the old file size. + */ + buffer_left = fd->pos - size_old; + fd->pos = size_old; + } +#endif + } + + return buffer_len - buffer_left; +} +#endif + +/** + * \ingroup fat_file + * Repositions the read/write file offset. + * + * Changes the file offset where the next call to fat_read_file() + * or fat_write_file() starts reading/writing. + * + * If the new offset is beyond the end of the file, fat_resize_file() + * is implicitly called, i.e. the file is expanded. + * + * The new offset can be given in different ways determined by + * the \c whence parameter: + * - \b FAT_SEEK_SET: \c *offset is relative to the beginning of the file. + * - \b FAT_SEEK_CUR: \c *offset is relative to the current file position. + * - \b FAT_SEEK_END: \c *offset is relative to the end of the file. + * + * The resulting absolute offset is written to the location the \c offset + * parameter points to. + * + * Calling this function can also be used to retrieve the current file position: + \code + int32_t file_pos = 0; + if(!fat_seek_file(fd, &file_pos, FAT_SEEK_CUR)) + { + // error + } + // file_pos now contains the absolute file position + \endcode + * + * \param[in] fd The file decriptor of the file on which to seek. + * \param[in,out] offset A pointer to the new offset, as affected by the \c whence + * parameter. The function writes the new absolute offset + * to this location before it returns. + * \param[in] whence Affects the way \c offset is interpreted, see above. + * \returns 0 on failure, 1 on success. + */ +uint8_t fat_seek_file(struct fat_file_struct* fd, int32_t* offset, uint8_t whence) +{ + if(!fd || !offset) + return 0; + + uint32_t new_pos = fd->pos; + switch(whence) + { + case FAT_SEEK_SET: + new_pos = *offset; + break; + case FAT_SEEK_CUR: + new_pos += *offset; + break; + case FAT_SEEK_END: + new_pos = fd->dir_entry.file_size + *offset; + break; + default: + return 0; + } + + if(new_pos > fd->dir_entry.file_size +#if FAT_WRITE_SUPPORT + && !fat_resize_file(fd, new_pos) +#endif + ) + return 0; + + fd->pos = new_pos; + fd->pos_cluster = 0; + + *offset = (int32_t) new_pos; + return 1; +} + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_file + * Resizes a file to have a specific size. + * + * Enlarges or shrinks the file pointed to by the file descriptor to have + * exactly the specified size. + * + * If the file is truncated, all bytes having an equal or larger offset + * than the given size are lost. If the file is expanded, the additional + * bytes are allocated. + * + * \note Please be aware that this function just allocates or deallocates disk + * space, it does not explicitely clear it. To avoid data leakage, this + * must be done manually. + * + * \param[in] fd The file decriptor of the file which to resize. + * \param[in] size The new size of the file. + * \returns 0 on failure, 1 on success. + */ +uint8_t fat_resize_file(struct fat_file_struct* fd, uint32_t size) +{ + if(!fd) + return 0; + + cluster_t cluster_num = fd->dir_entry.cluster; + uint16_t cluster_size = fd->fs->header.cluster_size; + uint32_t size_new = size; + + do + { + if(cluster_num == 0 && size_new == 0) + /* the file stays empty */ + break; + + /* seek to the next cluster as long as we need the space */ + while(size_new > cluster_size) + { + /* get next cluster of file */ + cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num); + if(cluster_num_next) + { + cluster_num = cluster_num_next; + size_new -= cluster_size; + } + else + { + break; + } + } + + if(size_new > cluster_size || cluster_num == 0) + { + /* Allocate new cluster chain and append + * it to the existing one, if available. + */ + cluster_t cluster_count = (size_new + cluster_size - 1) / cluster_size; + cluster_t cluster_new_chain = fat_append_clusters(fd->fs, cluster_num, cluster_count); + if(!cluster_new_chain) + return 0; + + if(!cluster_num) + { + cluster_num = cluster_new_chain; + fd->dir_entry.cluster = cluster_num; + } + } + + /* write new directory entry */ + fd->dir_entry.file_size = size; + if(size == 0) + fd->dir_entry.cluster = 0; + if(!fat_write_dir_entry(fd->fs, &fd->dir_entry)) + return 0; + + if(size == 0) + { + /* free all clusters of file */ + fat_free_clusters(fd->fs, cluster_num); + } + else if(size_new <= cluster_size) + { + /* free all clusters no longer needed */ + fat_terminate_clusters(fd->fs, cluster_num); + } + + } while(0); + + /* correct file position */ + if(size < fd->pos) + { + fd->pos = size; + fd->pos_cluster = 0; + } + + return 1; +} +#endif + +/** + * \ingroup fat_dir + * Opens a directory. + * + * \param[in] fs The filesystem on which the directory to open resides. + * \param[in] dir_entry The directory entry which stands for the directory to open. + * \returns An opaque directory descriptor on success, 0 on failure. + * \see fat_close_dir + */ +struct fat_dir_struct* fat_open_dir(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry) +{ + if(!fs || !dir_entry || !(dir_entry->attributes & FAT_ATTRIB_DIR)) + return 0; + +#if USE_DYNAMIC_MEMORY + struct fat_dir_struct* dd = malloc(sizeof(*dd)); + if(!dd) + return 0; +#else + struct fat_dir_struct* dd = fat_dir_handles; + uint8_t i; + for(i = 0; i < FAT_DIR_COUNT; ++i) + { + if(!dd->fs) + break; + + ++dd; + } + if(i >= FAT_DIR_COUNT) + return 0; +#endif + + memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry)); + dd->fs = fs; + dd->entry_cluster = dir_entry->cluster; + dd->entry_offset = 0; + + return dd; +} + +/** + * \ingroup fat_dir + * Closes a directory descriptor. + * + * This function destroys a directory descriptor which was + * previously obtained by calling fat_open_dir(). When this + * function returns, the given descriptor will be invalid. + * + * \param[in] dd The directory descriptor to close. + * \see fat_open_dir + */ +void fat_close_dir(struct fat_dir_struct* dd) +{ + if(dd) +#if USE_DYNAMIC_MEMORY + free(dd); +#else + dd->fs = 0; +#endif +} + +/** + * \ingroup fat_dir + * Reads the next directory entry contained within a parent directory. + * + * \param[in] dd The descriptor of the parent directory from which to read the entry. + * \param[out] dir_entry Pointer to a buffer into which to write the directory entry information. + * \returns 0 on failure, 1 on success. + * \see fat_reset_dir + */ +uint8_t fat_read_dir(struct fat_dir_struct* dd, struct fat_dir_entry_struct* dir_entry) +{ + if(!dd || !dir_entry) + return 0; + + /* get current position of directory handle */ + struct fat_fs_struct* fs = dd->fs; + const struct fat_header_struct* header = &fs->header; + uint16_t cluster_size = header->cluster_size; + cluster_t cluster_num = dd->entry_cluster; + uint16_t cluster_offset = dd->entry_offset; + struct fat_read_dir_callback_arg arg; + + if(cluster_offset >= cluster_size) + { + /* The latest call hit the border of the last cluster in + * the chain, but it still returned a directory entry. + * So we now reset the handle and signal the caller the + * end of the listing. + */ + fat_reset_dir(dd); + return 0; + } + + /* reset callback arguments */ + memset(&arg, 0, sizeof(arg)); + memset(dir_entry, 0, sizeof(*dir_entry)); + arg.dir_entry = dir_entry; + + /* check if we read from the root directory */ + if(cluster_num == 0) + { +#if FAT_FAT32_SUPPORT + if(fs->partition->type == PARTITION_TYPE_FAT32) + cluster_num = header->root_dir_cluster; + else +#endif + cluster_size = header->cluster_zero_offset - header->root_dir_offset; + } + + /* read entries */ + uint8_t buffer[32]; + while(!arg.finished) + { + /* read directory entries up to the cluster border */ + uint16_t cluster_left = cluster_size - cluster_offset; + offset_t pos = cluster_offset; + if(cluster_num == 0) + pos += header->root_dir_offset; + else + pos += fat_cluster_offset(fs, cluster_num); + + arg.bytes_read = 0; + if(!fs->partition->device_read_interval(pos, + buffer, + sizeof(buffer), + cluster_left, + fat_dir_entry_read_callback, + &arg) + ) + return 0; + + cluster_offset += arg.bytes_read; + + if(cluster_offset >= cluster_size) + { + /* we reached the cluster border and switch to the next cluster */ + + /* get number of next cluster */ + if((cluster_num = fat_get_next_cluster(fs, cluster_num)) != 0) + { + cluster_offset = 0; + continue; + } + + /* we are at the end of the cluster chain */ + if(!arg.finished) + { + /* directory entry not found, reset directory handle */ + fat_reset_dir(dd); + return 0; + } + else + { + /* The current execution of the function has been successful, + * so we can not signal an end of the directory listing to + * the caller, but must wait for the next call. So we keep an + * invalid cluster offset to mark this directory handle's + * traversal as finished. + */ + } + + break; + } + } + + dd->entry_cluster = cluster_num; + dd->entry_offset = cluster_offset; + + return arg.finished; +} + +/** + * \ingroup fat_dir + * Resets a directory handle. + * + * Resets the directory handle such that reading restarts + * with the first directory entry. + * + * \param[in] dd The directory handle to reset. + * \returns 0 on failure, 1 on success. + * \see fat_read_dir + */ +uint8_t fat_reset_dir(struct fat_dir_struct* dd) +{ + if(!dd) + return 0; + + dd->entry_cluster = dd->dir_entry.cluster; + dd->entry_offset = 0; + return 1; +} + +/** + * \ingroup fat_fs + * Callback function for reading a directory entry. + * + * Interprets a raw directory entry and puts the contained + * information into a fat_dir_entry_struct structure. + * + * For a single file there may exist multiple directory + * entries. All except the last one are lfn entries, which + * contain parts of the long filename. The last directory + * entry is a traditional 8.3 style one. It contains all + * other information like size, cluster, date and time. + * + * \param[in] buffer A pointer to 32 bytes of raw data. + * \param[in] offset The absolute offset of the raw data. + * \param[in,out] p An argument structure controlling operation. + * \returns 0 on failure or completion, 1 if reading has + * to be continued + */ +uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p) +{ + struct fat_read_dir_callback_arg* arg = p; + struct fat_dir_entry_struct* dir_entry = arg->dir_entry; + + arg->bytes_read += 32; + + /* skip deleted or empty entries */ + if(buffer[0] == FAT_DIRENTRY_DELETED || !buffer[0]) + { +#if FAT_LFN_SUPPORT + arg->checksum = 0; +#endif + return 1; + } + +#if !FAT_LFN_SUPPORT + /* skip lfn entries */ + if(buffer[11] == 0x0f) + return 1; +#endif + + char* long_name = dir_entry->long_name; +#if FAT_LFN_SUPPORT + if(buffer[11] == 0x0f) + { + /* checksum validation */ + if(arg->checksum == 0 || arg->checksum != buffer[13]) + { + /* reset directory entry */ + memset(dir_entry, 0, sizeof(*dir_entry)); + + arg->checksum = buffer[13]; + dir_entry->entry_offset = offset; + } + + /* lfn supports unicode, but we do not, for now. + * So we assume pure ascii and read only every + * second byte. + */ + uint16_t char_offset = ((buffer[0] & 0x3f) - 1) * 13; + const uint8_t char_mapping[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; + for(uint8_t i = 0; i <= 12 && char_offset + i < sizeof(dir_entry->long_name) - 1; ++i) + long_name[char_offset + i] = buffer[char_mapping[i]]; + + return 1; + } + else +#endif + { +#if FAT_LFN_SUPPORT + /* if we do not have a long name or the previous lfn does not match, take the 8.3 name */ + if(long_name[0] == '\0' || arg->checksum != fat_calc_83_checksum(buffer)) +#endif + { + /* reset directory entry */ + memset(dir_entry, 0, sizeof(*dir_entry)); + dir_entry->entry_offset = offset; + + uint8_t i; + for(i = 0; i < 8; ++i) + { + if(buffer[i] == ' ') + break; + long_name[i] = buffer[i]; + + /* Windows NT and later versions do not store lfn entries + * for 8.3 names which have a lowercase basename, extension + * or both when everything else is uppercase. They use two + * extra bits to signal a lowercase basename or extension. + */ + if((buffer[12] & 0x08) && buffer[i] >= 'A' && buffer[i] <= 'Z') + long_name[i] += 'a' - 'A'; + } + if(long_name[0] == 0x05) + long_name[0] = (char) FAT_DIRENTRY_DELETED; + + if(buffer[8] != ' ') + { + long_name[i++] = '.'; + + uint8_t j = 8; + for(; j < 11; ++j) + { + if(buffer[j] == ' ') + break; + long_name[i] = buffer[j]; + + /* See above for the lowercase 8.3 name handling of + * Windows NT and later. + */ + if((buffer[12] & 0x10) && buffer[j] >= 'A' && buffer[j] <= 'Z') + long_name[i] += 'a' - 'A'; + + ++i; + } + } + + long_name[i] = '\0'; + } + + /* extract properties of file and store them within the structure */ + dir_entry->attributes = buffer[11]; + dir_entry->cluster = read16(&buffer[26]); +#if FAT_FAT32_SUPPORT + dir_entry->cluster |= ((cluster_t) read16(&buffer[20])) << 16; +#endif + dir_entry->file_size = read32(&buffer[28]); + +#if FAT_DATETIME_SUPPORT + dir_entry->modification_time = read16(&buffer[22]); + dir_entry->modification_date = read16(&buffer[24]); +#endif + + arg->finished = 1; + return 0; + } +} + +#if DOXYGEN || FAT_LFN_SUPPORT +/** + * \ingroup fat_fs + * Calculates the checksum for 8.3 names used within the + * corresponding lfn directory entries. + * + * \param[in] file_name_83 The 11-byte file name buffer. + * \returns The checksum of the given file name. + */ +uint8_t fat_calc_83_checksum(const uint8_t* file_name_83) +{ + uint8_t checksum = file_name_83[0]; + for(uint8_t i = 1; i < 11; ++i) + checksum = ((checksum >> 1) | (checksum << 7)) + file_name_83[i]; + + return checksum; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Searches for space where to store a directory entry. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] parent The directory in which to search. + * \param[in] dir_entry The directory entry for which to search space. + * \returns 0 on failure, a device offset on success. + */ +offset_t fat_find_offset_for_dir_entry(struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry) +{ + if(!fs || !dir_entry) + return 0; + + /* search for a place where to write the directory entry to disk */ +#if FAT_LFN_SUPPORT + uint8_t free_dir_entries_needed = (strlen(dir_entry->long_name) + 12) / 13 + 1; + uint8_t free_dir_entries_found = 0; +#endif + cluster_t cluster_num = parent->dir_entry.cluster; + offset_t dir_entry_offset = 0; + offset_t offset = 0; + offset_t offset_to = 0; +#if FAT_FAT32_SUPPORT + uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32); +#endif + + if(cluster_num == 0) + { +#if FAT_FAT32_SUPPORT + if(is_fat32) + { + cluster_num = fs->header.root_dir_cluster; + } + else +#endif + { + /* we read/write from the root directory entry */ + offset = fs->header.root_dir_offset; + offset_to = fs->header.cluster_zero_offset; + dir_entry_offset = offset; + } + } + + while(1) + { + if(offset == offset_to) + { + if(cluster_num == 0) + /* We iterated through the whole root directory and + * could not find enough space for the directory entry. + */ + return 0; + + if(offset) + { + /* We reached a cluster boundary and have to + * switch to the next cluster. + */ + + cluster_t cluster_next = fat_get_next_cluster(fs, cluster_num); + if(!cluster_next) + { + cluster_next = fat_append_clusters(fs, cluster_num, 1); + if(!cluster_next) + return 0; + + /* we appended a new cluster and know it is free */ + dir_entry_offset = fs->header.cluster_zero_offset + + (offset_t) (cluster_next - 2) * fs->header.cluster_size; + + /* clear cluster to avoid garbage directory entries */ + fat_clear_cluster(fs, cluster_next); + + break; + } + cluster_num = cluster_next; + } + + offset = fat_cluster_offset(fs, cluster_num); + offset_to = offset + fs->header.cluster_size; + dir_entry_offset = offset; +#if FAT_LFN_SUPPORT + free_dir_entries_found = 0; +#endif + } + + /* read next lfn or 8.3 entry */ + uint8_t first_char; + if(!fs->partition->device_read(offset, &first_char, sizeof(first_char))) + return 0; + + /* check if we found a free directory entry */ + if(first_char == FAT_DIRENTRY_DELETED || !first_char) + { + /* check if we have the needed number of available entries */ +#if FAT_LFN_SUPPORT + ++free_dir_entries_found; + if(free_dir_entries_found >= free_dir_entries_needed) +#endif + break; + + offset += 32; + } + else + { + offset += 32; + dir_entry_offset = offset; +#if FAT_LFN_SUPPORT + free_dir_entries_found = 0; +#endif + } + } + + return dir_entry_offset; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_fs + * Writes a directory entry to disk. + * + * \note The file name is not checked for invalid characters. + * + * \note The generation of the short 8.3 file name is quite + * simple. The first eight characters are used for the filename. + * The extension, if any, is made up of the first three characters + * following the last dot within the long filename. If the + * filename (without the extension) is longer than eight characters, + * the lower byte of the cluster number replaces the last two + * characters to avoid name clashes. In any other case, it is your + * responsibility to avoid name clashes. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] dir_entry The directory entry to write. + * \returns 0 on failure, 1 on success. + */ +uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry) +{ + if(!fs || !dir_entry) + return 0; + +#if FAT_DATETIME_SUPPORT + { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint8_t sec; + + fat_get_datetime(&year, &month, &day, &hour, &min, &sec); + fat_set_file_modification_date(dir_entry, year, month, day); + fat_set_file_modification_time(dir_entry, hour, min, sec); + } +#endif + + device_write_t device_write = fs->partition->device_write; + offset_t offset = dir_entry->entry_offset; + const char* name = dir_entry->long_name; + uint8_t name_len = strlen(name); +#if FAT_LFN_SUPPORT + uint8_t lfn_entry_count = (name_len + 12) / 13; +#endif + uint8_t buffer[32]; + + /* write 8.3 entry */ + + /* generate 8.3 file name */ + memset(&buffer[0], ' ', 11); + char* name_ext = strrchr(name, '.'); + if(name_ext && *++name_ext) + { + uint8_t name_ext_len = strlen(name_ext); + name_len -= name_ext_len + 1; + + if(name_ext_len > 3) +#if FAT_LFN_SUPPORT + name_ext_len = 3; +#else + return 0; +#endif + + memcpy(&buffer[8], name_ext, name_ext_len); + } + + if(name_len <= 8) + { + memcpy(buffer, name, name_len); + +#if FAT_LFN_SUPPORT + /* For now, we create lfn entries for all files, + * except the "." and ".." directory references. + * This is to avoid difficulties with capitalization, + * as 8.3 filenames allow uppercase letters only. + * + * Theoretically it would be possible to leave + * the 8.3 entry alone if the basename and the + * extension have no mixed capitalization. + */ + if(name[0] == '.' && + ((name[1] == '.' && name[2] == '\0') || + name[1] == '\0') + ) + lfn_entry_count = 0; +#endif + } + else + { +#if FAT_LFN_SUPPORT + memcpy(buffer, name, 8); + + /* Minimize 8.3 name clashes by appending + * the lower byte of the cluster number. + */ + uint8_t num = dir_entry->cluster & 0xff; + + buffer[6] = (num < 0xa0) ? ('0' + (num >> 4)) : ('a' + (num >> 4)); + num &= 0x0f; + buffer[7] = (num < 0x0a) ? ('0' + num) : ('a' + num); +#else + return 0; +#endif + } + if(buffer[0] == FAT_DIRENTRY_DELETED) + buffer[0] = 0x05; + + /* fill directory entry buffer */ + memset(&buffer[11], 0, sizeof(buffer) - 11); + buffer[0x0b] = dir_entry->attributes; +#if FAT_DATETIME_SUPPORT + write16(&buffer[0x16], dir_entry->modification_time); + write16(&buffer[0x18], dir_entry->modification_date); +#endif +#if FAT_FAT32_SUPPORT + write16(&buffer[0x14], (uint16_t) (dir_entry->cluster >> 16)); +#endif + write16(&buffer[0x1a], dir_entry->cluster); + write32(&buffer[0x1c], dir_entry->file_size); + + /* write to disk */ +#if FAT_LFN_SUPPORT + if(!device_write(offset + (uint16_t) lfn_entry_count * 32, buffer, sizeof(buffer))) +#else + if(!device_write(offset, buffer, sizeof(buffer))) +#endif + return 0; + +#if FAT_LFN_SUPPORT + /* calculate checksum of 8.3 name */ + uint8_t checksum = fat_calc_83_checksum(buffer); + + /* write lfn entries */ + for(uint8_t lfn_entry = lfn_entry_count; lfn_entry > 0; --lfn_entry) + { + memset(buffer, 0xff, sizeof(buffer)); + + /* set file name */ + const char* long_name_curr = name + (lfn_entry - 1) * 13; + uint8_t i = 1; + while(i < 0x1f) + { + buffer[i++] = *long_name_curr; + buffer[i++] = 0; + + switch(i) + { + case 0x0b: + i = 0x0e; + break; + case 0x1a: + i = 0x1c; + break; + } + + if(!*long_name_curr++) + break; + } + + /* set index of lfn entry */ + buffer[0x00] = lfn_entry; + if(lfn_entry == lfn_entry_count) + buffer[0x00] |= FAT_DIRENTRY_LFNLAST; + + /* mark as lfn entry */ + buffer[0x0b] = 0x0f; + + /* set 8.3 checksum */ + buffer[0x0d] = checksum; + + /* clear reserved bytes */ + buffer[0x0c] = 0; + buffer[0x1a] = 0; + buffer[0x1b] = 0; + + /* write entry */ + device_write(offset, buffer, sizeof(buffer)); + + offset += sizeof(buffer); + } +#endif + + return 1; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_file + * Creates a file. + * + * Creates a file and obtains the directory entry of the + * new file. If the file to create already exists, the + * directory entry of the existing file will be returned + * within the dir_entry parameter. + * + * \note The file name is not checked for invalid characters. + * + * \note The generation of the short 8.3 file name is quite + * simple. The first eight characters are used for the filename. + * The extension, if any, is made up of the first three characters + * following the last dot within the long filename. If the + * filename (without the extension) is longer than eight characters, + * the lower byte of the cluster number replaces the last two + * characters to avoid name clashes. In any other case, it is your + * responsibility to avoid name clashes. + * + * \param[in] parent The handle of the directory in which to create the file. + * \param[in] file The name of the file to create. + * \param[out] dir_entry The directory entry to fill for the new (or existing) file. + * \returns 0 on failure, 1 on success, 2 if the file already existed. + * \see fat_delete_file + */ +uint8_t fat_create_file(struct fat_dir_struct* parent, const char* file, struct fat_dir_entry_struct* dir_entry) +{ + if(!parent || !file || !file[0] || !dir_entry) + return 0; + + /* check if the file already exists */ + while(1) + { + if(!fat_read_dir(parent, dir_entry)) + break; + + if(strcmp(file, dir_entry->long_name) == 0) + { + fat_reset_dir(parent); + return 2; + } + } + + struct fat_fs_struct* fs = parent->fs; + + /* prepare directory entry with values already known */ + memset(dir_entry, 0, sizeof(*dir_entry)); + strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1); + + /* find place where to store directory entry */ + if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry))) + return 0; + + /* write directory entry to disk */ + if(!fat_write_dir_entry(fs, dir_entry)) + return 0; + + return 1; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_file + * Deletes a file or directory. + * + * If a directory is deleted without first deleting its + * subdirectories and files, disk space occupied by these + * files will get wasted as there is no chance to release + * it and mark it as free. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] dir_entry The directory entry of the file to delete. + * \returns 0 on failure, 1 on success. + * \see fat_create_file + */ +uint8_t fat_delete_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry) +{ + if(!fs || !dir_entry) + return 0; + + /* get offset of the file's directory entry */ + offset_t dir_entry_offset = dir_entry->entry_offset; + if(!dir_entry_offset) + return 0; + +#if FAT_LFN_SUPPORT + uint8_t buffer[12]; + while(1) + { + /* read directory entry */ + if(!fs->partition->device_read(dir_entry_offset, buffer, sizeof(buffer))) + return 0; + + /* mark the directory entry as deleted */ + buffer[0] = FAT_DIRENTRY_DELETED; + + /* write back entry */ + if(!fs->partition->device_write(dir_entry_offset, buffer, sizeof(buffer))) + return 0; + + /* check if we deleted the whole entry */ + if(buffer[11] != 0x0f) + break; + + dir_entry_offset += 32; + } +#else + /* mark the directory entry as deleted */ + uint8_t first_char = FAT_DIRENTRY_DELETED; + if(!fs->partition->device_write(dir_entry_offset, &first_char, 1)) + return 0; +#endif + + /* We deleted the directory entry. The next thing to do is + * marking all occupied clusters as free. + */ + return (dir_entry->cluster == 0 || fat_free_clusters(fs, dir_entry->cluster)); +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_file + * Moves or renames a file. + * + * Changes a file's name, optionally moving it into another + * directory as well. Before calling this function, the + * target file name must not exist. Moving a file to a + * different filesystem (i.e. \a parent_new doesn't lie on + * \a fs) is not supported. + * + * After successfully renaming (and moving) the file, the + * given directory entry is updated such that it points to + * the file's new location. + * + * \note The notes which apply to fat_create_file() also + * apply to this function. + * + * \param[in] fs The filesystem on which to operate. + * \param[in,out] dir_entry The directory entry of the file to move. + * \param[in] parent_new The handle of the new parent directory of the file. + * \param[in] file_new The file's new name. + * \returns 0 on failure, 1 on success. + * \see fat_create_file, fat_delete_file, fat_move_dir + */ +uint8_t fat_move_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry, struct fat_dir_struct* parent_new, const char* file_new) +{ + if(!fs || !dir_entry || !parent_new || (file_new && !file_new[0])) + return 0; + if(fs != parent_new->fs) + return 0; + + /* use existing file name if none has been specified */ + if(!file_new) + file_new = dir_entry->long_name; + + /* create file with new file name */ + struct fat_dir_entry_struct dir_entry_new; + if(!fat_create_file(parent_new, file_new, &dir_entry_new)) + return 0; + + /* copy members of directory entry which do not change with rename */ + dir_entry_new.attributes = dir_entry->attributes; +#if FAT_DATETIME_SUPPORT + dir_entry_new.modification_time = dir_entry->modification_time; + dir_entry_new.modification_date = dir_entry->modification_date; +#endif + dir_entry_new.cluster = dir_entry->cluster; + dir_entry_new.file_size = dir_entry->file_size; + + /* make the new file name point to the old file's content */ + if(!fat_write_dir_entry(fs, &dir_entry_new)) + { + fat_delete_file(fs, &dir_entry_new); + return 0; + } + + /* delete the old file, but not its clusters, which have already been remapped above */ + dir_entry->cluster = 0; + if(!fat_delete_file(fs, dir_entry)) + return 0; + + *dir_entry = dir_entry_new; + return 1; +} +#endif + +#if DOXYGEN || FAT_WRITE_SUPPORT +/** + * \ingroup fat_dir + * Creates a directory. + * + * Creates a directory and obtains its directory entry. + * If the directory to create already exists, its + * directory entry will be returned within the dir_entry + * parameter. + * + * \note The notes which apply to fat_create_file() also + * apply to this function. + * + * \param[in] parent The handle of the parent directory of the new directory. + * \param[in] dir The name of the directory to create. + * \param[out] dir_entry The directory entry to fill for the new directory. + * \returns 0 on failure, 1 on success. + * \see fat_delete_dir + */ +uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry) +{ + if(!parent || !dir || !dir[0] || !dir_entry) + return 0; + + /* check if the file or directory already exists */ + while(fat_read_dir(parent, dir_entry)) + { + if(strcmp(dir, dir_entry->long_name) == 0) + { + fat_reset_dir(parent); + return 0; + } + } + + struct fat_fs_struct* fs = parent->fs; + + /* allocate cluster which will hold directory entries */ + cluster_t dir_cluster = fat_append_clusters(fs, 0, 1); + if(!dir_cluster) + return 0; + + /* clear cluster to prevent bogus directory entries */ + fat_clear_cluster(fs, dir_cluster); + + memset(dir_entry, 0, sizeof(*dir_entry)); + dir_entry->attributes = FAT_ATTRIB_DIR; + + /* create "." directory self reference */ + dir_entry->entry_offset = fs->header.cluster_zero_offset + + (offset_t) (dir_cluster - 2) * fs->header.cluster_size; + dir_entry->long_name[0] = '.'; + dir_entry->cluster = dir_cluster; + if(!fat_write_dir_entry(fs, dir_entry)) + { + fat_free_clusters(fs, dir_cluster); + return 0; + } + + /* create ".." parent directory reference */ + dir_entry->entry_offset += 32; + dir_entry->long_name[1] = '.'; + dir_entry->cluster = parent->dir_entry.cluster; + if(!fat_write_dir_entry(fs, dir_entry)) + { + fat_free_clusters(fs, dir_cluster); + return 0; + } + + /* fill directory entry */ + strncpy(dir_entry->long_name, dir, sizeof(dir_entry->long_name) - 1); + dir_entry->cluster = dir_cluster; + + /* find place where to store directory entry */ + if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry))) + { + fat_free_clusters(fs, dir_cluster); + return 0; + } + + /* write directory to disk */ + if(!fat_write_dir_entry(fs, dir_entry)) + { + fat_free_clusters(fs, dir_cluster); + return 0; + } + + return 1; +} +#endif + +/** + * \ingroup fat_dir + * Deletes a directory. + * + * This is just a synonym for fat_delete_file(). + * If a directory is deleted without first deleting its + * subdirectories and files, disk space occupied by these + * files will get wasted as there is no chance to release + * it and mark it as free. + * + * \param[in] fs The filesystem on which to operate. + * \param[in] dir_entry The directory entry of the directory to delete. + * \returns 0 on failure, 1 on success. + * \see fat_create_dir + */ +#ifdef DOXYGEN +uint8_t fat_delete_dir(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry); +#endif + +/** + * \ingroup fat_dir + * Moves or renames a directory. + * + * This is just a synonym for fat_move_file(). + * + * \param[in] fs The filesystem on which to operate. + * \param[in,out] dir_entry The directory entry of the directory to move. + * \param[in] parent_new The handle of the new parent directory. + * \param[in] dir_new The directory's new name. + * \returns 0 on failure, 1 on success. + * \see fat_create_dir, fat_delete_dir, fat_move_file + */ +#ifdef DOXYGEN +uint8_t fat_move_dir(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry, struct fat_dir_struct* parent_new, const char* dir_new); +#endif + +#if DOXYGEN || FAT_DATETIME_SUPPORT +/** + * \ingroup fat_file + * Returns the modification date of a file. + * + * \param[in] dir_entry The directory entry of which to return the modification date. + * \param[out] year The year the file was last modified. + * \param[out] month The month the file was last modified. + * \param[out] day The day the file was last modified. + */ +void fat_get_file_modification_date(const struct fat_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day) +{ + if(!dir_entry) + return; + + *year = 1980 + ((dir_entry->modification_date >> 9) & 0x7f); + *month = (dir_entry->modification_date >> 5) & 0x0f; + *day = (dir_entry->modification_date >> 0) & 0x1f; +} +#endif + +#if DOXYGEN || FAT_DATETIME_SUPPORT +/** + * \ingroup fat_file + * Returns the modification time of a file. + * + * \param[in] dir_entry The directory entry of which to return the modification time. + * \param[out] hour The hour the file was last modified. + * \param[out] min The min the file was last modified. + * \param[out] sec The sec the file was last modified. + */ +void fat_get_file_modification_time(const struct fat_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec) +{ + if(!dir_entry) + return; + + *hour = (dir_entry->modification_time >> 11) & 0x1f; + *min = (dir_entry->modification_time >> 5) & 0x3f; + *sec = ((dir_entry->modification_time >> 0) & 0x1f) * 2; +} +#endif + +#if DOXYGEN || (FAT_WRITE_SUPPORT && FAT_DATETIME_SUPPORT) +/** + * \ingroup fat_file + * Sets the modification time of a date. + * + * \param[in] dir_entry The directory entry for which to set the modification date. + * \param[in] year The year the file was last modified. + * \param[in] month The month the file was last modified. + * \param[in] day The day the file was last modified. + */ +void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day) +{ + if(!dir_entry) + return; + + dir_entry->modification_date = + ((year - 1980) << 9) | + ((uint16_t) month << 5) | + ((uint16_t) day << 0); +} +#endif + +#if DOXYGEN || (FAT_WRITE_SUPPORT && FAT_DATETIME_SUPPORT) +/** + * \ingroup fat_file + * Sets the modification time of a file. + * + * \param[in] dir_entry The directory entry for which to set the modification time. + * \param[in] hour The year the file was last modified. + * \param[in] min The month the file was last modified. + * \param[in] sec The day the file was last modified. + */ +void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec) +{ + if(!dir_entry) + return; + + dir_entry->modification_time = + ((uint16_t) hour << 11) | + ((uint16_t) min << 5) | + ((uint16_t) sec >> 1) ; +} +#endif + +/** + * \ingroup fat_fs + * Returns the amount of total storage capacity of the filesystem in bytes. + * + * \param[in] fs The filesystem on which to operate. + * \returns 0 on failure, the filesystem size in bytes otherwise. + */ +offset_t fat_get_fs_size(const struct fat_fs_struct* fs) +{ + if(!fs) + return 0; + +#if FAT_FAT32_SUPPORT + if(fs->partition->type == PARTITION_TYPE_FAT32) + return (offset_t) (fs->header.fat_size / 4 - 2) * fs->header.cluster_size; + else +#endif + return (offset_t) (fs->header.fat_size / 2 - 2) * fs->header.cluster_size; +} + +/** + * \ingroup fat_fs + * Returns the amount of free storage capacity on the filesystem in bytes. + * + * \note As the FAT filesystem is cluster based, this function does not + * return continuous values but multiples of the cluster size. + * + * \param[in] fs The filesystem on which to operate. + * \returns 0 on failure, the free filesystem space in bytes otherwise. + */ +offset_t fat_get_fs_free(const struct fat_fs_struct* fs) +{ + if(!fs) + return 0; + + uint8_t fat[32]; + struct fat_usage_count_callback_arg count_arg; + count_arg.cluster_count = 0; + count_arg.buffer_size = sizeof(fat); + + offset_t fat_offset = fs->header.fat_offset; + uint32_t fat_size = fs->header.fat_size; + while(fat_size > 0) + { + uintptr_t length = UINTPTR_MAX - 1; + if(fat_size < length) + length = fat_size; + + if(!fs->partition->device_read_interval(fat_offset, + fat, + sizeof(fat), + length, +#if FAT_FAT32_SUPPORT + (fs->partition->type == PARTITION_TYPE_FAT16) ? + fat_get_fs_free_16_callback : + fat_get_fs_free_32_callback, +#else + fat_get_fs_free_16_callback, +#endif + &count_arg + ) + ) + return 0; + + fat_offset += length; + fat_size -= length; + } + + return (offset_t) count_arg.cluster_count * fs->header.cluster_size; +} + +/** + * \ingroup fat_fs + * Callback function used for counting free clusters in a FAT. + */ +uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p) +{ + struct fat_usage_count_callback_arg* count_arg = (struct fat_usage_count_callback_arg*) p; + uintptr_t buffer_size = count_arg->buffer_size; + + for(uintptr_t i = 0; i < buffer_size; i += 2, buffer += 2) + { + uint16_t cluster = read16(buffer); + if(cluster == HTOL16(FAT16_CLUSTER_FREE)) + ++(count_arg->cluster_count); + } + + return 1; +} + +#if DOXYGEN || FAT_FAT32_SUPPORT +/** + * \ingroup fat_fs + * Callback function used for counting free clusters in a FAT32. + */ +uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p) +{ + struct fat_usage_count_callback_arg* count_arg = (struct fat_usage_count_callback_arg*) p; + uintptr_t buffer_size = count_arg->buffer_size; + + for(uintptr_t i = 0; i < buffer_size; i += 4, buffer += 4) + { + uint32_t cluster = read32(buffer); + if(cluster == HTOL32(FAT32_CLUSTER_FREE)) + ++(count_arg->cluster_count); + } + + return 1; +} +#endif + diff --git a/final_project/sd_reader/fat.h b/final_project/sd_reader/fat.h new file mode 100644 index 0000000..b67bb29 --- /dev/null +++ b/final_project/sd_reader/fat.h @@ -0,0 +1,131 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef FAT_H +#define FAT_H + +#include +#include "fat_config.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup fat + * + * @{ + */ +/** + * \file + * FAT header (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +/** + * \addtogroup fat_file + * @{ + */ + +/** The file is read-only. */ +#define FAT_ATTRIB_READONLY (1 << 0) +/** The file is hidden. */ +#define FAT_ATTRIB_HIDDEN (1 << 1) +/** The file is a system file. */ +#define FAT_ATTRIB_SYSTEM (1 << 2) +/** The file is empty and has the volume label as its name. */ +#define FAT_ATTRIB_VOLUME (1 << 3) +/** The file is a directory. */ +#define FAT_ATTRIB_DIR (1 << 4) +/** The file has to be archived. */ +#define FAT_ATTRIB_ARCHIVE (1 << 5) + +/** The given offset is relative to the beginning of the file. */ +#define FAT_SEEK_SET 0 +/** The given offset is relative to the current read/write position. */ +#define FAT_SEEK_CUR 1 +/** The given offset is relative to the end of the file. */ +#define FAT_SEEK_END 2 + +/** + * @} + */ + +struct partition_struct; +struct fat_fs_struct; +struct fat_file_struct; +struct fat_dir_struct; + +/** + * \ingroup fat_file + * Describes a directory entry. + */ +struct fat_dir_entry_struct +{ + /** The file's name, truncated to 31 characters. */ + char long_name[32]; + /** The file's attributes. Mask of the FAT_ATTRIB_* constants. */ + uint8_t attributes; +#if FAT_DATETIME_SUPPORT + /** Compressed representation of modification time. */ + uint16_t modification_time; + /** Compressed representation of modification date. */ + uint16_t modification_date; +#endif + /** The cluster in which the file's first byte resides. */ + cluster_t cluster; + /** The file's size. */ + uint32_t file_size; + /** The total disk offset of this directory entry. */ + offset_t entry_offset; +}; + +struct fat_fs_struct* fat_open(struct partition_struct* partition); +void fat_close(struct fat_fs_struct* fs); + +struct fat_file_struct* fat_open_file(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry); +void fat_close_file(struct fat_file_struct* fd); +intptr_t fat_read_file(struct fat_file_struct* fd, uint8_t* buffer, uintptr_t buffer_len); +intptr_t fat_write_file(struct fat_file_struct* fd, const uint8_t* buffer, uintptr_t buffer_len); +uint8_t fat_seek_file(struct fat_file_struct* fd, int32_t* offset, uint8_t whence); +uint8_t fat_resize_file(struct fat_file_struct* fd, uint32_t size); + +struct fat_dir_struct* fat_open_dir(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry); +void fat_close_dir(struct fat_dir_struct* dd); +uint8_t fat_read_dir(struct fat_dir_struct* dd, struct fat_dir_entry_struct* dir_entry); +uint8_t fat_reset_dir(struct fat_dir_struct* dd); + +uint8_t fat_create_file(struct fat_dir_struct* parent, const char* file, struct fat_dir_entry_struct* dir_entry); +uint8_t fat_delete_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry); +uint8_t fat_move_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry, struct fat_dir_struct* parent_new, const char* file_new); +uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry); +#define fat_delete_dir fat_delete_file +#define fat_move_dir fat_move_file + +void fat_get_file_modification_date(const struct fat_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day); +void fat_get_file_modification_time(const struct fat_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec); + +uint8_t fat_get_dir_entry_of_path(struct fat_fs_struct* fs, const char* path, struct fat_dir_entry_struct* dir_entry); + +offset_t fat_get_fs_size(const struct fat_fs_struct* fs); +offset_t fat_get_fs_free(const struct fat_fs_struct* fs); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/fat.o b/final_project/sd_reader/fat.o new file mode 100644 index 0000000..496c258 Binary files /dev/null and b/final_project/sd_reader/fat.o differ diff --git a/final_project/sd_reader/fat_config.h b/final_project/sd_reader/fat_config.h new file mode 100644 index 0000000..0ca8d4c --- /dev/null +++ b/final_project/sd_reader/fat_config.h @@ -0,0 +1,128 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef FAT_CONFIG_H +#define FAT_CONFIG_H + +#include +#include "sd_raw_config.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup fat + * + * @{ + */ +/** + * \file + * FAT configuration (license: GPLv2 or LGPLv2.1) + */ + +/** + * \ingroup fat_config + * Controls FAT write support. + * + * Set to 1 to enable FAT write support, set to 0 to disable it. + */ +#define FAT_WRITE_SUPPORT SD_RAW_WRITE_SUPPORT + +/** + * \ingroup fat_config + * Controls FAT long filename (LFN) support. + * + * Set to 1 to enable LFN support, set to 0 to disable it. + */ +#define FAT_LFN_SUPPORT 1 + +/** + * \ingroup fat_config + * Controls FAT date and time support. + * + * Set to 1 to enable FAT date and time stamping support. + */ +#define FAT_DATETIME_SUPPORT 0 + +/** + * \ingroup fat_config + * Controls FAT32 support. + * + * Set to 1 to enable FAT32 support. + */ +#define FAT_FAT32_SUPPORT SD_RAW_SDHC + +/** + * \ingroup fat_config + * Controls updates of directory entries. + * + * Set to 1 to delay directory entry updates until the file is closed. + * This can boost performance significantly, but may cause data loss + * if the file is not properly closed. + */ +#define FAT_DELAY_DIRENTRY_UPDATE 0 + +/** + * \ingroup fat_config + * Determines the function used for retrieving current date and time. + * + * Define this to the function call which shall be used to retrieve + * current date and time. + * + * \note Used only when FAT_DATETIME_SUPPORT is 1. + * + * \param[out] year Pointer to a \c uint16_t which receives the current year. + * \param[out] month Pointer to a \c uint8_t which receives the current month. + * \param[out] day Pointer to a \c uint8_t which receives the current day. + * \param[out] hour Pointer to a \c uint8_t which receives the current hour. + * \param[out] min Pointer to a \c uint8_t which receives the current minute. + * \param[out] sec Pointer to a \c uint8_t which receives the current sec. + */ +#define fat_get_datetime(year, month, day, hour, min, sec) \ + get_datetime(year, month, day, hour, min, sec) +/* forward declaration for the above */ +void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec); + +/** + * \ingroup fat_config + * Maximum number of filesystem handles. + */ +#define FAT_FS_COUNT 1 + +/** + * \ingroup fat_config + * Maximum number of file handles. + */ +#define FAT_FILE_COUNT 1 + +/** + * \ingroup fat_config + * Maximum number of directory handles. + */ +#define FAT_DIR_COUNT 2 + +/** + * @} + */ + +#if FAT_FAT32_SUPPORT + typedef uint32_t cluster_t; +#else + typedef uint16_t cluster_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/main.c b/final_project/sd_reader/main.c new file mode 100644 index 0000000..47298d4 --- /dev/null +++ b/final_project/sd_reader/main.c @@ -0,0 +1,666 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include "fat.h" +#include "fat_config.h" +#include "partition.h" +#include "sd_raw.h" +#include "sd_raw_config.h" +#include "uart.h" + +#define DEBUG 1 + +/** + * \mainpage MMC/SD/SDHC card library + * + * This project provides a general purpose library which implements read and write + * support for MMC, SD and SDHC memory cards. + * + * It includes + * - low-level \link sd_raw MMC, SD and SDHC read/write routines \endlink + * - \link partition partition table support \endlink + * - a simple \link fat FAT16/FAT32 read/write implementation \endlink + * + * \section circuit The circuit + * The circuit which was mainly used during development consists of an Atmel AVR + * microcontroller with some passive components. It is quite simple and provides + * an easy test environment. The circuit which can be downloaded on the + * project homepage has been + * improved with regard to operation stability. + * + * I used different microcontrollers during development, the ATmega8 with 8kBytes + * of flash, and its pin-compatible alternative, the ATmega168 with 16kBytes flash. + * The first one is the one I started with, but when I implemented FAT16 write + * support, I ran out of flash space and switched to the ATmega168. For FAT32, an + * ATmega328 is required. + * + * The circuit board is a self-made and self-soldered board consisting of a single + * copper layer and standard DIL components, except of the MMC/SD card connector. + * + * The connector is soldered to the bottom side of the board. It has a simple + * eject button which, when a card is inserted, needs some space beyond the connector + * itself. As an additional feature the connector has two electrical switches + * to detect wether a card is inserted and wether this card is write-protected. + * + * \section pictures Pictures + * \image html pic01.jpg "The circuit board used to implement and test this application." + * \image html pic02.jpg "The MMC/SD card connector on the soldering side of the circuit board." + * + * \section software The software + * The software is written in C (ISO C99). It might not be the smallest or + * the fastest one, but I think it is quite flexible. See the project's + * benchmark page to get an + * idea of the possible data rates. + * + * I implemented an example application providing a simple command prompt which is accessible + * via the UART at 9600 Baud. With commands similiar to the Unix shell you can browse different + * directories, read and write files, create new ones and delete them again. Not all commands are + * available in all software configurations. + * - cat \\n + * Writes a hexdump of \ to the terminal. + * - cd \\n + * Changes current working directory to \. + * - disk\n + * Shows card manufacturer, status, filesystem capacity and free storage space. + * - init\n + * Reinitializes and reopens the memory card. + * - ls\n + * Shows the content of the current directory. + * - mkdir \\n + * Creates a directory called \. + * - mv \ \\n + * Renames \ to \. + * - rm \\n + * Deletes \. + * - sync\n + * Ensures all buffered data is written to the card. + * - touch \\n + * Creates \. + * - write \ \\n + * Writes text to \, starting from \. The text is read + * from the UART, line by line. Finish with an empty line. + * + * \htmlonly + *

+ * The following table shows some typical code sizes in bytes, using the 20090330 release with a + * buffered read-write MMC/SD configuration, FAT16 and static memory allocation: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
layercode sizestatic RAM usage
MMC/SD2410518
Partition45617
FAT167928188
+ * + *

+ * The static RAM is mostly used for buffering memory card access, which + * improves performance and reduces implementation complexity. + *

+ * + *

+ * Please note that the numbers above do not include the C library functions + * used, e.g. some string functions. These will raise the numbers somewhat + * if they are not already used in other program parts. + *

+ * + *

+ * When opening a partition, filesystem, file or directory, a little amount + * of RAM is used, as listed in the following table. Depending on the library + * configuration, the memory is either allocated statically or dynamically. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
descriptordynamic/static RAM
partition17
filesystem26
file53
directory49
+ * + * \endhtmlonly + * + * \section adaptation Adapting the software to your needs + * The only hardware dependent part is the communication layer talking to the + * memory card. The other parts like partition table and FAT support are + * completely independent, you could use them even for managing Compact Flash + * cards or standard ATAPI hard disks. + * + * By changing the MCU* variables in the Makefile, you can use other Atmel + * microcontrollers or different clock speeds. You might also want to change + * the configuration defines in the files fat_config.h, partition_config.h, + * sd_raw_config.h and sd-reader_config.h. For example, you could disable + * write support completely if you only need read support. + * + * For further information, visit the project's + * FAQ page. + * + * \section bugs Bugs or comments? + * If you have comments or found a bug in the software - there might be some + * of them - you may contact me per mail at feedback@roland-riegel.de. + * + * \section acknowledgements Acknowledgements + * Thanks go to Ulrich Radig, who explained on his homepage how to interface + * MMC cards to the Atmel microcontroller (http://www.ulrichradig.de/). + * I adapted his work for my circuit. + * + * \section copyright Copyright 2006-2012 by Roland Riegel + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation (http://www.gnu.org/copyleft/gpl.html). + * At your option, you can alternatively redistribute and/or modify the following + * files under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation (http://www.gnu.org/copyleft/lgpl.html): + * - byteordering.c + * - byteordering.h + * - fat.c + * - fat.h + * - fat_config.h + * - partition.c + * - partition.h + * - partition_config.h + * - sd_raw.c + * - sd_raw.h + * - sd_raw_config.h + * - sd-reader_config.h + */ + +static uint8_t read_line(char* buffer, uint8_t buffer_length); +static uint32_t strtolong(const char* str); +static uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry); +static struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name); +static uint8_t print_disk_info(const struct fat_fs_struct* fs); + +int main() +{ + /* we will just use ordinary idle mode */ + set_sleep_mode(SLEEP_MODE_IDLE); + + /* setup uart */ + uart_init(); + + while(1) + { + /* setup sd card slot */ + if(!sd_raw_init()) + { +#if DEBUG + uart_puts_p(PSTR("MMC/SD initialization failed\n")); +#endif + continue; + } + + /* open first partition */ + struct partition_struct* partition = partition_open(sd_raw_read, + sd_raw_read_interval, +#if SD_RAW_WRITE_SUPPORT + sd_raw_write, + sd_raw_write_interval, +#else + 0, + 0, +#endif + 0 + ); + + if(!partition) + { + /* If the partition did not open, assume the storage device + * is a "superfloppy", i.e. has no MBR. + */ + partition = partition_open(sd_raw_read, + sd_raw_read_interval, +#if SD_RAW_WRITE_SUPPORT + sd_raw_write, + sd_raw_write_interval, +#else + 0, + 0, +#endif + -1 + ); + if(!partition) + { +#if DEBUG + uart_puts_p(PSTR("opening partition failed\n")); +#endif + continue; + } + } + + /* open file system */ + struct fat_fs_struct* fs = fat_open(partition); + if(!fs) + { +#if DEBUG + uart_puts_p(PSTR("opening filesystem failed\n")); +#endif + continue; + } + + /* open root directory */ + struct fat_dir_entry_struct directory; + fat_get_dir_entry_of_path(fs, "/", &directory); + + struct fat_dir_struct* dd = fat_open_dir(fs, &directory); + if(!dd) + { +#if DEBUG + uart_puts_p(PSTR("opening root directory failed\n")); +#endif + continue; + } + + /* print some card information as a boot message */ + print_disk_info(fs); + + /* provide a simple shell */ + char buffer[24]; + while(1) + { + /* print prompt */ + uart_putc('>'); + uart_putc(' '); + + /* read command */ + char* command = buffer; + if(read_line(command, sizeof(buffer)) < 1) + continue; + + /* execute command */ + if(strcmp_P(command, PSTR("init")) == 0) + { + break; + } + else if(strncmp_P(command, PSTR("cd "), 3) == 0) + { + command += 3; + if(command[0] == '\0') + continue; + + /* change directory */ + struct fat_dir_entry_struct subdir_entry; + if(find_file_in_dir(fs, dd, command, &subdir_entry)) + { + struct fat_dir_struct* dd_new = fat_open_dir(fs, &subdir_entry); + if(dd_new) + { + fat_close_dir(dd); + dd = dd_new; + continue; + } + } + + uart_puts_p(PSTR("directory not found: ")); + uart_puts(command); + uart_putc('\n'); + } + else if(strcmp_P(command, PSTR("ls")) == 0) + { + /* print directory listing */ + struct fat_dir_entry_struct dir_entry; + while(fat_read_dir(dd, &dir_entry)) + { + uint8_t spaces = sizeof(dir_entry.long_name) - strlen(dir_entry.long_name) + 4; + + uart_puts(dir_entry.long_name); + uart_putc(dir_entry.attributes & FAT_ATTRIB_DIR ? '/' : ' '); + while(spaces--) + uart_putc(' '); + uart_putdw_dec(dir_entry.file_size); + uart_putc('\n'); + } + } + else if(strncmp_P(command, PSTR("cat "), 4) == 0) + { + command += 4; + if(command[0] == '\0') + continue; + + /* search file in current directory and open it */ + struct fat_file_struct* fd = open_file_in_dir(fs, dd, command); + if(!fd) + { + uart_puts_p(PSTR("error opening ")); + uart_puts(command); + uart_putc('\n'); + continue; + } + + /* print file contents */ + uint8_t buffer[8]; + uint32_t offset = 0; + intptr_t count; + while((count = fat_read_file(fd, buffer, sizeof(buffer))) > 0) + { + uart_putdw_hex(offset); + uart_putc(':'); + for(intptr_t i = 0; i < count; ++i) + { + uart_putc(' '); + uart_putc_hex(buffer[i]); + } + uart_putc('\n'); + offset += 8; + } + + fat_close_file(fd); + } + else if(strcmp_P(command, PSTR("disk")) == 0) + { + if(!print_disk_info(fs)) + uart_puts_p(PSTR("error reading disk info\n")); + } +#if FAT_WRITE_SUPPORT + else if(strncmp_P(command, PSTR("rm "), 3) == 0) + { + command += 3; + if(command[0] == '\0') + continue; + + struct fat_dir_entry_struct file_entry; + if(find_file_in_dir(fs, dd, command, &file_entry)) + { + if(fat_delete_file(fs, &file_entry)) + continue; + } + + uart_puts_p(PSTR("error deleting file: ")); + uart_puts(command); + uart_putc('\n'); + } + else if(strncmp_P(command, PSTR("touch "), 6) == 0) + { + command += 6; + if(command[0] == '\0') + continue; + + struct fat_dir_entry_struct file_entry; + if(!fat_create_file(dd, command, &file_entry)) + { + uart_puts_p(PSTR("error creating file: ")); + uart_puts(command); + uart_putc('\n'); + } + } + else if(strncmp_P(command, PSTR("mv "), 3) == 0) + { + command += 3; + if(command[0] == '\0') + continue; + + char* target = command; + while(*target != ' ' && *target != '\0') + ++target; + + if(*target == ' ') + *target++ = '\0'; + else + continue; + + struct fat_dir_entry_struct file_entry; + if(find_file_in_dir(fs, dd, command, &file_entry)) + { + if(fat_move_file(fs, &file_entry, dd, target)) + continue; + } + + uart_puts_p(PSTR("error moving file: ")); + uart_puts(command); + uart_putc('\n'); + } + else if(strncmp_P(command, PSTR("write "), 6) == 0) + { + command += 6; + if(command[0] == '\0') + continue; + + char* offset_value = command; + while(*offset_value != ' ' && *offset_value != '\0') + ++offset_value; + + if(*offset_value == ' ') + *offset_value++ = '\0'; + else + continue; + + /* search file in current directory and open it */ + struct fat_file_struct* fd = open_file_in_dir(fs, dd, command); + if(!fd) + { + uart_puts_p(PSTR("error opening ")); + uart_puts(command); + uart_putc('\n'); + continue; + } + + int32_t offset = strtolong(offset_value); + if(!fat_seek_file(fd, &offset, FAT_SEEK_SET)) + { + uart_puts_p(PSTR("error seeking on ")); + uart_puts(command); + uart_putc('\n'); + + fat_close_file(fd); + continue; + } + + /* read text from the shell and write it to the file */ + uint8_t data_len; + while(1) + { + /* give a different prompt */ + uart_putc('<'); + uart_putc(' '); + + /* read one line of text */ + data_len = read_line(buffer, sizeof(buffer)); + if(!data_len) + break; + + /* write text to file */ + if(fat_write_file(fd, (uint8_t*) buffer, data_len) != data_len) + { + uart_puts_p(PSTR("error writing to file\n")); + break; + } + } + + fat_close_file(fd); + } + else if(strncmp_P(command, PSTR("mkdir "), 6) == 0) + { + command += 6; + if(command[0] == '\0') + continue; + + struct fat_dir_entry_struct dir_entry; + if(!fat_create_dir(dd, command, &dir_entry)) + { + uart_puts_p(PSTR("error creating directory: ")); + uart_puts(command); + uart_putc('\n'); + } + } +#endif +#if SD_RAW_WRITE_BUFFERING + else if(strcmp_P(command, PSTR("sync")) == 0) + { + if(!sd_raw_sync()) + uart_puts_p(PSTR("error syncing disk\n")); + } +#endif + else + { + uart_puts_p(PSTR("unknown command: ")); + uart_puts(command); + uart_putc('\n'); + } + } + + /* close directory */ + fat_close_dir(dd); + + /* close file system */ + fat_close(fs); + + /* close partition */ + partition_close(partition); + } + + return 0; +} + +uint8_t read_line(char* buffer, uint8_t buffer_length) +{ + memset(buffer, 0, buffer_length); + + uint8_t read_length = 0; + while(read_length < buffer_length - 1) + { + uint8_t c = uart_getc(); + + if(c == 0x08 || c == 0x7f) + { + if(read_length < 1) + continue; + + --read_length; + buffer[read_length] = '\0'; + + uart_putc(0x08); + uart_putc(' '); + uart_putc(0x08); + + continue; + } + + uart_putc(c); + + if(c == '\n') + { + buffer[read_length] = '\0'; + break; + } + else + { + buffer[read_length] = c; + ++read_length; + } + } + + return read_length; +} + +uint32_t strtolong(const char* str) +{ + uint32_t l = 0; + while(*str >= '0' && *str <= '9') + l = l * 10 + (*str++ - '0'); + + return l; +} + +uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry) +{ + while(fat_read_dir(dd, dir_entry)) + { + if(strcmp(dir_entry->long_name, name) == 0) + { + fat_reset_dir(dd); + return 1; + } + } + + return 0; +} + +struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name) +{ + struct fat_dir_entry_struct file_entry; + if(!find_file_in_dir(fs, dd, name, &file_entry)) + return 0; + + return fat_open_file(fs, &file_entry); +} + +uint8_t print_disk_info(const struct fat_fs_struct* fs) +{ + if(!fs) + return 0; + + struct sd_raw_info disk_info; + if(!sd_raw_get_info(&disk_info)) + return 0; + + uart_puts_p(PSTR("manuf: 0x")); uart_putc_hex(disk_info.manufacturer); uart_putc('\n'); + uart_puts_p(PSTR("oem: ")); uart_puts((char*) disk_info.oem); uart_putc('\n'); + uart_puts_p(PSTR("prod: ")); uart_puts((char*) disk_info.product); uart_putc('\n'); + uart_puts_p(PSTR("rev: ")); uart_putc_hex(disk_info.revision); uart_putc('\n'); + uart_puts_p(PSTR("serial: 0x")); uart_putdw_hex(disk_info.serial); uart_putc('\n'); + uart_puts_p(PSTR("date: ")); uart_putw_dec(disk_info.manufacturing_month); uart_putc('/'); + uart_putw_dec(disk_info.manufacturing_year); uart_putc('\n'); + uart_puts_p(PSTR("size: ")); uart_putdw_dec(disk_info.capacity / 1024 / 1024); uart_puts_p(PSTR("MB\n")); + uart_puts_p(PSTR("copy: ")); uart_putw_dec(disk_info.flag_copy); uart_putc('\n'); + uart_puts_p(PSTR("wr.pr.: ")); uart_putw_dec(disk_info.flag_write_protect_temp); uart_putc('/'); + uart_putw_dec(disk_info.flag_write_protect); uart_putc('\n'); + uart_puts_p(PSTR("format: ")); uart_putw_dec(disk_info.format); uart_putc('\n'); + uart_puts_p(PSTR("free: ")); uart_putdw_dec(fat_get_fs_free(fs)); uart_putc('/'); + uart_putdw_dec(fat_get_fs_size(fs)); uart_putc('\n'); + + return 1; +} + +#if FAT_DATETIME_SUPPORT +void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec) +{ + *year = 2007; + *month = 1; + *day = 1; + *hour = 0; + *min = 0; + *sec = 0; +} +#endif + + diff --git a/final_project/sd_reader/main.o b/final_project/sd_reader/main.o new file mode 100644 index 0000000..f9ecb15 Binary files /dev/null and b/final_project/sd_reader/main.o differ diff --git a/final_project/sd_reader/partition.c b/final_project/sd_reader/partition.c new file mode 100644 index 0000000..6c5d982 --- /dev/null +++ b/final_project/sd_reader/partition.c @@ -0,0 +1,155 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "byteordering.h" +#include "partition.h" +#include "partition_config.h" +#include "sd-reader_config.h" + +#include + +#if USE_DYNAMIC_MEMORY + #include +#endif + +/** + * \addtogroup partition Partition table support + * + * Support for reading partition tables and access to partitions. + * + * @{ + */ +/** + * \file + * Partition table implementation (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +/** + * \addtogroup partition_config Configuration of partition table support + * Preprocessor defines to configure the partition support. + */ + +#if !USE_DYNAMIC_MEMORY +static struct partition_struct partition_handles[PARTITION_COUNT]; +#endif + +/** + * Opens a partition. + * + * Opens a partition by its index number and returns a partition + * handle which describes the opened partition. + * + * \note This function does not support extended partitions. + * + * \param[in] device_read A function pointer which is used to read from the disk. + * \param[in] device_read_interval A function pointer which is used to read in constant intervals from the disk. + * \param[in] device_write A function pointer which is used to write to the disk. + * \param[in] device_write_interval A function pointer which is used to write a data stream to disk. + * \param[in] index The index of the partition which should be opened, range 0 to 3. + * A negative value is allowed as well. In this case, the partition opened is + * not checked for existance, begins at offset zero, has a length of zero + * and is of an unknown type. Use this in case you want to open the whole device + * as a single partition (e.g. for "super floppy" use). + * \returns 0 on failure, a partition descriptor on success. + * \see partition_close + */ +struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index) +{ + struct partition_struct* new_partition = 0; + uint8_t buffer[0x10]; + + if(!device_read || !device_read_interval || index >= 4) + return 0; + + if(index >= 0) + { + /* read specified partition table index */ + if(!device_read(0x01be + index * 0x10, buffer, sizeof(buffer))) + return 0; + + /* abort on empty partition entry */ + if(buffer[4] == 0x00) + return 0; + } + + /* allocate partition descriptor */ +#if USE_DYNAMIC_MEMORY + new_partition = malloc(sizeof(*new_partition)); + if(!new_partition) + return 0; +#else + new_partition = partition_handles; + uint8_t i; + for(i = 0; i < PARTITION_COUNT; ++i) + { + if(new_partition->type == PARTITION_TYPE_FREE) + break; + + ++new_partition; + } + if(i >= PARTITION_COUNT) + return 0; +#endif + + memset(new_partition, 0, sizeof(*new_partition)); + + /* fill partition descriptor */ + new_partition->device_read = device_read; + new_partition->device_read_interval = device_read_interval; + new_partition->device_write = device_write; + new_partition->device_write_interval = device_write_interval; + + if(index >= 0) + { + new_partition->type = buffer[4]; + new_partition->offset = read32(&buffer[8]); + new_partition->length = read32(&buffer[12]); + } + else + { + new_partition->type = 0xff; + } + + return new_partition; +} + +/** + * Closes a partition. + * + * This function destroys a partition descriptor which was + * previously obtained from a call to partition_open(). + * When this function returns, the given descriptor will be + * invalid. + * + * \param[in] partition The partition descriptor to destroy. + * \returns 0 on failure, 1 on success. + * \see partition_open + */ +uint8_t partition_close(struct partition_struct* partition) +{ + if(!partition) + return 0; + + /* destroy partition descriptor */ +#if USE_DYNAMIC_MEMORY + free(partition); +#else + partition->type = PARTITION_TYPE_FREE; +#endif + + return 1; +} + +/** + * @} + */ + diff --git a/final_project/sd_reader/partition.h b/final_project/sd_reader/partition.h new file mode 100644 index 0000000..d559c6e --- /dev/null +++ b/final_project/sd_reader/partition.h @@ -0,0 +1,212 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef PARTITION_H +#define PARTITION_H + +#include +#include "sd_raw_config.h" +#include "partition_config.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup partition + * + * @{ + */ +/** + * \file + * Partition table header (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +/** + * The partition table entry is not used. + */ +#define PARTITION_TYPE_FREE 0x00 +/** + * The partition contains a FAT12 filesystem. + */ +#define PARTITION_TYPE_FAT12 0x01 +/** + * The partition contains a FAT16 filesystem with 32MB maximum. + */ +#define PARTITION_TYPE_FAT16_32MB 0x04 +/** + * The partition is an extended partition with its own partition table. + */ +#define PARTITION_TYPE_EXTENDED 0x05 +/** + * The partition contains a FAT16 filesystem. + */ +#define PARTITION_TYPE_FAT16 0x06 +/** + * The partition contains a FAT32 filesystem. + */ +#define PARTITION_TYPE_FAT32 0x0b +/** + * The partition contains a FAT32 filesystem with LBA. + */ +#define PARTITION_TYPE_FAT32_LBA 0x0c +/** + * The partition contains a FAT16 filesystem with LBA. + */ +#define PARTITION_TYPE_FAT16_LBA 0x0e +/** + * The partition is an extended partition with LBA. + */ +#define PARTITION_TYPE_EXTENDED_LBA 0x0f +/** + * The partition has an unknown type. + */ +#define PARTITION_TYPE_UNKNOWN 0xff + +/** + * A function pointer used to read from the partition. + * + * \param[in] offset The offset on the device where to start reading. + * \param[out] buffer The buffer into which to place the data. + * \param[in] length The count of bytes to read. + */ +typedef uint8_t (*device_read_t)(offset_t offset, uint8_t* buffer, uintptr_t length); +/** + * A function pointer passed to a \c device_read_interval_t. + * + * \param[in] buffer The buffer which contains the data just read. + * \param[in] offset The offset from which the data in \c buffer was read. + * \param[in] p An opaque pointer. + * \see device_read_interval_t + */ +typedef uint8_t (*device_read_callback_t)(uint8_t* buffer, offset_t offset, void* p); +/** + * A function pointer used to continuously read units of \c interval bytes + * and call a callback function. + * + * This function starts reading at the specified offset. Every \c interval bytes, + * it calls the callback function with the associated data buffer. + * + * By returning zero, the callback may stop reading. + * + * \param[in] offset Offset from which to start reading. + * \param[in] buffer Pointer to a buffer which is at least interval bytes in size. + * \param[in] interval Number of bytes to read before calling the callback function. + * \param[in] length Number of bytes to read altogether. + * \param[in] callback The function to call every interval bytes. + * \param[in] p An opaque pointer directly passed to the callback function. + * \returns 0 on failure, 1 on success + * \see device_read_t + */ +typedef uint8_t (*device_read_interval_t)(offset_t offset, uint8_t* buffer, uintptr_t interval, uintptr_t length, device_read_callback_t callback, void* p); +/** + * A function pointer used to write to the partition. + * + * \param[in] offset The offset on the device where to start writing. + * \param[in] buffer The buffer which to write. + * \param[in] length The count of bytes to write. + */ +typedef uint8_t (*device_write_t)(offset_t offset, const uint8_t* buffer, uintptr_t length); +/** + * A function pointer passed to a \c device_write_interval_t. + * + * \param[in] buffer The buffer which receives the data to write. + * \param[in] offset The offset to which the data in \c buffer will be written. + * \param[in] p An opaque pointer. + * \returns The number of bytes put into \c buffer + * \see device_write_interval_t + */ +typedef uintptr_t (*device_write_callback_t)(uint8_t* buffer, offset_t offset, void* p); +/** + * A function pointer used to continuously write a data stream obtained from + * a callback function. + * + * This function starts writing at the specified offset. To obtain the + * next bytes to write, it calls the callback function. The callback fills the + * provided data buffer and returns the number of bytes it has put into the buffer. + * + * By returning zero, the callback may stop writing. + * + * \param[in] offset Offset where to start writing. + * \param[in] buffer Pointer to a buffer which is used for the callback function. + * \param[in] length Number of bytes to write in total. May be zero for endless writes. + * \param[in] callback The function used to obtain the bytes to write. + * \param[in] p An opaque pointer directly passed to the callback function. + * \returns 0 on failure, 1 on success + * \see device_write_t + */ +typedef uint8_t (*device_write_interval_t)(offset_t offset, uint8_t* buffer, uintptr_t length, device_write_callback_t callback, void* p); + +/** + * Describes a partition. + */ +struct partition_struct +{ + /** + * The function which reads data from the partition. + * + * \note The offset given to this function is relative to the whole disk, + * not to the start of the partition. + */ + device_read_t device_read; + /** + * The function which repeatedly reads a constant amount of data from the partition. + * + * \note The offset given to this function is relative to the whole disk, + * not to the start of the partition. + */ + device_read_interval_t device_read_interval; + /** + * The function which writes data to the partition. + * + * \note The offset given to this function is relative to the whole disk, + * not to the start of the partition. + */ + device_write_t device_write; + /** + * The function which repeatedly writes data to the partition. + * + * \note The offset given to this function is relative to the whole disk, + * not to the start of the partition. + */ + device_write_interval_t device_write_interval; + + /** + * The type of the partition. + * + * Compare this value to the PARTITION_TYPE_* constants. + */ + uint8_t type; + /** + * The offset in blocks on the disk where this partition starts. + */ + uint32_t offset; + /** + * The length in blocks of this partition. + */ + uint32_t length; +}; + +struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index); +uint8_t partition_close(struct partition_struct* partition); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/partition.o b/final_project/sd_reader/partition.o new file mode 100644 index 0000000..ca73887 Binary files /dev/null and b/final_project/sd_reader/partition.o differ diff --git a/final_project/sd_reader/partition_config.h b/final_project/sd_reader/partition_config.h new file mode 100644 index 0000000..0b49138 --- /dev/null +++ b/final_project/sd_reader/partition_config.h @@ -0,0 +1,44 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef PARTITION_CONFIG_H +#define PARTITION_CONFIG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup partition + * + * @{ + */ +/** + * \file + * Partition configuration (license: GPLv2 or LGPLv2.1) + */ + +/** + * \ingroup partition_config + * Maximum number of partition handles. + */ +#define PARTITION_COUNT 1 + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/sd-reader.map b/final_project/sd_reader/sd-reader.map new file mode 100644 index 0000000..d0b9c52 --- /dev/null +++ b/final_project/sd_reader/sd-reader.map @@ -0,0 +1,735 @@ +Archive member included to satisfy reference by file (symbol) + +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + fat.o (__mulsi3) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + uart.o (__udivmodhi4) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + fat.o (__divmodhi4) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + uart.o (__udivmodsi4) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o (exit) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + sd_raw.o (__tablejump2__) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + fat.o (__do_copy_data) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + partition.o (__do_clear_bss) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + fat.o (__umulhisi3) +/usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + uart.o (__muluhisi3) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp_P.o) + main.o (strcmp_P) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp_P.o) + main.o (strncmp_P) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memcpy.o) + sd_raw.o (memcpy) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memset.o) + fat.o (memset) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strchr.o) + fat.o (strchr) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp.o) + fat.o (strcmp) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp.o) + fat.o (strncmp) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncpy.o) + fat.o (strncpy) +/usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strrchr.o) + fat.o (strrchr) + +Memory Configuration + +Name Origin Length Attributes +text 0x0000000000000000 0x0000000000020000 xr +data 0x0000000000800060 0x000000000000ffa0 rw !x +eeprom 0x0000000000810000 0x0000000000010000 rw !x +fuse 0x0000000000820000 0x0000000000000003 rw !x +lock 0x0000000000830000 0x0000000000000400 rw !x +signature 0x0000000000840000 0x0000000000000400 rw !x +user_signatures 0x0000000000850000 0x0000000000000400 rw !x +*default* 0x0000000000000000 0xffffffffffffffff + +Linker script and memory map + +Address of section .data set to 0x800100 +LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o +LOAD partition.o +LOAD sd_raw.o +LOAD uart.o +LOAD byteordering.o +LOAD fat.o +LOAD main.o +START GROUP +LOAD /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a +LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libm.a +LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a +LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libatmega168.a +END GROUP + 0x0000000000020000 __TEXT_REGION_LENGTH__ = DEFINED (__TEXT_REGION_LENGTH__)?__TEXT_REGION_LENGTH__:0x20000 + 0x000000000000ffa0 __DATA_REGION_LENGTH__ = DEFINED (__DATA_REGION_LENGTH__)?__DATA_REGION_LENGTH__:0xffa0 + 0x0000000000010000 __EEPROM_REGION_LENGTH__ = DEFINED (__EEPROM_REGION_LENGTH__)?__EEPROM_REGION_LENGTH__:0x10000 + [0x0000000000000003] __FUSE_REGION_LENGTH__ = DEFINED (__FUSE_REGION_LENGTH__)?__FUSE_REGION_LENGTH__:0x400 + 0x0000000000000400 __LOCK_REGION_LENGTH__ = DEFINED (__LOCK_REGION_LENGTH__)?__LOCK_REGION_LENGTH__:0x400 + 0x0000000000000400 __SIGNATURE_REGION_LENGTH__ = DEFINED (__SIGNATURE_REGION_LENGTH__)?__SIGNATURE_REGION_LENGTH__:0x400 + 0x0000000000000400 __USER_SIGNATURE_REGION_LENGTH__ = DEFINED (__USER_SIGNATURE_REGION_LENGTH__)?__USER_SIGNATURE_REGION_LENGTH__:0x400 + +.hash + *(.hash) + +.dynsym + *(.dynsym) + +.dynstr + *(.dynstr) + +.gnu.version + *(.gnu.version) + +.gnu.version_d + *(.gnu.version_d) + +.gnu.version_r + *(.gnu.version_r) + +.rel.init + *(.rel.init) + +.rela.init + *(.rela.init) + +.rel.text + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t*) + +.rela.text + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t*) + +.rel.fini + *(.rel.fini) + +.rela.fini + *(.rela.fini) + +.rel.rodata + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r*) + +.rela.rodata + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r*) + +.rel.data + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d*) + +.rela.data + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d*) + +.rel.ctors + *(.rel.ctors) + +.rela.ctors + *(.rela.ctors) + +.rel.dtors + *(.rel.dtors) + +.rela.dtors + *(.rela.dtors) + +.rel.got + *(.rel.got) + +.rela.got + *(.rela.got) + +.rel.bss + *(.rel.bss) + +.rela.bss + *(.rela.bss) + +.rel.plt + *(.rel.plt) + +.rela.plt + *(.rela.plt) + +.text 0x0000000000000000 0x3574 + *(.vectors) + .vectors 0x0000000000000000 0x68 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + 0x0000000000000000 __vectors + 0x0000000000000000 __vector_default + *(.vectors) + *(.progmem.gcc*) + .progmem.gcc_sw_table + 0x0000000000000068 0x1e sd_raw.o + 0x0000000000000086 . = ALIGN (0x2) + 0x0000000000000086 __trampolines_start = . + *(.trampolines) + .trampolines 0x0000000000000086 0x0 linker stubs + *(.trampolines*) + 0x0000000000000086 __trampolines_end = . + *libprintf_flt.a:*(.progmem.data) + *libc.a:*(.progmem.data) + *(.progmem*) + .progmem.data 0x0000000000000086 0x20c main.o + 0x0000000000000292 . = ALIGN (0x2) + *(.jumptables) + *(.jumptables*) + *(.lowtext) + *(.lowtext*) + 0x0000000000000292 __ctors_start = . + *(.ctors) + 0x0000000000000292 __ctors_end = . + 0x0000000000000292 __dtors_start = . + *(.dtors) + 0x0000000000000292 __dtors_end = . + SORT(*)(.ctors) + SORT(*)(.dtors) + *(.init0) + .init0 0x0000000000000292 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + 0x0000000000000292 __init + *(.init0) + *(.init1) + *(.init1) + *(.init2) + .init2 0x0000000000000292 0xc /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + *(.init2) + *(.init3) + *(.init3) + *(.init4) + .init4 0x000000000000029e 0x16 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + 0x000000000000029e __do_copy_data + .init4 0x00000000000002b4 0x10 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + 0x00000000000002b4 __do_clear_bss + *(.init4) + *(.init5) + *(.init5) + *(.init6) + *(.init6) + *(.init7) + *(.init7) + *(.init8) + *(.init8) + *(.init9) + .init9 0x00000000000002c4 0x8 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + *(.init9) + *(.text) + .text 0x00000000000002cc 0x4 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + 0x00000000000002cc __vector_22 + 0x00000000000002cc __vector_1 + 0x00000000000002cc __vector_24 + 0x00000000000002cc __vector_12 + 0x00000000000002cc __bad_interrupt + 0x00000000000002cc __vector_6 + 0x00000000000002cc __vector_3 + 0x00000000000002cc __vector_23 + 0x00000000000002cc __vector_25 + 0x00000000000002cc __vector_11 + 0x00000000000002cc __vector_13 + 0x00000000000002cc __vector_17 + 0x00000000000002cc __vector_19 + 0x00000000000002cc __vector_7 + 0x00000000000002cc __vector_5 + 0x00000000000002cc __vector_4 + 0x00000000000002cc __vector_9 + 0x00000000000002cc __vector_2 + 0x00000000000002cc __vector_21 + 0x00000000000002cc __vector_15 + 0x00000000000002cc __vector_8 + 0x00000000000002cc __vector_14 + 0x00000000000002cc __vector_10 + 0x00000000000002cc __vector_16 + 0x00000000000002cc __vector_20 + .text 0x00000000000002d0 0x126 partition.o + 0x00000000000002d0 partition_open + 0x00000000000003e6 partition_close + .text 0x00000000000003f6 0x7de sd_raw.o + 0x0000000000000484 sd_raw_available + 0x0000000000000490 sd_raw_locked + 0x000000000000049e sd_raw_sync + 0x00000000000004d2 sd_raw_read + 0x0000000000000602 sd_raw_init + 0x0000000000000714 sd_raw_read_interval + 0x00000000000007ba sd_raw_write + 0x0000000000000930 sd_raw_write_interval + 0x00000000000009d8 sd_raw_get_info + .text 0x0000000000000bd4 0x224 uart.o + 0x0000000000000bd4 uart_init + 0x0000000000000bec uart_putc + 0x0000000000000c0a uart_putc_hex + 0x0000000000000c34 uart_putw_hex + 0x0000000000000c46 uart_putdw_hex + 0x0000000000000c66 uart_putw_dec + 0x0000000000000cde uart_putdw_dec + 0x0000000000000d96 uart_puts + 0x0000000000000dae uart_puts_p + 0x0000000000000dcc uart_getc + 0x0000000000000df6 __vector_18 + .text 0x0000000000000df8 0x28 byteordering.o + 0x0000000000000df8 read16 + 0x0000000000000e00 read32 + 0x0000000000000e0c write16 + 0x0000000000000e14 write32 + .text 0x0000000000000e20 0x1dd4 fat.o + 0x00000000000018da fat_open + 0x0000000000001bec fat_close + 0x0000000000001bf8 fat_open_file + 0x0000000000001c58 fat_close_file + 0x0000000000001c64 fat_read_file + 0x0000000000001e6e fat_write_file + 0x00000000000020f6 fat_resize_file + 0x00000000000022de fat_seek_file + 0x0000000000002380 fat_open_dir + 0x00000000000023e8 fat_close_dir + 0x00000000000023f4 fat_reset_dir + 0x000000000000240e fat_read_dir + 0x000000000000259c fat_get_dir_entry_of_path + 0x00000000000026ae fat_create_file + 0x000000000000275c fat_delete_file + 0x0000000000002848 fat_move_file + 0x0000000000002934 fat_create_dir + 0x0000000000002aa2 fat_get_fs_size + 0x0000000000002ad6 fat_get_fs_free + .text 0x0000000000002bf4 0x23a main.o + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp_P.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp_P.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memcpy.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memset.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strchr.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncpy.o) + .text 0x0000000000002e2e 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strrchr.o) + 0x0000000000002e2e . = ALIGN (0x2) + *(.text.*) + .text.startup 0x0000000000002e2e 0x588 main.o + 0x0000000000002e2e main + .text.libgcc.mul + 0x00000000000033b6 0x20 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + 0x00000000000033b6 __mulsi3 + .text.libgcc.div + 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text.libgcc 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text.libgcc.prologue + 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text.libgcc.builtins + 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text.libgcc.fmul + 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text.libgcc.fixed + 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .text.libgcc.mul + 0x00000000000033d6 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text.libgcc.div + 0x00000000000033d6 0x28 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + 0x00000000000033d6 __udivmodhi4 + .text.libgcc 0x00000000000033fe 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text.libgcc.prologue + 0x00000000000033fe 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text.libgcc.builtins + 0x00000000000033fe 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text.libgcc.fmul + 0x00000000000033fe 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text.libgcc.fixed + 0x00000000000033fe 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .text.libgcc.mul + 0x00000000000033fe 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text.libgcc.div + 0x00000000000033fe 0x28 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + 0x00000000000033fe __divmodhi4 + 0x00000000000033fe _div + .text.libgcc 0x0000000000003426 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text.libgcc.prologue + 0x0000000000003426 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text.libgcc.builtins + 0x0000000000003426 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text.libgcc.fmul + 0x0000000000003426 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text.libgcc.fixed + 0x0000000000003426 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .text.libgcc.mul + 0x0000000000003426 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text.libgcc.div + 0x0000000000003426 0x44 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + 0x0000000000003426 __udivmodsi4 + .text.libgcc 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text.libgcc.prologue + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text.libgcc.builtins + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text.libgcc.fmul + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text.libgcc.fixed + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .text.libgcc.mul + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc.div + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc.prologue + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc.builtins + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc.fmul + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc.fixed + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .text.libgcc.mul + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text.libgcc.div + 0x000000000000346a 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text.libgcc 0x000000000000346a 0xc /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + 0x000000000000346a __tablejump2__ + .text.libgcc.prologue + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text.libgcc.builtins + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text.libgcc.fmul + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text.libgcc.fixed + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .text.libgcc.mul + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc.div + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc.prologue + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc.builtins + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc.fmul + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc.fixed + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .text.libgcc.mul + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc.div + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc.prologue + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc.builtins + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc.fmul + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc.fixed + 0x0000000000003476 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .text.libgcc.mul + 0x0000000000003476 0x1e /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + 0x0000000000003476 __umulhisi3 + .text.libgcc.div + 0x0000000000003494 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text.libgcc 0x0000000000003494 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text.libgcc.prologue + 0x0000000000003494 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text.libgcc.builtins + 0x0000000000003494 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text.libgcc.fmul + 0x0000000000003494 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text.libgcc.fixed + 0x0000000000003494 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .text.libgcc.mul + 0x0000000000003494 0x16 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + 0x0000000000003494 __muluhisi3 + .text.libgcc.div + 0x00000000000034aa 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text.libgcc 0x00000000000034aa 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text.libgcc.prologue + 0x00000000000034aa 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text.libgcc.builtins + 0x00000000000034aa 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text.libgcc.fmul + 0x00000000000034aa 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text.libgcc.fixed + 0x00000000000034aa 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .text.avr-libc + 0x00000000000034aa 0x12 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp_P.o) + 0x00000000000034aa strcmp_P + .text.avr-libc + 0x00000000000034bc 0x1c /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp_P.o) + 0x00000000000034bc strncmp_P + .text.avr-libc + 0x00000000000034d8 0x12 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memcpy.o) + 0x00000000000034d8 memcpy + .text.avr-libc + 0x00000000000034ea 0xe /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memset.o) + 0x00000000000034ea memset + .text.avr-libc + 0x00000000000034f8 0x16 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strchr.o) + 0x00000000000034f8 strchr + .text.avr-libc + 0x000000000000350e 0x12 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp.o) + 0x000000000000350e strcmp + .text.avr-libc + 0x0000000000003520 0x1c /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp.o) + 0x0000000000003520 strncmp + .text.avr-libc + 0x000000000000353c 0x1e /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncpy.o) + 0x000000000000353c strncpy + .text.avr-libc + 0x000000000000355a 0x16 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strrchr.o) + 0x000000000000355a strrchr + 0x0000000000003570 . = ALIGN (0x2) + *(.fini9) + .fini9 0x0000000000003570 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + 0x0000000000003570 exit + 0x0000000000003570 _exit + *(.fini9) + *(.fini8) + *(.fini8) + *(.fini7) + *(.fini7) + *(.fini6) + *(.fini6) + *(.fini5) + *(.fini5) + *(.fini4) + *(.fini4) + *(.fini3) + *(.fini3) + *(.fini2) + *(.fini2) + *(.fini1) + *(.fini1) + *(.fini0) + .fini0 0x0000000000003570 0x4 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + *(.fini0) + 0x0000000000003574 _etext = . + +.data 0x0000000000800100 0x10 load address 0x0000000000003574 + 0x0000000000800100 PROVIDE (__data_start, .) + *(.data) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + .data 0x0000000000800100 0x0 partition.o + .data 0x0000000000800100 0x0 sd_raw.o + .data 0x0000000000800100 0x0 uart.o + .data 0x0000000000800100 0x0 byteordering.o + .data 0x0000000000800100 0x0 fat.o + .data 0x0000000000800100 0x0 main.o + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp_P.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp_P.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memcpy.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memset.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strchr.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncpy.o) + .data 0x0000000000800100 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strrchr.o) + *(.data*) + *(.rodata) + .rodata 0x0000000000800100 0xd fat.o + *(.rodata*) + .rodata.str1.1 + 0x000000000080010d 0x2 main.o + *(.gnu.linkonce.d*) + 0x0000000000800110 . = ALIGN (0x2) + *fill* 0x000000000080010f 0x1 + 0x0000000000800110 _edata = . + 0x0000000000800110 PROVIDE (__data_end, .) + +.bss 0x0000000000800110 0x2c8 + 0x0000000000800110 PROVIDE (__bss_start, .) + *(.bss) + .bss 0x0000000000800110 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + .bss 0x0000000000800110 0x11 partition.o + .bss 0x0000000000800121 0x206 sd_raw.o + .bss 0x0000000000800327 0x0 uart.o + .bss 0x0000000000800327 0x0 byteordering.o + .bss 0x0000000000800327 0xb1 fat.o + .bss 0x00000000008003d8 0x0 main.o + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_mulsi3.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodhi4.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_divmodhi4.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_udivmodsi4.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_exit.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_tablejump2.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_copy_data.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_clear_bss.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_umulhisi3.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/avr5/libgcc.a(_muluhisi3.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp_P.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp_P.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memcpy.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(memset.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strchr.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strcmp.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncmp.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strncpy.o) + .bss 0x00000000008003d8 0x0 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/libc.a(strrchr.o) + *(.bss*) + *(COMMON) + 0x00000000008003d8 PROVIDE (__bss_end, .) + 0x0000000000003574 __data_load_start = LOADADDR (.data) + 0x0000000000003584 __data_load_end = (__data_load_start + SIZEOF (.data)) + +.noinit 0x00000000008003d8 0x0 + [!provide] PROVIDE (__noinit_start, .) + *(.noinit*) + [!provide] PROVIDE (__noinit_end, .) + 0x00000000008003d8 _end = . + [!provide] PROVIDE (__heap_start, .) + +.eeprom 0x0000000000810000 0x0 + *(.eeprom*) + 0x0000000000810000 __eeprom_end = . + +.fuse + *(.fuse) + *(.lfuse) + *(.hfuse) + *(.efuse) + +.lock + *(.lock*) + +.signature + *(.signature*) + +.user_signatures + *(.user_signatures*) + +.stab 0x0000000000000000 0x67bc + *(.stab) + .stab 0x0000000000000000 0x6e4 partition.o + .stab 0x00000000000006e4 0x1350 sd_raw.o + 0x1500 (size before relaxing) + .stab 0x0000000000001a34 0xa20 uart.o + 0xbf4 (size before relaxing) + .stab 0x0000000000002454 0x414 byteordering.o + 0x594 (size before relaxing) + .stab 0x0000000000002868 0x2fdc fat.o + 0x31f8 (size before relaxing) + .stab 0x0000000000005844 0xf78 main.o + 0x1200 (size before relaxing) + +.stabstr 0x0000000000000000 0x2a7b + *(.stabstr) + .stabstr 0x0000000000000000 0x2a7b partition.o + +.stab.excl + *(.stab.excl) + +.stab.exclstr + *(.stab.exclstr) + +.stab.index + *(.stab.index) + +.stab.indexstr + *(.stab.indexstr) + +.comment 0x0000000000000000 0x11 + *(.comment) + .comment 0x0000000000000000 0x11 partition.o + 0x12 (size before relaxing) + .comment 0x0000000000000011 0x12 sd_raw.o + .comment 0x0000000000000011 0x12 uart.o + .comment 0x0000000000000011 0x12 byteordering.o + .comment 0x0000000000000011 0x12 fat.o + .comment 0x0000000000000011 0x12 main.o + +.note.gnu.avr.deviceinfo + 0x0000000000000000 0x3c + .note.gnu.avr.deviceinfo + 0x0000000000000000 0x3c /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + +.note.gnu.build-id + *(.note.gnu.build-id) + +.debug + *(.debug) + +.line + *(.line) + +.debug_srcinfo + *(.debug_srcinfo) + +.debug_sfnames + *(.debug_sfnames) + +.debug_aranges + *(.debug_aranges) + +.debug_pubnames + *(.debug_pubnames) + +.debug_info 0x0000000000000000 0x5f4 + *(.debug_info .gnu.linkonce.wi.*) + .debug_info 0x0000000000000000 0x5f4 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + +.debug_abbrev 0x0000000000000000 0x5a2 + *(.debug_abbrev) + .debug_abbrev 0x0000000000000000 0x5a2 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + +.debug_line 0x0000000000000000 0x1a + *(.debug_line .debug_line.* .debug_line_end) + .debug_line 0x0000000000000000 0x1a /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + +.debug_frame + *(.debug_frame) + +.debug_str 0x0000000000000000 0x208 + *(.debug_str) + .debug_str 0x0000000000000000 0x208 /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr5/crtatmega168.o + +.debug_loc + *(.debug_loc) + +.debug_macinfo + *(.debug_macinfo) + +.debug_weaknames + *(.debug_weaknames) + +.debug_funcnames + *(.debug_funcnames) + +.debug_typenames + *(.debug_typenames) + +.debug_varnames + *(.debug_varnames) + +.debug_pubtypes + *(.debug_pubtypes) + +.debug_ranges + *(.debug_ranges) + +.debug_macro + *(.debug_macro) +OUTPUT(sd-reader.out elf32-avr) +LOAD linker stubs diff --git a/final_project/sd_reader/sd-reader.out b/final_project/sd_reader/sd-reader.out new file mode 100755 index 0000000..2825fc2 Binary files /dev/null and b/final_project/sd_reader/sd-reader.out differ diff --git a/final_project/sd_reader/sd-reader_config.h b/final_project/sd_reader/sd-reader_config.h new file mode 100644 index 0000000..16957f8 --- /dev/null +++ b/final_project/sd_reader/sd-reader_config.h @@ -0,0 +1,53 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef SD_READER_CONFIG_H +#define SD_READER_CONFIG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup config Sd-reader configuration + * + * @{ + */ + +/** + * \file + * Common sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1) + * + * \note This file contains only configuration items relevant to + * all sd-reader implementation files. For module specific configuration + * options, please see the files fat_config.h, partition_config.h + * and sd_raw_config.h. + */ + +/** + * Controls allocation of memory. + * + * Set to 1 to use malloc()/free() for allocation of structures + * like file and directory handles, set to 0 to use pre-allocated + * fixed-size handle arrays. + */ +#define USE_DYNAMIC_MEMORY 0 + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/sd_raw.c b/final_project/sd_reader/sd_raw.c new file mode 100644 index 0000000..5e80ed3 --- /dev/null +++ b/final_project/sd_reader/sd_raw.c @@ -0,0 +1,998 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include +#include +#include "sd_raw.h" + +/** + * \addtogroup sd_raw MMC/SD/SDHC card raw access + * + * This module implements read and write access to MMC, SD + * and SDHC cards. It serves as a low-level driver for the + * higher level modules such as partition and file system + * access. + * + * @{ + */ +/** + * \file + * MMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +/** + * \addtogroup sd_raw_config MMC/SD configuration + * Preprocessor defines to configure the MMC/SD support. + */ + +/** + * @} + */ + +/* commands available in SPI mode */ + +/* CMD0: response R1 */ +#define CMD_GO_IDLE_STATE 0x00 +/* CMD1: response R1 */ +#define CMD_SEND_OP_COND 0x01 +/* CMD8: response R7 */ +#define CMD_SEND_IF_COND 0x08 +/* CMD9: response R1 */ +#define CMD_SEND_CSD 0x09 +/* CMD10: response R1 */ +#define CMD_SEND_CID 0x0a +/* CMD12: response R1 */ +#define CMD_STOP_TRANSMISSION 0x0c +/* CMD13: response R2 */ +#define CMD_SEND_STATUS 0x0d +/* CMD16: arg0[31:0]: block length, response R1 */ +#define CMD_SET_BLOCKLEN 0x10 +/* CMD17: arg0[31:0]: data address, response R1 */ +#define CMD_READ_SINGLE_BLOCK 0x11 +/* CMD18: arg0[31:0]: data address, response R1 */ +#define CMD_READ_MULTIPLE_BLOCK 0x12 +/* CMD24: arg0[31:0]: data address, response R1 */ +#define CMD_WRITE_SINGLE_BLOCK 0x18 +/* CMD25: arg0[31:0]: data address, response R1 */ +#define CMD_WRITE_MULTIPLE_BLOCK 0x19 +/* CMD27: response R1 */ +#define CMD_PROGRAM_CSD 0x1b +/* CMD28: arg0[31:0]: data address, response R1b */ +#define CMD_SET_WRITE_PROT 0x1c +/* CMD29: arg0[31:0]: data address, response R1b */ +#define CMD_CLR_WRITE_PROT 0x1d +/* CMD30: arg0[31:0]: write protect data address, response R1 */ +#define CMD_SEND_WRITE_PROT 0x1e +/* CMD32: arg0[31:0]: data address, response R1 */ +#define CMD_TAG_SECTOR_START 0x20 +/* CMD33: arg0[31:0]: data address, response R1 */ +#define CMD_TAG_SECTOR_END 0x21 +/* CMD34: arg0[31:0]: data address, response R1 */ +#define CMD_UNTAG_SECTOR 0x22 +/* CMD35: arg0[31:0]: data address, response R1 */ +#define CMD_TAG_ERASE_GROUP_START 0x23 +/* CMD36: arg0[31:0]: data address, response R1 */ +#define CMD_TAG_ERASE_GROUP_END 0x24 +/* CMD37: arg0[31:0]: data address, response R1 */ +#define CMD_UNTAG_ERASE_GROUP 0x25 +/* CMD38: arg0[31:0]: stuff bits, response R1b */ +#define CMD_ERASE 0x26 +/* ACMD41: arg0[31:0]: OCR contents, response R1 */ +#define CMD_SD_SEND_OP_COND 0x29 +/* CMD42: arg0[31:0]: stuff bits, response R1b */ +#define CMD_LOCK_UNLOCK 0x2a +/* CMD55: arg0[31:0]: stuff bits, response R1 */ +#define CMD_APP 0x37 +/* CMD58: arg0[31:0]: stuff bits, response R3 */ +#define CMD_READ_OCR 0x3a +/* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */ +#define CMD_CRC_ON_OFF 0x3b + +/* command responses */ +/* R1: size 1 byte */ +#define R1_IDLE_STATE 0 +#define R1_ERASE_RESET 1 +#define R1_ILL_COMMAND 2 +#define R1_COM_CRC_ERR 3 +#define R1_ERASE_SEQ_ERR 4 +#define R1_ADDR_ERR 5 +#define R1_PARAM_ERR 6 +/* R1b: equals R1, additional busy bytes */ +/* R2: size 2 bytes */ +#define R2_CARD_LOCKED 0 +#define R2_WP_ERASE_SKIP 1 +#define R2_ERR 2 +#define R2_CARD_ERR 3 +#define R2_CARD_ECC_FAIL 4 +#define R2_WP_VIOLATION 5 +#define R2_INVAL_ERASE 6 +#define R2_OUT_OF_RANGE 7 +#define R2_CSD_OVERWRITE 7 +#define R2_IDLE_STATE (R1_IDLE_STATE + 8) +#define R2_ERASE_RESET (R1_ERASE_RESET + 8) +#define R2_ILL_COMMAND (R1_ILL_COMMAND + 8) +#define R2_COM_CRC_ERR (R1_COM_CRC_ERR + 8) +#define R2_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 8) +#define R2_ADDR_ERR (R1_ADDR_ERR + 8) +#define R2_PARAM_ERR (R1_PARAM_ERR + 8) +/* R3: size 5 bytes */ +#define R3_OCR_MASK (0xffffffffUL) +#define R3_IDLE_STATE (R1_IDLE_STATE + 32) +#define R3_ERASE_RESET (R1_ERASE_RESET + 32) +#define R3_ILL_COMMAND (R1_ILL_COMMAND + 32) +#define R3_COM_CRC_ERR (R1_COM_CRC_ERR + 32) +#define R3_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 32) +#define R3_ADDR_ERR (R1_ADDR_ERR + 32) +#define R3_PARAM_ERR (R1_PARAM_ERR + 32) +/* Data Response: size 1 byte */ +#define DR_STATUS_MASK 0x0e +#define DR_STATUS_ACCEPTED 0x05 +#define DR_STATUS_CRC_ERR 0x0a +#define DR_STATUS_WRITE_ERR 0x0c + +/* status bits for card types */ +#define SD_RAW_SPEC_1 0 +#define SD_RAW_SPEC_2 1 +#define SD_RAW_SPEC_SDHC 2 + +#if !SD_RAW_SAVE_RAM +/* static data buffer for acceleration */ +static uint8_t raw_block[512]; +/* offset where the data within raw_block lies on the card */ +static offset_t raw_block_address; +#if SD_RAW_WRITE_BUFFERING +/* flag to remember if raw_block was written to the card */ +static uint8_t raw_block_written; +#endif +#endif + +/* card type state */ +static uint8_t sd_raw_card_type; + +/* private helper functions */ +static void sd_raw_send_byte(uint8_t b); +static uint8_t sd_raw_rec_byte(); +static uint8_t sd_raw_send_command(uint8_t command, uint32_t arg); + +/** + * \ingroup sd_raw + * Initializes memory card communication. + * + * \returns 0 on failure, 1 on success. + */ +uint8_t sd_raw_init() +{ + /* enable inputs for reading card status */ + configure_pin_available(); + configure_pin_locked(); + + /* enable outputs for MOSI, SCK, SS, input for MISO */ + configure_pin_mosi(); + configure_pin_sck(); + configure_pin_ss(); + configure_pin_miso(); + + unselect_card(); + + /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */ + SPCR = (0 << SPIE) | /* SPI Interrupt Enable */ + (1 << SPE) | /* SPI Enable */ + (0 << DORD) | /* Data Order: MSB first */ + (1 << MSTR) | /* Master mode */ + (0 << CPOL) | /* Clock Polarity: SCK low when idle */ + (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */ + (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */ + (1 << SPR0); + SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */ + + /* initialization procedure */ + sd_raw_card_type = 0; + + if(!sd_raw_available()) + return 0; + + /* card needs 74 cycles minimum to start up */ + for(uint8_t i = 0; i < 10; ++i) + { + /* wait 8 clock cycles */ + sd_raw_rec_byte(); + } + + /* address card */ + select_card(); + + /* reset card */ + uint8_t response; + for(uint16_t i = 0; ; ++i) + { + response = sd_raw_send_command(CMD_GO_IDLE_STATE, 0); + if(response == (1 << R1_IDLE_STATE)) + break; + + if(i == 0x1ff) + { + unselect_card(); + return 0; + } + } + +#if SD_RAW_SDHC + /* check for version of SD card specification */ + response = sd_raw_send_command(CMD_SEND_IF_COND, 0x100 /* 2.7V - 3.6V */ | 0xaa /* test pattern */); + if((response & (1 << R1_ILL_COMMAND)) == 0) + { + sd_raw_rec_byte(); + sd_raw_rec_byte(); + if((sd_raw_rec_byte() & 0x01) == 0) + return 0; /* card operation voltage range doesn't match */ + if(sd_raw_rec_byte() != 0xaa) + return 0; /* wrong test pattern */ + + /* card conforms to SD 2 card specification */ + sd_raw_card_type |= (1 << SD_RAW_SPEC_2); + } + else +#endif + { + /* determine SD/MMC card type */ + sd_raw_send_command(CMD_APP, 0); + response = sd_raw_send_command(CMD_SD_SEND_OP_COND, 0); + if((response & (1 << R1_ILL_COMMAND)) == 0) + { + /* card conforms to SD 1 card specification */ + sd_raw_card_type |= (1 << SD_RAW_SPEC_1); + } + else + { + /* MMC card */ + } + } + + /* wait for card to get ready */ + for(uint16_t i = 0; ; ++i) + { + if(sd_raw_card_type & ((1 << SD_RAW_SPEC_1) | (1 << SD_RAW_SPEC_2))) + { + uint32_t arg = 0; +#if SD_RAW_SDHC + if(sd_raw_card_type & (1 << SD_RAW_SPEC_2)) + arg = 0x40000000; +#endif + sd_raw_send_command(CMD_APP, 0); + response = sd_raw_send_command(CMD_SD_SEND_OP_COND, arg); + } + else + { + response = sd_raw_send_command(CMD_SEND_OP_COND, 0); + } + + if((response & (1 << R1_IDLE_STATE)) == 0) + break; + + if(i == 0x7fff) + { + unselect_card(); + return 0; + } + } + +#if SD_RAW_SDHC + if(sd_raw_card_type & (1 << SD_RAW_SPEC_2)) + { + if(sd_raw_send_command(CMD_READ_OCR, 0)) + { + unselect_card(); + return 0; + } + + if(sd_raw_rec_byte() & 0x40) + sd_raw_card_type |= (1 << SD_RAW_SPEC_SDHC); + + sd_raw_rec_byte(); + sd_raw_rec_byte(); + sd_raw_rec_byte(); + } +#endif + + /* set block size to 512 bytes */ + if(sd_raw_send_command(CMD_SET_BLOCKLEN, 512)) + { + unselect_card(); + return 0; + } + + /* deaddress card */ + unselect_card(); + + /* switch to highest SPI frequency possible */ + SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */ + SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */ + +#if !SD_RAW_SAVE_RAM + /* the first block is likely to be accessed first, so precache it here */ + raw_block_address = (offset_t) -1; +#if SD_RAW_WRITE_BUFFERING + raw_block_written = 1; +#endif + if(!sd_raw_read(0, raw_block, sizeof(raw_block))) + return 0; +#endif + + return 1; +} + +/** + * \ingroup sd_raw + * Checks wether a memory card is located in the slot. + * + * \returns 1 if the card is available, 0 if it is not. + */ +uint8_t sd_raw_available() +{ + return get_pin_available() == 0x00; +} + +/** + * \ingroup sd_raw + * Checks wether the memory card is locked for write access. + * + * \returns 1 if the card is locked, 0 if it is not. + */ +uint8_t sd_raw_locked() +{ + return get_pin_locked() == 0x00; +} + +/** + * \ingroup sd_raw + * Sends a raw byte to the memory card. + * + * \param[in] b The byte to sent. + * \see sd_raw_rec_byte + */ +void sd_raw_send_byte(uint8_t b) +{ + SPDR = b; + /* wait for byte to be shifted out */ + while(!(SPSR & (1 << SPIF))); + SPSR &= ~(1 << SPIF); +} + +/** + * \ingroup sd_raw + * Receives a raw byte from the memory card. + * + * \returns The byte which should be read. + * \see sd_raw_send_byte + */ +uint8_t sd_raw_rec_byte() +{ + /* send dummy data for receiving some */ + SPDR = 0xff; + while(!(SPSR & (1 << SPIF))); + SPSR &= ~(1 << SPIF); + + return SPDR; +} + +/** + * \ingroup sd_raw + * Send a command to the memory card which responses with a R1 response (and possibly others). + * + * \param[in] command The command to send. + * \param[in] arg The argument for command. + * \returns The command answer. + */ +uint8_t sd_raw_send_command(uint8_t command, uint32_t arg) +{ + uint8_t response; + + /* wait some clock cycles */ + sd_raw_rec_byte(); + + /* send command via SPI */ + sd_raw_send_byte(0x40 | command); + sd_raw_send_byte((arg >> 24) & 0xff); + sd_raw_send_byte((arg >> 16) & 0xff); + sd_raw_send_byte((arg >> 8) & 0xff); + sd_raw_send_byte((arg >> 0) & 0xff); + switch(command) + { + case CMD_GO_IDLE_STATE: + sd_raw_send_byte(0x95); + break; + case CMD_SEND_IF_COND: + sd_raw_send_byte(0x87); + break; + default: + sd_raw_send_byte(0xff); + break; + } + + /* receive response */ + for(uint8_t i = 0; i < 10; ++i) + { + response = sd_raw_rec_byte(); + if(response != 0xff) + break; + } + + return response; +} + +/** + * \ingroup sd_raw + * Reads raw data from the card. + * + * \param[in] offset The offset from which to read. + * \param[out] buffer The buffer into which to write the data. + * \param[in] length The number of bytes to read. + * \returns 0 on failure, 1 on success. + * \see sd_raw_read_interval, sd_raw_write, sd_raw_write_interval + */ +uint8_t sd_raw_read(offset_t offset, uint8_t* buffer, uintptr_t length) +{ + offset_t block_address; + uint16_t block_offset; + uint16_t read_length; + while(length > 0) + { + /* determine byte count to read at once */ + block_offset = offset & 0x01ff; + block_address = offset - block_offset; + read_length = 512 - block_offset; /* read up to block border */ + if(read_length > length) + read_length = length; + +#if !SD_RAW_SAVE_RAM + /* check if the requested data is cached */ + if(block_address != raw_block_address) +#endif + { +#if SD_RAW_WRITE_BUFFERING + if(!sd_raw_sync()) + return 0; +#endif + + /* address card */ + select_card(); + + /* send single block request */ +#if SD_RAW_SDHC + if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address))) +#else + if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, block_address)) +#endif + { + unselect_card(); + return 0; + } + + /* wait for data block (start byte 0xfe) */ + while(sd_raw_rec_byte() != 0xfe); + +#if SD_RAW_SAVE_RAM + /* read byte block */ + uint16_t read_to = block_offset + read_length; + for(uint16_t i = 0; i < 512; ++i) + { + uint8_t b = sd_raw_rec_byte(); + if(i >= block_offset && i < read_to) + *buffer++ = b; + } +#else + /* read byte block */ + uint8_t* cache = raw_block; + for(uint16_t i = 0; i < 512; ++i) + *cache++ = sd_raw_rec_byte(); + raw_block_address = block_address; + + memcpy(buffer, raw_block + block_offset, read_length); + buffer += read_length; +#endif + + /* read crc16 */ + sd_raw_rec_byte(); + sd_raw_rec_byte(); + + /* deaddress card */ + unselect_card(); + + /* let card some time to finish */ + sd_raw_rec_byte(); + } +#if !SD_RAW_SAVE_RAM + else + { + /* use cached data */ + memcpy(buffer, raw_block + block_offset, read_length); + buffer += read_length; + } +#endif + + length -= read_length; + offset += read_length; + } + + return 1; +} + +/** + * \ingroup sd_raw + * Continuously reads units of \c interval bytes and calls a callback function. + * + * This function starts reading at the specified offset. Every \c interval bytes, + * it calls the callback function with the associated data buffer. + * + * By returning zero, the callback may stop reading. + * + * \note Within the callback function, you can not start another read or + * write operation. + * \note This function only works if the following conditions are met: + * - (offset - (offset % 512)) % interval == 0 + * - length % interval == 0 + * + * \param[in] offset Offset from which to start reading. + * \param[in] buffer Pointer to a buffer which is at least interval bytes in size. + * \param[in] interval Number of bytes to read before calling the callback function. + * \param[in] length Number of bytes to read altogether. + * \param[in] callback The function to call every interval bytes. + * \param[in] p An opaque pointer directly passed to the callback function. + * \returns 0 on failure, 1 on success + * \see sd_raw_write_interval, sd_raw_read, sd_raw_write + */ +uint8_t sd_raw_read_interval(offset_t offset, uint8_t* buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void* p) +{ + if(!buffer || interval == 0 || length < interval || !callback) + return 0; + +#if !SD_RAW_SAVE_RAM + while(length >= interval) + { + /* as reading is now buffered, we directly + * hand over the request to sd_raw_read() + */ + if(!sd_raw_read(offset, buffer, interval)) + return 0; + if(!callback(buffer, offset, p)) + break; + offset += interval; + length -= interval; + } + + return 1; +#else + /* address card */ + select_card(); + + uint16_t block_offset; + uint16_t read_length; + uint8_t* buffer_cur; + uint8_t finished = 0; + do + { + /* determine byte count to read at once */ + block_offset = offset & 0x01ff; + read_length = 512 - block_offset; + + /* send single block request */ +#if SD_RAW_SDHC + if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? offset / 512 : offset - block_offset))) +#else + if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, offset - block_offset)) +#endif + { + unselect_card(); + return 0; + } + + /* wait for data block (start byte 0xfe) */ + while(sd_raw_rec_byte() != 0xfe); + + /* read up to the data of interest */ + for(uint16_t i = 0; i < block_offset; ++i) + sd_raw_rec_byte(); + + /* read interval bytes of data and execute the callback */ + do + { + if(read_length < interval || length < interval) + break; + + buffer_cur = buffer; + for(uint16_t i = 0; i < interval; ++i) + *buffer_cur++ = sd_raw_rec_byte(); + + if(!callback(buffer, offset + (512 - read_length), p)) + { + finished = 1; + break; + } + + read_length -= interval; + length -= interval; + + } while(read_length > 0 && length > 0); + + /* read rest of data block */ + while(read_length-- > 0) + sd_raw_rec_byte(); + + /* read crc16 */ + sd_raw_rec_byte(); + sd_raw_rec_byte(); + + if(length < interval) + break; + + offset = offset - block_offset + 512; + + } while(!finished); + + /* deaddress card */ + unselect_card(); + + /* let card some time to finish */ + sd_raw_rec_byte(); + + return 1; +#endif +} + +#if DOXYGEN || SD_RAW_WRITE_SUPPORT +/** + * \ingroup sd_raw + * Writes raw data to the card. + * + * \note If write buffering is enabled, you might have to + * call sd_raw_sync() before disconnecting the card + * to ensure all remaining data has been written. + * + * \param[in] offset The offset where to start writing. + * \param[in] buffer The buffer containing the data to be written. + * \param[in] length The number of bytes to write. + * \returns 0 on failure, 1 on success. + * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval + */ +uint8_t sd_raw_write(offset_t offset, const uint8_t* buffer, uintptr_t length) +{ + if(sd_raw_locked()) + return 0; + + offset_t block_address; + uint16_t block_offset; + uint16_t write_length; + while(length > 0) + { + /* determine byte count to write at once */ + block_offset = offset & 0x01ff; + block_address = offset - block_offset; + write_length = 512 - block_offset; /* write up to block border */ + if(write_length > length) + write_length = length; + + /* Merge the data to write with the content of the block. + * Use the cached block if available. + */ + if(block_address != raw_block_address) + { +#if SD_RAW_WRITE_BUFFERING + if(!sd_raw_sync()) + return 0; +#endif + + if(block_offset || write_length < 512) + { + if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) + return 0; + } + raw_block_address = block_address; + } + + if(buffer != raw_block) + { + memcpy(raw_block + block_offset, buffer, write_length); + +#if SD_RAW_WRITE_BUFFERING + raw_block_written = 0; + + if(length == write_length) + return 1; +#endif + } + + /* address card */ + select_card(); + + /* send single block request */ +#if SD_RAW_SDHC + if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address))) +#else + if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, block_address)) +#endif + { + unselect_card(); + return 0; + } + + /* send start byte */ + sd_raw_send_byte(0xfe); + + /* write byte block */ + uint8_t* cache = raw_block; + for(uint16_t i = 0; i < 512; ++i) + sd_raw_send_byte(*cache++); + + /* write dummy crc16 */ + sd_raw_send_byte(0xff); + sd_raw_send_byte(0xff); + + /* wait while card is busy */ + while(sd_raw_rec_byte() != 0xff); + sd_raw_rec_byte(); + + /* deaddress card */ + unselect_card(); + + buffer += write_length; + offset += write_length; + length -= write_length; + +#if SD_RAW_WRITE_BUFFERING + raw_block_written = 1; +#endif + } + + return 1; +} +#endif + +#if DOXYGEN || SD_RAW_WRITE_SUPPORT +/** + * \ingroup sd_raw + * Writes a continuous data stream obtained from a callback function. + * + * This function starts writing at the specified offset. To obtain the + * next bytes to write, it calls the callback function. The callback fills the + * provided data buffer and returns the number of bytes it has put into the buffer. + * + * By returning zero, the callback may stop writing. + * + * \param[in] offset Offset where to start writing. + * \param[in] buffer Pointer to a buffer which is used for the callback function. + * \param[in] length Number of bytes to write in total. May be zero for endless writes. + * \param[in] callback The function used to obtain the bytes to write. + * \param[in] p An opaque pointer directly passed to the callback function. + * \returns 0 on failure, 1 on success + * \see sd_raw_read_interval, sd_raw_write, sd_raw_read + */ +uint8_t sd_raw_write_interval(offset_t offset, uint8_t* buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void* p) +{ +#if SD_RAW_SAVE_RAM + #error "SD_RAW_WRITE_SUPPORT is not supported together with SD_RAW_SAVE_RAM" +#endif + + if(!buffer || !callback) + return 0; + + uint8_t endless = (length == 0); + while(endless || length > 0) + { + uint16_t bytes_to_write = callback(buffer, offset, p); + if(!bytes_to_write) + break; + if(!endless && bytes_to_write > length) + return 0; + + /* as writing is always buffered, we directly + * hand over the request to sd_raw_write() + */ + if(!sd_raw_write(offset, buffer, bytes_to_write)) + return 0; + + offset += bytes_to_write; + length -= bytes_to_write; + } + + return 1; +} +#endif + +#if DOXYGEN || SD_RAW_WRITE_SUPPORT +/** + * \ingroup sd_raw + * Writes the write buffer's content to the card. + * + * \note When write buffering is enabled, you should + * call this function before disconnecting the + * card to ensure all remaining data has been + * written. + * + * \returns 0 on failure, 1 on success. + * \see sd_raw_write + */ +uint8_t sd_raw_sync() +{ +#if SD_RAW_WRITE_BUFFERING + if(raw_block_written) + return 1; + if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) + return 0; + raw_block_written = 1; +#endif + return 1; +} +#endif + +/** + * \ingroup sd_raw + * Reads informational data from the card. + * + * This function reads and returns the card's registers + * containing manufacturing and status information. + * + * \note: The information retrieved by this function is + * not required in any way to operate on the card, + * but it might be nice to display some of the data + * to the user. + * + * \param[in] info A pointer to the structure into which to save the information. + * \returns 0 on failure, 1 on success. + */ +uint8_t sd_raw_get_info(struct sd_raw_info* info) +{ + if(!info || !sd_raw_available()) + return 0; + + memset(info, 0, sizeof(*info)); + + select_card(); + + /* read cid register */ + if(sd_raw_send_command(CMD_SEND_CID, 0)) + { + unselect_card(); + return 0; + } + while(sd_raw_rec_byte() != 0xfe); + for(uint8_t i = 0; i < 18; ++i) + { + uint8_t b = sd_raw_rec_byte(); + + switch(i) + { + case 0: + info->manufacturer = b; + break; + case 1: + case 2: + info->oem[i - 1] = b; + break; + case 3: + case 4: + case 5: + case 6: + case 7: + info->product[i - 3] = b; + break; + case 8: + info->revision = b; + break; + case 9: + case 10: + case 11: + case 12: + info->serial |= (uint32_t) b << ((12 - i) * 8); + break; + case 13: + info->manufacturing_year = b << 4; + break; + case 14: + info->manufacturing_year |= b >> 4; + info->manufacturing_month = b & 0x0f; + break; + } + } + + /* read csd register */ + uint8_t csd_read_bl_len = 0; + uint8_t csd_c_size_mult = 0; +#if SD_RAW_SDHC + uint16_t csd_c_size = 0; +#else + uint32_t csd_c_size = 0; +#endif + uint8_t csd_structure = 0; + if(sd_raw_send_command(CMD_SEND_CSD, 0)) + { + unselect_card(); + return 0; + } + while(sd_raw_rec_byte() != 0xfe); + for(uint8_t i = 0; i < 18; ++i) + { + uint8_t b = sd_raw_rec_byte(); + + if(i == 0) + { + csd_structure = b >> 6; + } + else if(i == 14) + { + if(b & 0x40) + info->flag_copy = 1; + if(b & 0x20) + info->flag_write_protect = 1; + if(b & 0x10) + info->flag_write_protect_temp = 1; + info->format = (b & 0x0c) >> 2; + } + else + { +#if SD_RAW_SDHC + if(csd_structure == 0x01) + { + switch(i) + { + case 7: + b &= 0x3f; + case 8: + case 9: + csd_c_size <<= 8; + csd_c_size |= b; + break; + } + if(i == 9) + { + ++csd_c_size; + info->capacity = (offset_t) csd_c_size * 512 * 1024; + } + } + else if(csd_structure == 0x00) +#endif + { + switch(i) + { + case 5: + csd_read_bl_len = b & 0x0f; + break; + case 6: + csd_c_size = b & 0x03; + csd_c_size <<= 8; + break; + case 7: + csd_c_size |= b; + csd_c_size <<= 2; + break; + case 8: + csd_c_size |= b >> 6; + ++csd_c_size; + break; + case 9: + csd_c_size_mult = b & 0x03; + csd_c_size_mult <<= 1; + break; + case 10: + csd_c_size_mult |= b >> 7; + + info->capacity = (uint32_t) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2); + break; + } + } + } + } + + unselect_card(); + + return 1; +} + diff --git a/final_project/sd_reader/sd_raw.h b/final_project/sd_reader/sd_raw.h new file mode 100644 index 0000000..6aa9750 --- /dev/null +++ b/final_project/sd_reader/sd_raw.h @@ -0,0 +1,148 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef SD_RAW_H +#define SD_RAW_H + +#include +#include "sd_raw_config.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup sd_raw + * + * @{ + */ +/** + * \file + * MMC/SD/SDHC raw access header (license: GPLv2 or LGPLv2.1) + * + * \author Roland Riegel + */ + +/** + * The card's layout is harddisk-like, which means it contains + * a master boot record with a partition table. + */ +#define SD_RAW_FORMAT_HARDDISK 0 +/** + * The card contains a single filesystem and no partition table. + */ +#define SD_RAW_FORMAT_SUPERFLOPPY 1 +/** + * The card's layout follows the Universal File Format. + */ +#define SD_RAW_FORMAT_UNIVERSAL 2 +/** + * The card's layout is unknown. + */ +#define SD_RAW_FORMAT_UNKNOWN 3 + +/** + * This struct is used by sd_raw_get_info() to return + * manufacturing and status information of the card. + */ +struct sd_raw_info +{ + /** + * A manufacturer code globally assigned by the SD card organization. + */ + uint8_t manufacturer; + /** + * A string describing the card's OEM or content, globally assigned by the SD card organization. + */ + uint8_t oem[3]; + /** + * A product name. + */ + uint8_t product[6]; + /** + * The card's revision, coded in packed BCD. + * + * For example, the revision value \c 0x32 means "3.2". + */ + uint8_t revision; + /** + * A serial number assigned by the manufacturer. + */ + uint32_t serial; + /** + * The year of manufacturing. + * + * A value of zero means year 2000. + */ + uint8_t manufacturing_year; + /** + * The month of manufacturing. + */ + uint8_t manufacturing_month; + /** + * The card's total capacity in bytes. + */ + offset_t capacity; + /** + * Defines wether the card's content is original or copied. + * + * A value of \c 0 means original, \c 1 means copied. + */ + uint8_t flag_copy; + /** + * Defines wether the card's content is write-protected. + * + * \note This is an internal flag and does not represent the + * state of the card's mechanical write-protect switch. + */ + uint8_t flag_write_protect; + /** + * Defines wether the card's content is temporarily write-protected. + * + * \note This is an internal flag and does not represent the + * state of the card's mechanical write-protect switch. + */ + uint8_t flag_write_protect_temp; + /** + * The card's data layout. + * + * See the \c SD_RAW_FORMAT_* constants for details. + * + * \note This value is not guaranteed to match reality. + */ + uint8_t format; +}; + +typedef uint8_t (*sd_raw_read_interval_handler_t)(uint8_t* buffer, offset_t offset, void* p); +typedef uintptr_t (*sd_raw_write_interval_handler_t)(uint8_t* buffer, offset_t offset, void* p); + +uint8_t sd_raw_init(); +uint8_t sd_raw_available(); +uint8_t sd_raw_locked(); + +uint8_t sd_raw_read(offset_t offset, uint8_t* buffer, uintptr_t length); +uint8_t sd_raw_read_interval(offset_t offset, uint8_t* buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void* p); +uint8_t sd_raw_write(offset_t offset, const uint8_t* buffer, uintptr_t length); +uint8_t sd_raw_write_interval(offset_t offset, uint8_t* buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void* p); +uint8_t sd_raw_sync(); + +uint8_t sd_raw_get_info(struct sd_raw_info* info); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/sd_raw.o b/final_project/sd_reader/sd_raw.o new file mode 100644 index 0000000..77999a6 Binary files /dev/null and b/final_project/sd_reader/sd_raw.o differ diff --git a/final_project/sd_reader/sd_raw_config.h b/final_project/sd_reader/sd_raw_config.h new file mode 100644 index 0000000..ca88eaa --- /dev/null +++ b/final_project/sd_reader/sd_raw_config.h @@ -0,0 +1,139 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef SD_RAW_CONFIG_H +#define SD_RAW_CONFIG_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \addtogroup sd_raw + * + * @{ + */ +/** + * \file + * MMC/SD support configuration (license: GPLv2 or LGPLv2.1) + */ + +/** + * \ingroup sd_raw_config + * Controls MMC/SD write support. + * + * Set to 1 to enable MMC/SD write support, set to 0 to disable it. + */ +#define SD_RAW_WRITE_SUPPORT 1 + +/** + * \ingroup sd_raw_config + * Controls MMC/SD write buffering. + * + * Set to 1 to buffer write accesses, set to 0 to disable it. + * + * \note This option has no effect when SD_RAW_WRITE_SUPPORT is 0. + */ +#define SD_RAW_WRITE_BUFFERING 1 + +/** + * \ingroup sd_raw_config + * Controls MMC/SD access buffering. + * + * Set to 1 to save static RAM, but be aware that you will + * lose performance. + * + * \note When SD_RAW_WRITE_SUPPORT is 1, SD_RAW_SAVE_RAM will + * be reset to 0. + */ +#define SD_RAW_SAVE_RAM 1 + +/** + * \ingroup sd_raw_config + * Controls support for SDHC cards. + * + * Set to 1 to support so-called SDHC memory cards, i.e. SD + * cards with more than 2 gigabytes of memory. + */ +#define SD_RAW_SDHC 0 + +/** + * @} + */ + +/* defines for customisation of sd/mmc port access */ +#if defined(__AVR_ATmega8__) || \ + defined(__AVR_ATmega48__) || \ + defined(__AVR_ATmega48P__) || \ + defined(__AVR_ATmega88__) || \ + defined(__AVR_ATmega88P__) || \ + defined(__AVR_ATmega168__) || \ + defined(__AVR_ATmega168P__) || \ + defined(__AVR_ATmega328P__) + #define configure_pin_mosi() DDRB |= (1 << DDB3) + #define configure_pin_sck() DDRB |= (1 << DDB5) + #define configure_pin_ss() DDRB |= (1 << DDB2) + #define configure_pin_miso() DDRB &= ~(1 << DDB4) + + #define select_card() PORTB &= ~(1 << PORTB2) + #define unselect_card() PORTB |= (1 << PORTB2) +#elif defined(__AVR_ATmega16__) || \ + defined(__AVR_ATmega32__) + #define configure_pin_mosi() DDRB |= (1 << DDB5) + #define configure_pin_sck() DDRB |= (1 << DDB7) + #define configure_pin_ss() DDRB |= (1 << DDB4) + #define configure_pin_miso() DDRB &= ~(1 << DDB6) + + #define select_card() PORTB &= ~(1 << PORTB4) + #define unselect_card() PORTB |= (1 << PORTB4) +#elif defined(__AVR_ATmega64__) || \ + defined(__AVR_ATmega128__) || \ + defined(__AVR_ATmega169__) + #define configure_pin_mosi() DDRB |= (1 << DDB2) + #define configure_pin_sck() DDRB |= (1 << DDB1) + #define configure_pin_ss() DDRB |= (1 << DDB0) + #define configure_pin_miso() DDRB &= ~(1 << DDB3) + + #define select_card() PORTB &= ~(1 << PORTB0) + #define unselect_card() PORTB |= (1 << PORTB0) +#else + #error "no sd/mmc pin mapping available!" +#endif + +#define configure_pin_available() DDRC &= ~(1 << DDC4) +#define configure_pin_locked() DDRC &= ~(1 << DDC5) + +#define get_pin_available() (PINC & (1 << PINC4)) +#define get_pin_locked() (PINC & (1 << PINC5)) + +#if SD_RAW_SDHC + typedef uint64_t offset_t; +#else + typedef uint32_t offset_t; +#endif + +/* configuration checks */ +#if SD_RAW_WRITE_SUPPORT +#undef SD_RAW_SAVE_RAM +#define SD_RAW_SAVE_RAM 0 +#else +#undef SD_RAW_WRITE_BUFFERING +#define SD_RAW_WRITE_BUFFERING 0 +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/uart.c b/final_project/sd_reader/uart.c new file mode 100644 index 0000000..df5e1fd --- /dev/null +++ b/final_project/sd_reader/uart.c @@ -0,0 +1,198 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "uart.h" + +/* some mcus have multiple uarts */ +#ifdef UDR0 +#define UBRRH UBRR0H +#define UBRRL UBRR0L +#define UDR UDR0 + +#define UCSRA UCSR0A +#define UDRE UDRE0 +#define RXC RXC0 + +#define UCSRB UCSR0B +#define RXEN RXEN0 +#define TXEN TXEN0 +#define RXCIE RXCIE0 + +#define UCSRC UCSR0C +#define URSEL +#define UCSZ0 UCSZ00 +#define UCSZ1 UCSZ01 +#define UCSRC_SELECT 0 +#else +#define UCSRC_SELECT (1 << URSEL) +#endif + +#ifndef USART_RXC_vect +#if defined(UART0_RX_vect) +#define USART_RXC_vect UART0_RX_vect +#elif defined(UART_RX_vect) +#define USART_RXC_vect UART_RX_vect +#elif defined(USART0_RX_vect) +#define USART_RXC_vect USART0_RX_vect +#elif defined(USART_RX_vect) +#define USART_RXC_vect USART_RX_vect +#elif defined(USART0_RXC_vect) +#define USART_RXC_vect USART0_RXC_vect +#elif defined(USART_RXC_vect) +#define USART_RXC_vect USART_RXC_vect +#else +#error "Uart receive complete interrupt not defined!" +#endif +#endif + +#define BAUD 9600UL +#define UBRRVAL (F_CPU/(BAUD*16)-1) +#define USE_SLEEP 1 + +void uart_init() +{ + /* set baud rate */ + UBRRH = UBRRVAL >> 8; + UBRRL = UBRRVAL & 0xff; + /* set frame format: 8 bit, no parity, 1 bit */ + UCSRC = UCSRC_SELECT | (1 << UCSZ1) | (1 << UCSZ0); + /* enable serial receiver and transmitter */ +#if !USE_SLEEP + UCSRB = (1 << RXEN) | (1 << TXEN); +#else + UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE); +#endif +} + +void uart_putc(uint8_t c) +{ + if(c == '\n') + uart_putc('\r'); + + /* wait until transmit buffer is empty */ + while(!(UCSRA & (1 << UDRE))); + + /* send next byte */ + UDR = c; +} + +void uart_putc_hex(uint8_t b) +{ + /* upper nibble */ + if((b >> 4) < 0x0a) + uart_putc((b >> 4) + '0'); + else + uart_putc((b >> 4) - 0x0a + 'a'); + + /* lower nibble */ + if((b & 0x0f) < 0x0a) + uart_putc((b & 0x0f) + '0'); + else + uart_putc((b & 0x0f) - 0x0a + 'a'); +} + +void uart_putw_hex(uint16_t w) +{ + uart_putc_hex((uint8_t) (w >> 8)); + uart_putc_hex((uint8_t) (w & 0xff)); +} + +void uart_putdw_hex(uint32_t dw) +{ + uart_putw_hex((uint16_t) (dw >> 16)); + uart_putw_hex((uint16_t) (dw & 0xffff)); +} + +void uart_putw_dec(uint16_t w) +{ + uint16_t num = 10000; + uint8_t started = 0; + + while(num > 0) + { + uint8_t b = w / num; + if(b > 0 || started || num == 1) + { + uart_putc('0' + b); + started = 1; + } + w -= b * num; + + num /= 10; + } +} + +void uart_putdw_dec(uint32_t dw) +{ + uint32_t num = 1000000000; + uint8_t started = 0; + + while(num > 0) + { + uint8_t b = dw / num; + if(b > 0 || started || num == 1) + { + uart_putc('0' + b); + started = 1; + } + dw -= b * num; + + num /= 10; + } +} + +void uart_puts(const char* str) +{ + while(*str) + uart_putc(*str++); +} + +void uart_puts_p(PGM_P str) +{ + while(1) + { + uint8_t b = pgm_read_byte_near(str++); + if(!b) + break; + + uart_putc(b); + } +} + +uint8_t uart_getc() +{ + /* wait until receive buffer is full */ +#if USE_SLEEP + uint8_t sreg = SREG; + sei(); + + while(!(UCSRA & (1 << RXC))) + sleep_mode(); + + SREG = sreg; +#else + while(!(UCSRA & (1 << RXC))); +#endif + + uint8_t b = UDR; + if(b == '\r') + b = '\n'; + + return b; +} + +EMPTY_INTERRUPT(USART_RXC_vect) + diff --git a/final_project/sd_reader/uart.h b/final_project/sd_reader/uart.h new file mode 100644 index 0000000..d94d93d --- /dev/null +++ b/final_project/sd_reader/uart.h @@ -0,0 +1,42 @@ + +/* + * Copyright (c) 2006-2012 by Roland Riegel + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef UART_H +#define UART_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +void uart_init(); + +void uart_putc(uint8_t c); + +void uart_putc_hex(uint8_t b); +void uart_putw_hex(uint16_t w); +void uart_putdw_hex(uint32_t dw); + +void uart_putw_dec(uint16_t w); +void uart_putdw_dec(uint32_t dw); + +void uart_puts(const char* str); +void uart_puts_p(PGM_P str); + +uint8_t uart_getc(); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/final_project/sd_reader/uart.o b/final_project/sd_reader/uart.o new file mode 100644 index 0000000..d23568d Binary files /dev/null and b/final_project/sd_reader/uart.o differ