No changes between revisions
/Designs/GPSRL02A/SW/logger/ChangeLog |
---|
0,0 → 1,68 |
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. |
/Designs/GPSRL02A/SW/logger/Doxyfile |
---|
0,0 → 1,1311 |
# Doxyfile 1.5.3-20071008 |
# 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, Finnish, French, German, Greek, Hungarian, |
# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, |
# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, |
# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. |
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 DETAILS_AT_TOP tag is set to YES then Doxygen |
# will output the detailed description near the top, like JavaDoc. |
# If set to NO, the detailed description appears after the member |
# documentation. |
DETAILS_AT_TOP = YES |
# 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 |
# 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 |
# 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 |
#--------------------------------------------------------------------------- |
# 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_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 |
# 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 <command> <input-file>, where <command> is the value of |
# the FILE_VERSION_FILTER tag, and <input-file> 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 = |
#--------------------------------------------------------------------------- |
# 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 |
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 <filter> <input-file>, where <filter> |
# is the value of the INPUT_FILTER tag, and <input-file> 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. If you have enabled CALL_GRAPH or CALLER_GRAPH |
# then you must also enable this option. If you don't then doxygen will produce |
# a warning and turn it on anyway |
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 (the default) |
# 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 (the default) |
# 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 documentstion. |
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 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 compressed HTML help file (.chm) |
# of the generated HTML documentation. |
GENERATE_HTMLHELP = NO |
# 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_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 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 |
# 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 |
# If the GENERATE_TREEVIEW tag 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 (for instance Mozilla 1.0+, |
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are |
# probably better off using the HTML help feature. |
GENERATE_TREEVIEW = 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 |
#--------------------------------------------------------------------------- |
# 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 |
#--------------------------------------------------------------------------- |
# 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 |
# 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, SOURCE_BROWSER and HAVE_DOT tags 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, SOURCE_BROWSER 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 MAX_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 |
# MAX_DOT_GRAPH_NOTES 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, which results in a white background. |
# 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 |
#--------------------------------------------------------------------------- |
# Configuration::additions related to the search engine |
#--------------------------------------------------------------------------- |
# The SEARCHENGINE tag specifies whether or not a search engine should be |
# used. If set to NO the values of all tags below this one will be ignored. |
SEARCHENGINE = NO |
/Designs/GPSRL02A/SW/logger/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 -p $(MCU_AVRDUDE) -P /dev/ttyUSB0 -c stk500v2 -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 |
/Designs/GPSRL02A/SW/logger/doc/pic01.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/GPSRL02A/SW/logger/doc/pic02.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/GPSRL02A/SW/logger/fat16.c |
---|
0,0 → 1,2233 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 "partition.h" |
#include "fat16.h" |
#include "fat16_config.h" |
#include "sd-reader_config.h" |
#include <string.h> |
#if USE_DYNAMIC_MEMORY |
#include <stdlib.h> |
#endif |
/** |
* \addtogroup fat16 FAT16 support |
* |
* This module implements FAT16 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 |
* FAT16 implementation (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* \addtogroup fat16_config FAT16 configuration |
* Preprocessor defines to configure the FAT16 implementation. |
*/ |
/** |
* \addtogroup fat16_fs FAT16 access |
* Basic functions for handling a FAT16 filesystem. |
*/ |
/** |
* \addtogroup fat16_file FAT16 file functions |
* Functions for managing files. |
*/ |
/** |
* \addtogroup fat16_dir FAT16 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 FAT16_DIRENTRY_DELETED 0xe5 |
#define FAT16_DIRENTRY_LFNLAST (1 << 6) |
#define FAT16_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 (FAT16_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 fat16_header_struct |
{ |
uint32_t size; |
uint32_t fat_offset; |
uint32_t fat_size; |
uint16_t sector_size; |
uint16_t cluster_size; |
uint32_t root_dir_offset; |
uint32_t cluster_zero_offset; |
}; |
struct fat16_fs_struct |
{ |
struct partition_struct* partition; |
struct fat16_header_struct header; |
}; |
struct fat16_file_struct |
{ |
struct fat16_fs_struct* fs; |
struct fat16_dir_entry_struct dir_entry; |
uint32_t pos; |
uint16_t pos_cluster; |
}; |
struct fat16_dir_struct |
{ |
struct fat16_fs_struct* fs; |
struct fat16_dir_entry_struct dir_entry; |
uint16_t entry_next; |
}; |
struct fat16_read_callback_arg |
{ |
uint16_t entry_cur; |
uint16_t entry_num; |
uint32_t entry_offset; |
uint8_t byte_count; |
}; |
struct fat16_usage_count_callback_arg |
{ |
uint16_t cluster_count; |
uint8_t buffer_size; |
}; |
#if !USE_DYNAMIC_MEMORY |
static struct fat16_fs_struct fat16_fs_handlers[FAT16_FS_COUNT]; |
static struct fat16_file_struct fat16_file_handlers[FAT16_FILE_COUNT]; |
static struct fat16_dir_struct fat16_dir_handlers[FAT16_DIR_COUNT]; |
#endif |
static uint8_t fat16_read_header(struct fat16_fs_struct* fs); |
static uint8_t fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_read_sub_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, const struct fat16_dir_entry_struct* parent, struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_dir_entry_seek_callback(uint8_t* buffer, uint32_t offset, void* p); |
static uint8_t fat16_dir_entry_read_callback(uint8_t* buffer, uint32_t offset, void* p); |
static uint8_t fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const uint8_t* raw_entry); |
static uint16_t fat16_get_next_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count); |
static uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint8_t fat16_terminate_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint8_t fat16_clear_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint16_t fat16_clear_cluster_callback(uint8_t* buffer, uint32_t offset, void* p); |
static uint32_t fat16_find_offset_for_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_struct* parent, const struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_write_dir_entry(const struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_get_fs_free_callback(uint8_t* buffer, uint32_t offset, void* p); |
static void fat16_set_file_modification_date(struct fat16_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day); |
static void fat16_set_file_modification_time(struct fat16_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec); |
/** |
* \ingroup fat16_fs |
* Opens a FAT16 filesystem. |
* |
* \param[in] partition Discriptor of partition on which the filesystem resides. |
* \returns 0 on error, a FAT16 filesystem descriptor on success. |
* \see fat16_open |
*/ |
struct fat16_fs_struct* fat16_open(struct partition_struct* partition) |
{ |
if(!partition || |
#if FAT16_WRITE_SUPPORT |
!partition->device_write || |
!partition->device_write_interval |
#else |
0 |
#endif |
) |
return 0; |
#if USE_DYNAMIC_MEMORY |
struct fat16_fs_struct* fs = malloc(sizeof(*fs)); |
if(!fs) |
return 0; |
#else |
struct fat16_fs_struct* fs = fat16_fs_handlers; |
uint8_t i; |
for(i = 0; i < FAT16_FS_COUNT; ++i) |
{ |
if(!fs->partition) |
break; |
++fs; |
} |
if(i >= FAT16_FS_COUNT) |
return 0; |
#endif |
memset(fs, 0, sizeof(*fs)); |
fs->partition = partition; |
if(!fat16_read_header(fs)) |
{ |
#if USE_DYNAMIC_MEMORY |
free(fs); |
#else |
fs->partition = 0; |
#endif |
return 0; |
} |
return fs; |
} |
/** |
* \ingroup fat16_fs |
* Closes a FAT16 filesystem. |
* |
* When this function returns, the given filesystem descriptor |
* will be invalid. |
* |
* \param[in] fs The filesystem to close. |
* \see fat16_open |
*/ |
void fat16_close(struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return; |
#if USE_DYNAMIC_MEMORY |
free(fs); |
#else |
fs->partition = 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Reads and parses the header of a FAT16 filesystem. |
* |
* \param[inout] fs The filesystem for which to parse the header. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t fat16_read_header(struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
struct partition_struct* partition = fs->partition; |
if(!partition) |
return 0; |
/* read fat parameters */ |
uint8_t buffer[25]; |
uint32_t partition_offset = partition->offset * 512; |
if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer))) |
return 0; |
uint16_t bytes_per_sector = ((uint16_t) buffer[0x00]) | |
((uint16_t) buffer[0x01] << 8); |
uint8_t sectors_per_cluster = buffer[0x02]; |
uint16_t reserved_sectors = ((uint16_t) buffer[0x03]) | |
((uint16_t) buffer[0x04] << 8); |
uint8_t fat_copies = buffer[0x05]; |
uint16_t max_root_entries = ((uint16_t) buffer[0x06]) | |
((uint16_t) buffer[0x07] << 8); |
uint16_t sector_count_16 = ((uint16_t) buffer[0x08]) | |
((uint16_t) buffer[0x09] << 8); |
uint16_t sectors_per_fat = ((uint16_t) buffer[0x0b]) | |
((uint16_t) buffer[0x0c] << 8); |
uint32_t sector_count = ((uint32_t) buffer[0x15]) | |
((uint32_t) buffer[0x16] << 8) | |
((uint32_t) buffer[0x17] << 16) | |
((uint32_t) buffer[0x18] << 24); |
if(sectors_per_fat == 0) |
/* this is not a FAT16 */ |
return 0; |
if(sector_count == 0) |
{ |
if(sector_count_16 == 0) |
/* illegal volume size */ |
return 0; |
else |
sector_count = sector_count_16; |
} |
/* ensure we really have a FAT16 fs here */ |
uint32_t data_sector_count = sector_count |
- reserved_sectors |
- (uint32_t) sectors_per_fat * fat_copies |
- ((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 || data_cluster_count >= 65525) |
/* this is not a FAT16 */ |
return 0; |
partition->type = PARTITION_TYPE_FAT16; |
/* fill header information */ |
struct fat16_header_struct* header = &fs->header; |
memset(header, 0, sizeof(*header)); |
header->size = sector_count * bytes_per_sector; |
header->fat_offset = /* jump to partition */ |
partition_offset + |
/* jump to fat */ |
(uint32_t) reserved_sectors * bytes_per_sector; |
header->fat_size = (data_cluster_count + 2) * 2; |
header->sector_size = bytes_per_sector; |
header->cluster_size = (uint32_t) bytes_per_sector * sectors_per_cluster; |
header->root_dir_offset = /* jump to fats */ |
header->fat_offset + |
/* jump to root directory entries */ |
(uint32_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 */ |
(uint32_t) max_root_entries * 32; |
return 1; |
} |
/** |
* \ingroup fat16_fs |
* Reads a directory entry of the root directory. |
* |
* \param[in] fs Descriptor of file system to use. |
* \param[in] entry_num The index of the directory entry to read. |
* \param[out] dir_entry Directory entry descriptor which will get filled. |
* \returns 0 on failure, 1 on success |
* \see fat16_read_sub_dir_entry, fat16_read_dir_entry_by_path |
*/ |
uint8_t fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !dir_entry) |
return 0; |
/* we read from the root directory entry */ |
const struct fat16_header_struct* header = &fs->header; |
device_read_interval_t device_read_interval = fs->partition->device_read_interval; |
uint8_t buffer[32]; |
/* seek to the n-th entry */ |
struct fat16_read_callback_arg arg; |
memset(&arg, 0, sizeof(arg)); |
arg.entry_num = entry_num; |
if(!device_read_interval(header->root_dir_offset, |
buffer, |
sizeof(buffer), |
header->cluster_zero_offset - header->root_dir_offset, |
fat16_dir_entry_seek_callback, |
&arg) || |
arg.entry_offset == 0 |
) |
return 0; |
/* read entry */ |
memset(dir_entry, 0, sizeof(*dir_entry)); |
if(!device_read_interval(arg.entry_offset, |
buffer, |
sizeof(buffer), |
arg.byte_count, |
fat16_dir_entry_read_callback, |
dir_entry)) |
return 0; |
return dir_entry->long_name[0] != '\0' ? 1 : 0; |
} |
/** |
* \ingroup fat16_fs |
* Reads a directory entry of a given parent directory. |
* |
* \param[in] fs Descriptor of file system to use. |
* \param[in] entry_num The index of the directory entry to read. |
* \param[in] parent Directory entry descriptor in which to read directory entry. |
* \param[out] dir_entry Directory entry descriptor which will get filled. |
* \returns 0 on failure, 1 on success |
* \see fat16_read_root_dir_entry, fat16_read_dir_entry_by_path |
*/ |
uint8_t fat16_read_sub_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, const struct fat16_dir_entry_struct* parent, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !parent || !dir_entry) |
return 0; |
/* we are in a parent directory and want to search within its directory entry table */ |
if(!(parent->attributes & FAT16_ATTRIB_DIR)) |
return 0; |
/* loop through all clusters of the directory */ |
uint8_t buffer[32]; |
uint32_t cluster_offset; |
uint16_t cluster_size = fs->header.cluster_size; |
uint16_t cluster_num = parent->cluster; |
struct fat16_read_callback_arg arg; |
while(1) |
{ |
/* calculate new cluster offset */ |
cluster_offset = fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * cluster_size; |
/* seek to the n-th entry */ |
memset(&arg, 0, sizeof(arg)); |
arg.entry_num = entry_num; |
if(!fs->partition->device_read_interval(cluster_offset, |
buffer, |
sizeof(buffer), |
cluster_size, |
fat16_dir_entry_seek_callback, |
&arg) |
) |
return 0; |
/* check if we found the entry */ |
if(arg.entry_offset) |
break; |
/* get number of next cluster */ |
if(!(cluster_num = fat16_get_next_cluster(fs, cluster_num))) |
return 0; /* directory entry not found */ |
} |
memset(dir_entry, 0, sizeof(*dir_entry)); |
/* read entry */ |
if(!fs->partition->device_read_interval(arg.entry_offset, |
buffer, |
sizeof(buffer), |
arg.byte_count, |
fat16_dir_entry_read_callback, |
dir_entry)) |
return 0; |
return dir_entry->long_name[0] != '\0' ? 1 : 0; |
} |
/** |
* \ingroup fat16_fs |
* Callback function for seeking through subdirectory entries. |
*/ |
uint8_t fat16_dir_entry_seek_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
struct fat16_read_callback_arg* arg = p; |
/* skip deleted or empty entries */ |
if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0]) |
return 1; |
if(arg->entry_cur == arg->entry_num) |
{ |
arg->entry_offset = offset; |
arg->byte_count = buffer[11] == 0x0f ? |
((buffer[0] & FAT16_DIRENTRY_LFNSEQMASK) + 1) * 32 : |
32; |
return 0; |
} |
/* if we read a 8.3 entry, we reached a new directory entry */ |
if(buffer[11] != 0x0f) |
++arg->entry_cur; |
return 1; |
} |
/** |
* \ingroup fat16_fs |
* Callback function for reading a directory entry. |
*/ |
uint8_t fat16_dir_entry_read_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
struct fat16_dir_entry_struct* dir_entry = p; |
/* there should not be any deleted or empty entries */ |
if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0]) |
return 0; |
if(!dir_entry->entry_offset) |
dir_entry->entry_offset = offset; |
switch(fat16_interpret_dir_entry(dir_entry, buffer)) |
{ |
case 0: /* failure */ |
return 0; |
case 1: /* buffer successfully parsed, continue */ |
return 1; |
case 2: /* directory entry complete, finish */ |
return 0; |
} |
return 0; |
} |
/** |
* \ingroup fat16_fs |
* Interprets a raw directory entry and puts the contained |
* information into the directory entry. |
* |
* 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,out] dir_entry The directory entry to fill. |
* \param[in] raw_entry A pointer to 32 bytes of raw data. |
* \returns 0 on failure, 1 on success and 2 if the |
* directory entry is complete. |
*/ |
uint8_t fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const uint8_t* raw_entry) |
{ |
if(!dir_entry || !raw_entry || !raw_entry[0]) |
return 0; |
char* long_name = dir_entry->long_name; |
if(raw_entry[11] == 0x0f) |
{ |
uint16_t char_offset = ((raw_entry[0] & 0x3f) - 1) * 13; |
if(char_offset + 12 < sizeof(dir_entry->long_name)) |
{ |
/* Lfn supports unicode, but we do not, for now. |
* So we assume pure ascii and read only every |
* second byte. |
*/ |
long_name[char_offset + 0] = raw_entry[1]; |
long_name[char_offset + 1] = raw_entry[3]; |
long_name[char_offset + 2] = raw_entry[5]; |
long_name[char_offset + 3] = raw_entry[7]; |
long_name[char_offset + 4] = raw_entry[9]; |
long_name[char_offset + 5] = raw_entry[14]; |
long_name[char_offset + 6] = raw_entry[16]; |
long_name[char_offset + 7] = raw_entry[18]; |
long_name[char_offset + 8] = raw_entry[20]; |
long_name[char_offset + 9] = raw_entry[22]; |
long_name[char_offset + 10] = raw_entry[24]; |
long_name[char_offset + 11] = raw_entry[28]; |
long_name[char_offset + 12] = raw_entry[30]; |
} |
return 1; |
} |
else |
{ |
/* if we do not have a long name, take the short one */ |
if(long_name[0] == '\0') |
{ |
uint8_t i; |
for(i = 0; i < 8; ++i) |
{ |
if(raw_entry[i] == ' ') |
break; |
long_name[i] = raw_entry[i]; |
} |
if(long_name[0] == 0x05) |
long_name[0] = (char) FAT16_DIRENTRY_DELETED; |
if(raw_entry[8] != ' ') |
{ |
long_name[i++] = '.'; |
uint8_t j = 8; |
for(; j < 11; ++j) |
{ |
if(raw_entry[j] != ' ') |
{ |
long_name[i++] = raw_entry[j]; |
} |
else |
{ |
break; |
} |
} |
} |
long_name[i] = '\0'; |
} |
/* extract properties of file and store them within the structure */ |
dir_entry->attributes = raw_entry[11]; |
dir_entry->cluster = ((uint16_t) raw_entry[26]) | |
((uint16_t) raw_entry[27] << 8); |
dir_entry->file_size = ((uint32_t) raw_entry[28]) | |
((uint32_t) raw_entry[29] << 8) | |
((uint32_t) raw_entry[30] << 16) | |
((uint32_t) raw_entry[31] << 24); |
#if FAT16_DATETIME_SUPPORT |
dir_entry->modification_time = ((uint16_t) raw_entry[22]) | |
((uint16_t) raw_entry[23] << 8); |
dir_entry->modification_date = ((uint16_t) raw_entry[24]) | |
((uint16_t) raw_entry[25] << 8); |
#endif |
return 2; |
} |
} |
/** |
* \ingroup fat16_file |
* Retrieves the directory entry of a path. |
* |
* The given path may both describe a file or a directory. |
* |
* \param[in] fs The FAT16 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 fat16_read_dir |
*/ |
uint8_t fat16_get_dir_entry_of_path(struct fat16_fs_struct* fs, const char* path, struct fat16_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 = FAT16_ATTRIB_DIR; |
if(path[0] == '\0') |
return 1; |
while(1) |
{ |
struct fat16_dir_struct* dd = fat16_open_dir(fs, dir_entry); |
if(!dd) |
break; |
/* extract the next hierarchy we will search for */ |
const char* sep_pos = strchr(path, '/'); |
if(!sep_pos) |
sep_pos = path + strlen(path); |
uint8_t length_to_sep = sep_pos - path; |
/* read directory entries */ |
while(fat16_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; |
fat16_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 & FAT16_ATTRIB_DIR) |
{ |
/* we found a parent directory of the file we are searching for */ |
path = sep_pos + 1; |
break; |
} |
/* a parent of the file exists, but not the file itself */ |
return 0; |
} |
fat16_close_dir(dd); |
} |
return 0; |
} |
/** |
* \ingroup fat16_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. |
*/ |
uint16_t fat16_get_next_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
if(!fs || cluster_num < 2) |
return 0; |
/* read appropriate fat entry */ |
uint8_t fat_entry[2]; |
if(!fs->partition->device_read(fs->header.fat_offset + 2 * cluster_num, fat_entry, 2)) |
return 0; |
/* determine next cluster from fat */ |
cluster_num = ((uint16_t) fat_entry[0]) | |
((uint16_t) fat_entry[1] << 8); |
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; |
} |
/** |
* \ingroup fat16_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. |
*/ |
uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs) |
return 0; |
device_read_t device_read = fs->partition->device_read; |
device_write_t device_write = fs->partition->device_write; |
uint32_t fat_offset = fs->header.fat_offset; |
uint16_t cluster_max = fs->header.fat_size / 2; |
uint16_t cluster_next = 0; |
uint16_t count_left = count; |
uint8_t buffer[2]; |
for(uint16_t cluster_new = 0; cluster_new < cluster_max; ++cluster_new) |
{ |
if(!device_read(fat_offset + 2 * cluster_new, buffer, sizeof(buffer))) |
return 0; |
/* check if this is a free cluster */ |
if(buffer[0] == (FAT16_CLUSTER_FREE & 0xff) && |
buffer[1] == ((FAT16_CLUSTER_FREE >> 8) & 0xff)) |
{ |
/* allocate cluster */ |
if(count_left == count) |
{ |
buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff; |
buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff; |
} |
else |
{ |
buffer[0] = cluster_next & 0xff; |
buffer[1] = (cluster_next >> 8) & 0xff; |
} |
if(!device_write(fat_offset + 2 * cluster_new, buffer, sizeof(buffer))) |
break; |
cluster_next = cluster_new; |
if(--count_left == 0) |
break; |
} |
} |
do |
{ |
if(count_left > 0) |
break; |
/* We allocated a new cluster chain. Now join |
* it with the existing one. |
*/ |
if(cluster_num >= 2) |
{ |
buffer[0] = cluster_next & 0xff; |
buffer[1] = (cluster_next >> 8) & 0xff; |
if(!device_write(fat_offset + 2 * cluster_num, buffer, sizeof(buffer))) |
break; |
} |
return cluster_next; |
} while(0); |
/* No space left on device or writing error. |
* Free up all clusters already allocated. |
*/ |
fat16_free_clusters(fs, cluster_next); |
return 0; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_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 fat16_terminate_clusters |
*/ |
uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || cluster_num < 2) |
return 0; |
uint32_t fat_offset = fs->header.fat_offset; |
uint8_t buffer[2]; |
while(cluster_num) |
{ |
if(!fs->partition->device_read(fat_offset + 2 * cluster_num, buffer, 2)) |
return 0; |
/* get next cluster of current cluster before freeing current cluster */ |
uint16_t cluster_num_next = ((uint16_t) buffer[0]) | |
((uint16_t) buffer[1] << 8); |
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 */ |
buffer[0] = FAT16_CLUSTER_FREE & 0xff; |
buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff; |
fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2); |
/* 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; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_free_clusters |
*/ |
uint8_t fat16_terminate_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || cluster_num < 2) |
return 0; |
/* fetch next cluster before overwriting the cluster entry */ |
uint16_t cluster_num_next = fat16_get_next_cluster(fs, cluster_num); |
/* mark cluster as the last one */ |
uint8_t buffer[2]; |
buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff; |
buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff; |
if(!fs->partition->device_write(fs->header.fat_offset + 2 * cluster_num, buffer, 2)) |
return 0; |
/* free remaining clusters */ |
if(cluster_num_next) |
return fat16_free_clusters(fs, cluster_num_next); |
else |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_clear_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
#if FAT16_WRITE_SUPPORT |
if(cluster_num < 2) |
return 0; |
uint32_t cluster_offset = fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * fs->header.cluster_size; |
uint8_t zero[16]; |
return fs->partition->device_write_interval(cluster_offset, |
zero, |
fs->header.cluster_size, |
fat16_clear_cluster_callback, |
0 |
); |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Callback function for clearing a cluster. |
*/ |
uint16_t fat16_clear_cluster_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
#if FAT16_WRITE_SUPPORT |
memset(buffer, 0, 16); |
return 16; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Opens a file on a FAT16 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 fat16_close_file |
*/ |
struct fat16_file_struct* fat16_open_file(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !dir_entry || (dir_entry->attributes & FAT16_ATTRIB_DIR)) |
return 0; |
#if USE_DYNAMIC_MEMORY |
struct fat16_file_struct* fd = malloc(sizeof(*fd)); |
if(!fd) |
return 0; |
#else |
struct fat16_file_struct* fd = fat16_file_handlers; |
uint8_t i; |
for(i = 0; i < FAT16_FILE_COUNT; ++i) |
{ |
if(!fd->fs) |
break; |
++fd; |
} |
if(i >= FAT16_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 fat16_file |
* Closes a file. |
* |
* \param[in] fd The file handle of the file to close. |
* \see fat16_open_file |
*/ |
void fat16_close_file(struct fat16_file_struct* fd) |
{ |
if(fd) |
#if USE_DYNAMIC_MEMORY |
free(fd); |
#else |
fd->fs = 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_write_file |
*/ |
int16_t fat16_read_file(struct fat16_file_struct* fd, uint8_t* buffer, uint16_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; |
uint16_t cluster_num = fd->pos_cluster; |
uint16_t buffer_left = buffer_len; |
uint16_t first_cluster_offset = fd->pos % cluster_size; |
/* 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 = fat16_get_next_cluster(fd->fs, cluster_num); |
if(!cluster_num) |
return -1; |
} |
} |
} |
/* read data */ |
do |
{ |
/* calculate data size to copy from cluster */ |
uint32_t cluster_offset = fd->fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * cluster_size + 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 = fat16_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; |
} |
/** |
* \ingroup fat16_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 on disk full, or -1 on failure. |
* \see fat16_read_file |
*/ |
int16_t fat16_write_file(struct fat16_file_struct* fd, const uint8_t* buffer, uint16_t buffer_len) |
{ |
#if FAT16_WRITE_SUPPORT |
/* 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; |
uint16_t cluster_num = fd->pos_cluster; |
uint16_t buffer_left = buffer_len; |
uint16_t first_cluster_offset = fd->pos % cluster_size; |
/* 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 = fat16_append_clusters(fd->fs, 0, 1); |
if(!cluster_num) |
return -1; |
} |
else |
{ |
return -1; |
} |
} |
if(fd->pos) |
{ |
uint32_t pos = fd->pos; |
uint16_t cluster_num_next; |
while(pos >= cluster_size) |
{ |
pos -= cluster_size; |
cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num); |
if(!cluster_num_next && pos == 0) |
/* the file exactly ends on a cluster boundary, and we append to it */ |
cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1); |
if(!cluster_num_next) |
return -1; |
cluster_num = cluster_num_next; |
} |
} |
} |
/* write data */ |
do |
{ |
/* calculate data size to write to cluster */ |
uint32_t cluster_offset = fd->fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * cluster_size + 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 */ |
uint16_t cluster_num_next = fat16_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 = fat16_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) |
{ |
uint32_t size_old = fd->dir_entry.file_size; |
/* update file size */ |
fd->dir_entry.file_size = fd->pos; |
/* write directory entry */ |
if(!fat16_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; |
} |
} |
return buffer_len - buffer_left; |
#else |
return -1; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Repositions the read/write file offset. |
* |
* Changes the file offset where the next call to fat16_read_file() |
* or fat16_write_file() starts reading/writing. |
* |
* If the new offset is beyond the end of the file, fat16_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 FAT16_SEEK_SET: \c *offset is relative to the beginning of the file. |
* - \b FAT16_SEEK_CUR: \c *offset is relative to the current file position. |
* - \b FAT16_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. |
* |
* \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 fat16_seek_file(struct fat16_file_struct* fd, int32_t* offset, uint8_t whence) |
{ |
if(!fd || !offset) |
return 0; |
uint32_t new_pos = fd->pos; |
switch(whence) |
{ |
case FAT16_SEEK_SET: |
new_pos = *offset; |
break; |
case FAT16_SEEK_CUR: |
new_pos += *offset; |
break; |
case FAT16_SEEK_END: |
new_pos = fd->dir_entry.file_size + *offset; |
break; |
default: |
return 0; |
} |
if(new_pos > fd->dir_entry.file_size && !fat16_resize_file(fd, new_pos)) |
return 0; |
fd->pos = new_pos; |
fd->pos_cluster = 0; |
*offset = new_pos; |
return 1; |
} |
/** |
* \ingroup fat16_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 fat16_resize_file(struct fat16_file_struct* fd, uint32_t size) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fd) |
return 0; |
uint16_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 */ |
uint16_t cluster_num_next = fat16_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. |
*/ |
uint16_t cluster_count = size_new / cluster_size; |
if((uint32_t) cluster_count * cluster_size < size_new) |
++cluster_count; |
uint16_t cluster_new_chain = fat16_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(!fat16_write_dir_entry(fd->fs, &fd->dir_entry)) |
return 0; |
if(size == 0) |
{ |
/* free all clusters of file */ |
fat16_free_clusters(fd->fs, cluster_num); |
} |
else if(size_new <= cluster_size) |
{ |
/* free all clusters no longer needed */ |
fat16_terminate_clusters(fd->fs, cluster_num); |
} |
} while(0); |
/* correct file position */ |
if(size < fd->pos) |
{ |
fd->pos = size; |
fd->pos_cluster = 0; |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_close_dir |
*/ |
struct fat16_dir_struct* fat16_open_dir(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !dir_entry || !(dir_entry->attributes & FAT16_ATTRIB_DIR)) |
return 0; |
#if USE_DYNAMIC_MEMORY |
struct fat16_dir_struct* dd = malloc(sizeof(*dd)); |
if(!dd) |
return 0; |
#else |
struct fat16_dir_struct* dd = fat16_dir_handlers; |
uint8_t i; |
for(i = 0; i < FAT16_DIR_COUNT; ++i) |
{ |
if(!dd->fs) |
break; |
++dd; |
} |
if(i >= FAT16_DIR_COUNT) |
return 0; |
#endif |
memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry)); |
dd->fs = fs; |
dd->entry_next = 0; |
return dd; |
} |
/** |
* \ingroup fat16_dir |
* Closes a directory descriptor. |
* |
* This function destroys a directory descriptor which was |
* previously obtained by calling fat16_open_dir(). When this |
* function returns, the given descriptor will be invalid. |
* |
* \param[in] dd The directory descriptor to close. |
* \see fat16_open_dir |
*/ |
void fat16_close_dir(struct fat16_dir_struct* dd) |
{ |
if(dd) |
#if USE_DYNAMIC_MEMORY |
free(dd); |
#else |
dd->fs = 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_reset_dir |
*/ |
uint8_t fat16_read_dir(struct fat16_dir_struct* dd, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!dd || !dir_entry) |
return 0; |
if(dd->dir_entry.cluster == 0) |
{ |
/* read entry from root directory */ |
if(fat16_read_root_dir_entry(dd->fs, dd->entry_next, dir_entry)) |
{ |
++dd->entry_next; |
return 1; |
} |
} |
else |
{ |
/* read entry from a subdirectory */ |
if(fat16_read_sub_dir_entry(dd->fs, dd->entry_next, &dd->dir_entry, dir_entry)) |
{ |
++dd->entry_next; |
return 1; |
} |
} |
/* restart reading */ |
dd->entry_next = 0; |
return 0; |
} |
/** |
* \ingroup fat16_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 fat16_read_dir |
*/ |
uint8_t fat16_reset_dir(struct fat16_dir_struct* dd) |
{ |
if(!dd) |
return 0; |
dd->entry_next = 0; |
return 1; |
} |
/** |
* \ingroup fat16_fs |
* Searches for space where to store a directory entry. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] dir_entry The directory entry for which to search space. |
* \returns 0 on failure, a device offset on success. |
*/ |
uint32_t fat16_find_offset_for_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_struct* parent, const struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || !dir_entry) |
return 0; |
/* search for a place where to write the directory entry to disk */ |
uint8_t free_dir_entries_needed = (strlen(dir_entry->long_name) + 12) / 13 + 1; |
uint8_t free_dir_entries_found = 0; |
uint16_t cluster_num = parent->dir_entry.cluster; |
uint32_t dir_entry_offset = 0; |
uint32_t offset = 0; |
uint32_t offset_to = 0; |
if(cluster_num == 0) |
{ |
/* 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 entry |
* 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. |
*/ |
uint16_t cluster_next = fat16_get_next_cluster(fs, cluster_num); |
if(!cluster_next) |
{ |
cluster_next = fat16_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 + |
(uint32_t) (cluster_next - 2) * fs->header.cluster_size; |
/* clear cluster to avoid garbage directory entries */ |
fat16_clear_cluster(fs, cluster_next); |
break; |
} |
cluster_num = cluster_next; |
} |
offset = fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * fs->header.cluster_size; |
offset_to = offset + fs->header.cluster_size; |
dir_entry_offset = offset; |
free_dir_entries_found = 0; |
} |
/* 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 == FAT16_DIRENTRY_DELETED || !first_char) |
{ |
/* check if we have the needed number of available entries */ |
++free_dir_entries_found; |
if(free_dir_entries_found >= free_dir_entries_needed) |
break; |
offset += 32; |
} |
else |
{ |
offset += 32; |
dir_entry_offset = offset; |
free_dir_entries_found = 0; |
} |
} |
return dir_entry_offset; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_write_dir_entry(const struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || !dir_entry) |
return 0; |
#if FAT16_DATETIME_SUPPORT |
{ |
uint16_t year; |
uint8_t month; |
uint8_t day; |
uint8_t hour; |
uint8_t min; |
uint8_t sec; |
fat16_get_datetime(&year, &month, &day, &hour, &min, &sec); |
fat16_set_file_modification_date(dir_entry, year, month, day); |
fat16_set_file_modification_time(dir_entry, hour, min, sec); |
} |
#endif |
device_write_t device_write = fs->partition->device_write; |
uint32_t offset = dir_entry->entry_offset; |
const char* name = dir_entry->long_name; |
uint8_t name_len = strlen(name); |
uint8_t lfn_entry_count = (name_len + 12) / 13; |
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) |
name_ext_len = 3; |
memcpy(&buffer[8], name_ext, name_ext_len); |
} |
if(name_len <= 8) |
{ |
memcpy(buffer, name, name_len); |
/* 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; |
} |
else |
{ |
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); |
} |
if(buffer[0] == FAT16_DIRENTRY_DELETED) |
buffer[0] = 0x05; |
/* fill directory entry buffer */ |
memset(&buffer[11], 0, sizeof(buffer) - 11); |
buffer[0x0b] = dir_entry->attributes; |
#if FAT16_DATETIME_SUPPORT |
buffer[0x16] = (dir_entry->modification_time >> 0) & 0xff; |
buffer[0x17] = (dir_entry->modification_time >> 8) & 0xff; |
buffer[0x18] = (dir_entry->modification_date >> 0) & 0xff; |
buffer[0x19] = (dir_entry->modification_date >> 8) & 0xff; |
#endif |
buffer[0x1a] = (dir_entry->cluster >> 0) & 0xff; |
buffer[0x1b] = (dir_entry->cluster >> 8) & 0xff; |
buffer[0x1c] = (dir_entry->file_size >> 0) & 0xff; |
buffer[0x1d] = (dir_entry->file_size >> 8) & 0xff; |
buffer[0x1e] = (dir_entry->file_size >> 16) & 0xff; |
buffer[0x1f] = (dir_entry->file_size >> 24) & 0xff; |
/* write to disk */ |
if(!device_write(offset + (uint32_t) lfn_entry_count * 32, buffer, sizeof(buffer))) |
return 0; |
/* calculate checksum of 8.3 name */ |
uint8_t checksum = buffer[0]; |
for(uint8_t i = 1; i < 11; ++i) |
checksum = ((checksum >> 1) | (checksum << 7)) + buffer[i]; |
/* 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] |= FAT16_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); |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 file. |
* \returns 0 on failure, 1 on success. |
* \see fat16_delete_file |
*/ |
uint8_t fat16_create_file(struct fat16_dir_struct* parent, const char* file, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!parent || !file || !file[0] || !dir_entry) |
return 0; |
/* check if the file already exists */ |
while(1) |
{ |
if(!fat16_read_dir(parent, dir_entry)) |
break; |
if(strcmp(file, dir_entry->long_name) == 0) |
{ |
fat16_reset_dir(parent); |
return 0; |
} |
} |
struct fat16_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 = fat16_find_offset_for_dir_entry(fs, parent, dir_entry))) |
return 0; |
/* write directory entry to disk */ |
if(!fat16_write_dir_entry(fs, dir_entry)) |
return 0; |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_create_file |
*/ |
uint8_t fat16_delete_file(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || !dir_entry) |
return 0; |
/* get offset of the file's directory entry */ |
uint32_t dir_entry_offset = dir_entry->entry_offset; |
if(!dir_entry_offset) |
return 0; |
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] = FAT16_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; |
} |
/* We deleted the directory entry. The next thing to do is |
* marking all occupied clusters as free. |
*/ |
return (dir_entry->cluster == 0 || fat16_free_clusters(fs, dir_entry->cluster)); |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_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 fat16_delete_dir |
*/ |
uint8_t fat16_create_dir(struct fat16_dir_struct* parent, const char* dir, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!parent || !dir || !dir[0] || !dir_entry) |
return 0; |
/* check if the file or directory already exists */ |
while(1) |
{ |
if(!fat16_read_dir(parent, dir_entry)) |
break; |
if(strcmp(dir, dir_entry->long_name) == 0) |
{ |
fat16_reset_dir(parent); |
return 0; |
} |
} |
struct fat16_fs_struct* fs = parent->fs; |
/* allocate cluster which will hold directory entries */ |
uint16_t dir_cluster = fat16_append_clusters(fs, 0, 1); |
if(!dir_cluster) |
return 0; |
/* clear cluster to prevent bogus directory entries */ |
fat16_clear_cluster(fs, dir_cluster); |
memset(dir_entry, 0, sizeof(*dir_entry)); |
dir_entry->attributes = FAT16_ATTRIB_DIR; |
/* create "." directory self reference */ |
dir_entry->entry_offset = fs->header.cluster_zero_offset + |
(uint32_t) (dir_cluster - 2) * fs->header.cluster_size; |
dir_entry->long_name[0] = '.'; |
dir_entry->cluster = dir_cluster; |
if(!fat16_write_dir_entry(fs, dir_entry)) |
{ |
fat16_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(!fat16_write_dir_entry(fs, dir_entry)) |
{ |
fat16_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 = fat16_find_offset_for_dir_entry(fs, parent, dir_entry))) |
{ |
fat16_free_clusters(fs, dir_cluster); |
return 0; |
} |
/* write directory to disk */ |
if(!fat16_write_dir_entry(fs, dir_entry)) |
{ |
fat16_free_clusters(fs, dir_cluster); |
return 0; |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_dir |
* Deletes a directory. |
* |
* This is just a synonym for fat16_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 fat16_create_dir |
*/ |
#ifdef DOXYGEN |
uint8_t fat16_delete_dir(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry); |
#endif |
/** |
* \ingroup fat16_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 fat16_get_file_modification_date(const struct fat16_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day) |
{ |
#if FAT16_DATETIME_SUPPORT |
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 |
} |
/** |
* \ingroup fat16_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 fat16_get_file_modification_time(const struct fat16_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec) |
{ |
#if FAT16_DATETIME_SUPPORT |
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 |
} |
/** |
* \ingroup fat16_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 fat16_set_file_modification_date(struct fat16_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day) |
{ |
#if FAT16_WRITE_SUPPORT |
#if FAT16_DATETIME_SUPPORT |
if(!dir_entry) |
return; |
dir_entry->modification_date = |
((year - 1980) << 9) | |
((uint16_t) month << 5) | |
((uint16_t) day << 0); |
#endif |
#endif |
} |
/** |
* \ingroup fat16_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 fat16_set_file_modification_time(struct fat16_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec) |
{ |
#if FAT16_WRITE_SUPPORT |
#if FAT16_DATETIME_SUPPORT |
if(!dir_entry) |
return; |
dir_entry->modification_time = |
((uint16_t) hour << 11) | |
((uint16_t) min << 5) | |
((uint16_t) sec >> 1) ; |
#endif |
#endif |
} |
/** |
* \ingroup fat16_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. |
*/ |
uint32_t fat16_get_fs_size(const struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
return (fs->header.fat_size / 2 - 2) * fs->header.cluster_size; |
} |
/** |
* \ingroup fat16_fs |
* Returns the amount of free storage capacity on the filesystem in bytes. |
* |
* \note As the FAT16 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. |
*/ |
uint32_t fat16_get_fs_free(const struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
uint8_t fat[32]; |
struct fat16_usage_count_callback_arg count_arg; |
count_arg.cluster_count = 0; |
count_arg.buffer_size = sizeof(fat); |
uint32_t fat_offset = fs->header.fat_offset; |
uint32_t fat_size = fs->header.fat_size; |
while(fat_size > 0) |
{ |
uint16_t length = UINT16_MAX - 1; |
if(fat_size < length) |
length = fat_size; |
if(!fs->partition->device_read_interval(fat_offset, |
fat, |
sizeof(fat), |
length, |
fat16_get_fs_free_callback, |
&count_arg |
) |
) |
return 0; |
fat_offset += length; |
fat_size -= length; |
} |
return (uint32_t) count_arg.cluster_count * fs->header.cluster_size; |
} |
/** |
* \ingroup fat16_fs |
* Callback function used for counting free clusters. |
*/ |
uint8_t fat16_get_fs_free_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
struct fat16_usage_count_callback_arg* count_arg = (struct fat16_usage_count_callback_arg*) p; |
uint8_t buffer_size = count_arg->buffer_size; |
for(uint8_t i = 0; i < buffer_size; i += 2) |
{ |
if((((uint16_t) buffer[1] << 8) | ((uint16_t) buffer[0] << 0)) == FAT16_CLUSTER_FREE) |
++(count_arg->cluster_count); |
buffer += 2; |
} |
return 1; |
} |
/Designs/GPSRL02A/SW/logger/fat16.h |
---|
0,0 → 1,121 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 FAT16_H |
#define FAT16_H |
#include "fat16_config.h" |
#include <stdint.h> |
/** |
* \addtogroup fat16 |
* |
* @{ |
*/ |
/** |
* \file |
* FAT16 header (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* \addtogroup fat16_file |
* @{ |
*/ |
/** The file is read-only. */ |
#define FAT16_ATTRIB_READONLY (1 << 0) |
/** The file is hidden. */ |
#define FAT16_ATTRIB_HIDDEN (1 << 1) |
/** The file is a system file. */ |
#define FAT16_ATTRIB_SYSTEM (1 << 2) |
/** The file is empty and has the volume label as its name. */ |
#define FAT16_ATTRIB_VOLUME (1 << 3) |
/** The file is a directory. */ |
#define FAT16_ATTRIB_DIR (1 << 4) |
/** The file has to be archived. */ |
#define FAT16_ATTRIB_ARCHIVE (1 << 5) |
/** The given offset is relative to the beginning of the file. */ |
#define FAT16_SEEK_SET 0 |
/** The given offset is relative to the current read/write position. */ |
#define FAT16_SEEK_CUR 1 |
/** The given offset is relative to the end of the file. */ |
#define FAT16_SEEK_END 2 |
/** |
* @} |
*/ |
struct partition_struct; |
struct fat16_fs_struct; |
struct fat16_file_struct; |
struct fat16_dir_struct; |
/** |
* \ingroup fat16_file |
* Describes a directory entry. |
*/ |
struct fat16_dir_entry_struct |
{ |
/** The file's name, truncated to 31 characters. */ |
char long_name[32]; |
/** The file's attributes. Mask of the FAT16_ATTRIB_* constants. */ |
uint8_t attributes; |
#if FAT16_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. */ |
uint16_t cluster; |
/** The file's size. */ |
uint32_t file_size; |
/** The total disk offset of this directory entry. */ |
uint32_t entry_offset; |
}; |
struct fat16_fs_struct* fat16_open(struct partition_struct* partition); |
void fat16_close(struct fat16_fs_struct* fs); |
struct fat16_file_struct* fat16_open_file(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry); |
void fat16_close_file(struct fat16_file_struct* fd); |
int16_t fat16_read_file(struct fat16_file_struct* fd, uint8_t* buffer, uint16_t buffer_len); |
int16_t fat16_write_file(struct fat16_file_struct* fd, const uint8_t* buffer, uint16_t buffer_len); |
uint8_t fat16_seek_file(struct fat16_file_struct* fd, int32_t* offset, uint8_t whence); |
uint8_t fat16_resize_file(struct fat16_file_struct* fd, uint32_t size); |
struct fat16_dir_struct* fat16_open_dir(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry); |
void fat16_close_dir(struct fat16_dir_struct* dd); |
uint8_t fat16_read_dir(struct fat16_dir_struct* dd, struct fat16_dir_entry_struct* dir_entry); |
uint8_t fat16_reset_dir(struct fat16_dir_struct* dd); |
uint8_t fat16_create_file(struct fat16_dir_struct* parent, const char* file, struct fat16_dir_entry_struct* dir_entry); |
uint8_t fat16_delete_file(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry); |
uint8_t fat16_create_dir(struct fat16_dir_struct* parent, const char* dir, struct fat16_dir_entry_struct* dir_entry); |
#define fat16_delete_dir fat16_delete_file |
void fat16_get_file_modification_date(const struct fat16_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day); |
void fat16_get_file_modification_time(const struct fat16_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec); |
uint8_t fat16_get_dir_entry_of_path(struct fat16_fs_struct* fs, const char* path, struct fat16_dir_entry_struct* dir_entry); |
uint32_t fat16_get_fs_size(const struct fat16_fs_struct* fs); |
uint32_t fat16_get_fs_free(const struct fat16_fs_struct* fs); |
/** |
* @} |
*/ |
#endif |
/Designs/GPSRL02A/SW/logger/fat16_config.h |
---|
0,0 → 1,84 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 FAT16_CONFIG_H |
#define FAT16_CONFIG_G |
/** |
* \addtogroup fat16 |
* |
* @{ |
*/ |
/** |
* \file |
* FAT16 configuration (license: GPLv2 or LGPLv2.1) |
*/ |
/** |
* \ingroup fat16_config |
* Controls FAT16 write support. |
* |
* Set to 1 to enable FAT16 write support, set to 0 to disable it. |
*/ |
#define FAT16_WRITE_SUPPORT 1 |
/** |
* \ingroup fat16_config |
* Controls FAT16 date and time support. |
* |
* Set to 1 to enable FAT16 date and time stamping support. |
*/ |
#define FAT16_DATETIME_SUPPORT 0 |
/** |
* \ingroup fat16_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 FAT16_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 fat16_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 fat16_config |
* Maximum number of filesystem handles. |
*/ |
#define FAT16_FS_COUNT 1 |
/** |
* \ingroup fat16_config |
* Maximum number of file handles. |
*/ |
#define FAT16_FILE_COUNT 1 |
/** |
* \ingroup fat16_config |
* Maximum number of directory handles. |
*/ |
#define FAT16_DIR_COUNT 2 |
/** |
* @} |
*/ |
#endif |
/Designs/GPSRL02A/SW/logger/main.c |
---|
0,0 → 1,475 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 <string.h> |
#include <avr/pgmspace.h> |
#include <avr/sleep.h> |
#include "fat16.h" |
#include "fat16_config.h" |
#include "partition.h" |
#include "sd_raw.h" |
#include "sd_raw_config.h" |
#include "uart.h" |
#define DEBUG 1 |
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 fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* dir_entry); |
static struct fat16_file_struct* open_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name); |
static uint8_t print_disk_info(const struct fat16_fs_struct* fs); |
int main() |
{ |
/* we will just use ordinary idle mode */ |
set_sleep_mode(SLEEP_MODE_IDLE); |
/* setup uart */ |
uart_init(); |
/* setup sd card slot */ |
if(!sd_raw_init()) |
{ |
#if DEBUG |
uart_puts_p(PSTR("MMC/SD initialization failed\n")); |
#endif |
return 1; |
} |
/* open first partition */ |
struct partition_struct* partition = partition_open(sd_raw_read, |
sd_raw_read_interval, |
sd_raw_write, |
sd_raw_write_interval, |
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, |
sd_raw_write, |
sd_raw_write_interval, |
-1 |
); |
if(!partition) |
{ |
#if DEBUG |
uart_puts_p(PSTR("opening partition failed\n")); |
#endif |
return 1; |
} |
} |
/* open file system */ |
struct fat16_fs_struct* fs = fat16_open(partition); |
if(!fs) |
{ |
#if DEBUG |
uart_puts_p(PSTR("opening filesystem failed\n")); |
#endif |
return 1; |
} |
/* open root directory */ |
struct fat16_dir_entry_struct directory; |
fat16_get_dir_entry_of_path(fs, "/", &directory); |
struct fat16_dir_struct* dd = fat16_open_dir(fs, &directory); |
if(!dd) |
{ |
#if DEBUG |
uart_puts_p(PSTR("opening root directory failed\n")); |
#endif |
return 1; |
} |
/* print some card information as a boot message */ |
print_disk_info(fs); |
/* provide a simple shell */ |
char buffer[20]; |
char* command = buffer; |
//!!!KAKL |
{ |
uint8_t n; |
while(uart_getc()!='$'); |
while(uart_getc()!=','); |
for(n=0; n<6; n++) |
{ |
buffer[n]=uart_getc(); |
}; |
buffer[6]='\0'; |
} |
{ |
struct fat16_dir_entry_struct file_entry; |
fat16_create_file(dd, command, &file_entry); |
} |
{ |
int32_t offset; |
offset = 0; |
while(1) |
{ |
uint8_t znak; |
struct fat16_file_struct* fd = open_file_in_dir(fs, dd, command); |
fat16_seek_file(fd, &offset, FAT16_SEEK_SET); |
do |
{ |
znak=uart_getc(); |
fat16_write_file(fd, (uint8_t*) &znak, 1); |
uart_putc(znak); |
offset++; |
} while ((znak!='\n')&&(znak!='@')); |
fat16_close_file(fd); |
if(znak=='@') break; |
} |
} |
while(1) |
{ |
/* print prompt */ |
uart_putc('>'); |
uart_putc(' '); |
/* read command */ |
if(read_line(command, sizeof(buffer)) < 1) |
continue; |
/* execute command */ |
if(strncmp_P(command, PSTR("cd "), 3) == 0) |
{ |
command += 3; |
if(command[0] == '\0') |
continue; |
/* change directory */ |
struct fat16_dir_entry_struct subdir_entry; |
if(find_file_in_dir(fs, dd, command, &subdir_entry)) |
{ |
struct fat16_dir_struct* dd_new = fat16_open_dir(fs, &subdir_entry); |
if(dd_new) |
{ |
fat16_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 fat16_dir_entry_struct dir_entry; |
while(fat16_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 & FAT16_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 fat16_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; |
while(fat16_read_file(fd, buffer, sizeof(buffer)) > 0) |
{ |
uart_putdw_hex(offset); |
uart_putc(':'); |
for(uint8_t i = 0; i < 8; ++i) |
{ |
uart_putc(' '); |
uart_putc_hex(buffer[i]); |
} |
uart_putc('\n'); |
offset += 8; |
} |
fat16_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 FAT16_WRITE_SUPPORT |
else if(strncmp_P(command, PSTR("rm "), 3) == 0) |
{ |
command += 3; |
if(command[0] == '\0') |
continue; |
struct fat16_dir_entry_struct file_entry; |
if(find_file_in_dir(fs, dd, command, &file_entry)) |
{ |
if(fat16_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 fat16_dir_entry_struct file_entry; |
if(!fat16_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("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 fat16_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(!fat16_seek_file(fd, &offset, FAT16_SEEK_SET)) |
{ |
uart_puts_p(PSTR("error seeking on ")); |
uart_puts(command); |
uart_putc('\n'); |
fat16_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(fat16_write_file(fd, (uint8_t*) buffer, data_len) != data_len) |
{ |
uart_puts_p(PSTR("error writing to file\n")); |
break; |
} |
} |
fat16_close_file(fd); |
} |
else if(strncmp_P(command, PSTR("mkdir "), 6) == 0) |
{ |
command += 6; |
if(command[0] == '\0') |
continue; |
struct fat16_dir_entry_struct dir_entry; |
if(!fat16_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 file system */ |
fat16_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 fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* dir_entry) |
{ |
while(fat16_read_dir(dd, dir_entry)) |
{ |
if(strcmp(dir_entry->long_name, name) == 0) |
{ |
fat16_reset_dir(dd); |
return 1; |
} |
} |
return 0; |
} |
struct fat16_file_struct* open_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name) |
{ |
struct fat16_dir_entry_struct file_entry; |
if(!find_file_in_dir(fs, dd, name, &file_entry)) |
return 0; |
return fat16_open_file(fs, &file_entry); |
} |
uint8_t print_disk_info(const struct fat16_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); uart_putc('\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(fat16_get_fs_free(fs)); uart_putc('/'); |
uart_putdw_dec(fat16_get_fs_size(fs)); uart_putc('\n'); |
return 1; |
} |
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; |
} |
/Designs/GPSRL02A/SW/logger/partition.c |
---|
0,0 → 1,159 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 "partition.h" |
#include "partition_config.h" |
#include "sd-reader_config.h" |
#include <string.h> |
#if USE_DYNAMIC_MEMORY |
#include <stdlib.h> |
#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. |
* \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 = ((uint32_t) buffer[8]) | |
((uint32_t) buffer[9] << 8) | |
((uint32_t) buffer[10] << 16) | |
((uint32_t) buffer[11] << 24); |
new_partition->length = ((uint32_t) buffer[12]) | |
((uint32_t) buffer[13] << 8) | |
((uint32_t) buffer[14] << 16) | |
((uint32_t) buffer[15] << 24); |
} |
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; |
} |
/** |
* @} |
*/ |
/Designs/GPSRL02A/SW/logger/partition.h |
---|
0,0 → 1,201 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 <stdint.h> |
/** |
* \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)(uint32_t offset, uint8_t* buffer, uint16_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, uint32_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)(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_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)(uint32_t offset, const uint8_t* buffer, uint16_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 uint16_t (*device_write_callback_t)(uint8_t* buffer, uint32_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)(uint32_t offset, uint8_t* buffer, uint16_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 bytes on the disk where this partition starts. |
*/ |
uint32_t offset; |
/** |
* The length in bytes 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); |
/** |
* @} |
*/ |
#endif |
/Designs/GPSRL02A/SW/logger/partition_config.h |
---|
0,0 → 1,35 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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_G |
/** |
* \addtogroup partition |
* |
* @{ |
*/ |
/** |
* \file |
* Partition configuration (license: GPLv2 or LGPLv2.1) |
*/ |
/** |
* \ingroup partition_config |
* Maximum number of partition handles. |
*/ |
#define PARTITION_COUNT 1 |
/** |
* @} |
*/ |
#endif |
/Designs/GPSRL02A/SW/logger/sd-reader.hex |
---|
0,0 → 1,899 |
:100000000C941D010C943A010C943A010C943A01A1 |
:100010000C943A010C943A010C943A010C943A0174 |
:100020000C943A010C943A010C943A010C943A0164 |
:100030000C943A010C943A010C943A010C943A0154 |
:100040000C943A010C943A010C94341B0C943A0130 |
:100050000C943A010C943A010C943A010C943A0134 |
:100060000C943A010C943A01756E6B6E6F776E20AA |
:10007000636F6D6D616E643A20006572726F7220FD |
:100080006372656174696E67206469726563746F19 |
:1000900072793A20006D6B64697220006572726F2C |
:1000A000722077726974696E6720746F2066696C5C |
:1000B000650A006572726F72207365656B696E67A1 |
:1000C000206F6E20006572726F72206F70656E69AE |
:1000D0006E672000777269746520006572726F72B6 |
:1000E000206372656174696E672066696C653A2089 |
:1000F00000746F75636820006572726F72206465AA |
:100100006C6574696E672066696C653A2000726D73 |
:1001100020006572726F722072656164696E67207B |
:100120006469736B20696E666F0A006469736B00A3 |
:100130006572726F72206F70656E696E6720006302 |
:10014000617420006C73006469726563746F727906 |
:10015000206E6F7420666F756E643A2000636420B1 |
:10016000006F70656E696E6720726F6F74206469CE |
:10017000726563746F7279206661696C65640A00E8 |
:100180006F70656E696E672066696C6573797374EC |
:10019000656D206661696C65640A006F70656E69E3 |
:1001A0006E6720706172746974696F6E2066616930 |
:1001B0006C65640A004D4D432F534420696E697489 |
:1001C00069616C697A6174696F6E206661696C65DA |
:1001D000640A00667265653A20202000666F726DC1 |
:1001E00061743A200077722E70722E3A2000636F8D |
:1001F00070793A2020200073697A653A2020200027 |
:10020000646174653A2020200073657269616C3AFC |
:10021000203078007265763A202020200070726FBE |
:10022000643A202020006F656D3A20202020006D68 |
:10023000616E75663A202030780011241FBECFEF22 |
:10024000D4E0DEBFCDBF11E0A0E0B1E0E2E0F8E332 |
:1002500002C005900D92A230B107D9F713E0A2E0D9 |
:10026000B1E001C01D92A23CB107E1F70E94B512B6 |
:100270000C94001C0C940000FC01892B11F01182DD |
:1002800010820895CF93DF93FC01D9018081853ED0 |
:1002900029F1882319F12D913C911197ED018A8163 |
:1002A0009B812817390799F44C835D836E837F8384 |
:1002B00083858F3011F080E205C080818295880FA0 |
:1002C000807E805EFD01808780E090E009C08385AC |
:1002D0008F3021F02F5F3F4F2D933C9381E090E0D2 |
:1002E000DF91CF910895EF92FF920F931F93CF93D9 |
:1002F000DF93EC017A018B01B9018881853E09F415 |
:10030000CCC0882309F4C9C0F90187A190A5A1A593 |
:10031000B2A50097A105B10521F4E7A2F0A601A7B7 |
:1003200012A76115710509F4B8C0209709F4B5C08A |
:100330009881992309F4B1C0AE01455F5F4F8B8569 |
:100340008F3099F5892F99278F7390702DE030E0C9 |
:10035000AC01429FC001439F900D529F900D11240C |
:100360009C012D5030400197809708F093C0FB010D |
:10037000E20FF31F898180838B8181838D8182834A |
:100380008F818383898584838E858583888986830D |
:100390008A8987838C8980878E898187888D8287E7 |
:1003A0008C8D83878E8D848775C0FB018081882327 |
:1003B000B9F580E090E0382FFE01E80FF91F2081A9 |
:1003C000203249F0FB01E80FF91F20833F5F0196BF |
:1003D0008830910581F7FB018081853011F485EE2D |
:1003E00080838885803211F4832F16C0FB01E30FD0 |
:1003F000F11D8EE28083832F8F5FDE01232F2C5F20 |
:10040000FD019085903241F0FB01E80FF11D9083D2 |
:100410008F5F11968217A1F7FB01E80FF11D108283 |
:10042000FA018081FB0180A38B8D9927982F882763 |
:100430002A8D3327822B932B92A381A32D8D3327D3 |
:1004400044275527542F432F322F22278E8D99274B |
:10045000AA27BB27DC0199278827282B392B4A2B71 |
:100460005B2B8C8D9927AA27BB27282B392B4A2B4E |
:100470005B2B8F8D9927AA27BB27B82FAA279927EF |
:100480008827282B392B4A2B5B2B23A334A345A386 |
:1004900056A303C081E090E002C080E090E0DF91CD |
:1004A000CF911F910F91FF90EF9008950F931F939D |
:1004B000CF93DF93CDB7DEB722970FB6F894DEBFA8 |
:1004C0000FBECDBFDC01892BA9F16230710590F11F |
:1004D0000D911C911197660F771F88279927FD01B1 |
:1004E0002681378140855185620F731F841F951FB8 |
:1004F000D801ED91FC9122E030E0AE014F5F5F4FFB |
:1005000009958823B9F08A819927382F2227898174 |
:100510009927282B392B2115310571F0BFEF273F83 |
:100520003B0741F0C9014096079720F0EFEF283FC5 |
:100530003E0710F020E030E0C90122960FB6F89493 |
:10054000DEBF0FBECDBFDF91CF911F910F910895F8 |
:100550004F925F926F927F928F929F92AF92BF92D3 |
:10056000CF92DF92EF92FF920F931F93CF93DF937F |
:10057000CDB7DEB722970FB6F894DEBF0FBECDBF62 |
:100580005C01009709F44BC06230710508F447C064 |
:10059000FC0166807780808491842E010894411C40 |
:1005A000511C660F771F6B01EE24FF24C60CD71C6D |
:1005B000E81CF91CD501ED91FC910190F081E02D32 |
:1005C00022E030E0A201C701B6010995882339F184 |
:1005D0008A819927182F002789819927082B192BA1 |
:1005E00001151105F9F0C80140960897C0F0BFEF5A |
:1005F000083F1B0710F000E010E019821A82D501B5 |
:10060000ED91FC910480F581E02D22E030E0A20123 |
:10061000C701B6010995B801012B21F0C2CF80E0D6 |
:1006200090E002C081E090E022960FB6F894DEBF21 |
:100630000FBECDBFDF91CF911F910F91FF90EF9033 |
:10064000DF90CF90BF90AF909F908F907F906F90F2 |
:100650005F904F9008952F923F924F925F926F92CA |
:100660007F928F929F92AF92BF92CF92DF92EF9242 |
:10067000FF920F931F93CF93DF93CDB7DEB72C97E5 |
:100680000FB6F894DEBF0FBECDBF3C012B011A019F |
:10069000009709F495C0DC01ED91FC912081318136 |
:1006A0003C872B870480F581E02DFA87E987FC01E0 |
:1006B00086819781A085B1858D839E83AF83B8871E |
:1006C00082859385A485B585B695A79597958795D9 |
:1006D0009C838B836A01AA24BB248824992444C068 |
:1006E000C401880F991F7C01002711272D813E81AD |
:1006F0004F815885E20EF31E041F151F22E030E0E3 |
:10070000AE014F5F5F4FC801B701AB85BC85FD01EE |
:100710000995882309F454C08981882311F58A81B9 |
:100720008823F9F4C214D30419F48FEF898303C02A |
:10073000A9828B2D99278A8322E030E0AE014F5F9A |
:100740005F4FC801B701E985FA850995882391F0C3 |
:100750000894C108D108C114D10411F454010CC08B |
:1007600054010894811C911C2B813C8182169306B4 |
:1007700009F0B6CFCD2801F532E04316510410F14F |
:10078000A9828B2D99278A83440C551CB201882796 |
:1007900099272D813E814F815885620F731F841FD9 |
:1007A000951F22E030E0AE014F5F5F4FA985BA850B |
:1007B000FD010995882331F4B501C3010E94A80207 |
:1007C000AA24BB24C5012C960FB6F894DEBF0FBE39 |
:1007D000CDBFDF91CF911F910F91FF90EF90DF90F0 |
:1007E000CF90BF90AF909F908F907F906F905F90D1 |
:1007F0004F903F902F900895CF92DF92EF92FF920B |
:100800000F931F93CF93DF93CDB7DEB760970FB6EB |
:10081000F894DEBF0FBECDBF7C016230710518F4C5 |
:1008200080E090E027C0FC01C088D1880081118160 |
:1008300062507040882799279601442755270E94C7 |
:10084000981B9B01AC01F70166897789808D918D9A |
:10085000620F731F841F951FF801A681B781EE24D4 |
:10086000FF240AEE16E09601AE014F5F5F4FFD01D7 |
:100870000995992760960FB6F894DEBF0FBECDBFDD |
:10088000DF91CF911F910F91FF90EF90DF90CF906C |
:100890000895FC01892B11F01182108208952F9286 |
:1008A0003F924F925F926F927F928F929F92AF9200 |
:1008B000BF92CF92DF92EF92FF920F931F93CF934D |
:1008C000DF93CDB7DEB72C970FB6F894DEBF0FBE1F |
:1008D000CDBF3C0178876F835A874987009709F419 |
:1008E000FCC0672B09F4F9C0452B09F4F6C0FC01E4 |
:1008F000A5A4B6A4C7A4D0A825A136A147A150A5F8 |
:1009000069857A85CB01AA27BB278A0D9B1DAC1D63 |
:10091000BD1D281739074A075B0738F42A193B0918 |
:100920003A872987232B09F4DBC0D3018D919C9151 |
:10093000FC01808991899A838983F30101A8F2A936 |
:10094000E02DFC87EB87BC01882799276B837C838C |
:100950008D839E83EF2BE1F5F30103A0F4A1E02D3D |
:10096000FC87EB87EF2B39F4A114B104C104D10447 |
:1009700009F4B6C0B2C0A114B104C104D10441F15C |
:10098000860175012B803C804D805E8050944094A0 |
:1009900030942094211C311C411C511C10C06B85CB |
:1009A0007C85D3018D919C910E9456029C878B87F8 |
:1009B000892B09F492C0E20CF31C041D151D6B81F8 |
:1009C0007C818D819E81E616F7060807190738F7A6 |
:1009D000C601B5012B813C814D815E810E94DE1BE9 |
:1009E0002B0189849A84D3018D919C91A980BA802E |
:1009F000A418B5088A149B0408F45401FC01C080B3 |
:100A0000D18072010027112786899789A08DB18D29 |
:100A1000E80EF91E0A1F1B1F2B853C852250304013 |
:100A2000B901882799272E5F3F4F3C872B872B8161 |
:100A30003C814D815E810E94981BE60EF71E081FC7 |
:100A4000191FD601CD90DC9095014F815885C801C2 |
:100A5000B701F6010995882339F18A189B08C50169 |
:100A6000AA27BB27F30125A536A547A550A9280F1E |
:100A7000391F4A1F5B1F25A736A747A750ABC501E3 |
:100A8000840D951D29813A8182179307A0F06B850B |
:100A90007C85808191810E9456029C878B87892B5F |
:100AA00041F4F30112AA11AA49855A854819590936 |
:100AB00019C0442455242B853C85F30132AB21AB6E |
:100AC0008114910439F06F8178856A0D7B1D7887D8 |
:100AD0006F8389CF49855A8505C04FEF5FEF02C00C |
:100AE00040E050E0CA012C960FB6F894DEBF0FBE6E |
:100AF000CDBFDF91CF911F910F91FF90EF90DF90CD |
:100B0000CF90BF90AF909F908F907F906F905F90AD |
:100B10004F903F902F900895FC01892B11F0118286 |
:100B200010820895FC01892B19F480E090E008956B |
:100B300016A615A681E090E008958F929F92AF923D |
:100B4000BF92CF92DF92EF92FF920F931F93CF93BA |
:100B5000DF93CDB7DEB72C970FB6F894DEBF0FBE8C |
:100B6000CDBF6C015B01892B09F452C06115710581 |
:100B700009F44EC0FB01E7A0F0A401A512A5E11401 |
:100B8000F1040105110509F443C04E010894811CCC |
:100B9000911CD601ED91FC910190F081E02D2CE0AB |
:100BA00030E0A401C801B7010995882389F185EED9 |
:100BB0008983D601ED91FC910480F581E02D2CE034 |
:100BC00030E0A401C801B7010995882309F18C859B |
:100BD0008F3049F480E290E0A0E0B0E0E80EF91E2A |
:100BE0000A1F1B1FD6CFF50161A172A16115710506 |
:100BF00019F481E090E00AC0C6010E94A80220E03A |
:100C000030E0882311F021E030E0C901992702C0CB |
:100C100080E090E02C960FB6F894DEBF0FBECDBFFB |
:100C2000DF91CF911F910F91FF90EF90DF90CF90C8 |
:100C3000BF90AF909F908F90089508950895FC0104 |
:100C4000892B29F460E070E080E090E008956285EF |
:100C50007385848595859695879577956795625078 |
:100C600070408040904020893189442755270E9458 |
:100C7000981B08952F923F924F925F926F927F92AE |
:100C80008F929F92AF92BF92CF92DF92EF92FF929C |
:100C90000F931F93CF93DF93CDB7DEB7A5970FB612 |
:100CA000F894DEBF0FBECDBF1C01892B09F456C0DE |
:100CB0001A82198280E28B83F1014680578060841A |
:100CC000718482849384A484B58437C0FEEF8F1628 |
:100CD000FFEF9F06F0E0AF06F0E0BF0628F02EEF32 |
:100CE0003FEF3DA32CA302C09DA28CA2D101ED91A8 |
:100CF000FC910280F381E02D6E010894C11CD11C8F |
:100D0000BBECEB2EB6E0FB2E0CA11DA120E230E0E7 |
:100D1000AE014C5F5F4FC301B20109958823F1F02A |
:100D20000CA11DA1C801AA27BB27480E591E6A1E87 |
:100D30007B1E881A990AAA0ABB0A81149104A1048D |
:100D4000B10421F6F10160897189882799272981E9 |
:100D50003A81442755270E94981B04C060E070E048 |
:100D600080E090E0A5960FB6F894DEBF0FBECDBF31 |
:100D7000DF91CF911F910F91FF90EF90DF90CF9077 |
:100D8000BF90AF909F908F907F906F905F904F90AB |
:100D90003F902F900895AC01D901F9016281FC01C7 |
:100DA00012C081819927982F882720813327822B91 |
:100DB000932B892B39F48D919C9111970196119663 |
:100DC0009C938E9332968E2F841B861750F381E06E |
:100DD00090E0089520E1FC0111922A95E9F780E165 |
:100DE00090E008952F923F924F925F926F927F9280 |
:100DF0008F929F92AF92BF92CF92DF92EF92FF922B |
:100E00000F931F93CF93DF93CDB7DEB7E5970FB660 |
:100E1000F894DEBF0FBECDBF1C017DA76CA7009765 |
:100E200009F4F7C0672B09F4F4C0FC0163A074A0B7 |
:100E300025A536A53FA72EA74080518061147104D7 |
:100E400009F050C04114510409F4E0C0D201ED9101 |
:100E5000FC91A280B3809E012F5F3F4F89E0F90192 |
:100E600011928A95E9F78EA59FA59C838B83F20149 |
:100E7000628973898489958906891789061B170BEE |
:100E8000FAE08F2E912C8C0E9D1E6901E2E4EE2E6D |
:100E9000E1E0FE2E20E230E0A401F501099588236F |
:100EA00009F4B4C04D805E806F8078844114510491 |
:100EB0006104710409F4AAC08BE2ACA5BDA51D9222 |
:100EC0008A95E9F709851127CCA4DDA473E7E72EFD |
:100ED00071E0F72E20E230E0A401C301B201F50178 |
:100EE000099584C04114510409F490C0FC0182A109 |
:100EF00084FF8CC0F2010088F189E02DFBA7EAA7EE |
:100F0000CF01AA27BB2788AB99ABAAABBBABDE014D |
:100F10001196BDABACABEEEFFFEF6E0E7F1EB301D3 |
:100F20008827992722E030E0620E731E28A939A98C |
:100F30004AA95BA90E94981BF20186889788A08C19 |
:100F4000B18C860E971EA81EB91E89E0ACA9BDA95A |
:100F50001D928A95E9F7EEA5FFA5FC83EB83D201EC |
:100F6000ED91FC91AE01465F5F4F0280F381E02D71 |
:100F70006E010894C11CD11C62E4E62E61E0F62EDD |
:100F80000AA51BA520E230E0C501B401099588231C |
:100F9000E9F18D809E80AF80B88481149104A10412 |
:100FA000B10441F4B301C2010E9456023C01892BF5 |
:100FB00069F1B1CF8BE2ECA5FDA511928A95E9F715 |
:100FC000D201ED91FC91098511270280F381E02D7A |
:100FD000CCA4DDA433E7E32E31E0F32E20E230E0B1 |
:100FE000AE01465F5F4FC501B4010995882371F0DA |
:100FF000ECA5FDA58081882349F0F10185A596A582 |
:10100000019696A785A781E090E005C0F10116A69C |
:1010100015A680E090E0E5960FB6F894DEBF0FBE0F |
:10102000CDBFDF91CF911F910F91FF90EF90DF9097 |
:10103000CF90BF90AF909F908F907F906F905F9078 |
:101040004F903F902F9008952F923F924F925F9232 |
:101050006F927F928F929F92AF92BF92CF92DF92C8 |
:10106000EF92FF920F931F93CF93DF93CDB7DEB72D |
:10107000AC970FB6F894DEBF0FBECDBF6C010097E2 |
:1010800009F4A2C1FC0184819581892B09F49CC1DA |
:1010900086819781892B09F497C102E011E01CA792 |
:1010A0000BA78091020190910301892B09F08CC15B |
:1010B0008AE1D8011D928A95E9F7D0920301C09286 |
:1010C0000201018512852385348589E0000F111FF7 |
:1010D000221F331F8A95D1F70AA31BA32CA33DA37C |
:1010E000C901B801655F7F4F8F4F9F4F0190F0811D |
:1010F000E02D29E130E0AE014F5F5F4F0995882375 |
:1011000009F45EC129813A80FB81F8A74C813D81B9 |
:101110005E812F8048845984AA848D859927F82F71 |
:10112000EE278C859927E82BF92BEE888F89688D1F |
:10113000798D309709F444C19927AA27BB276624E3 |
:10114000782E892E9A2E862F9927AA27BB27DC0175 |
:1011500099278827682A792A8A2A9B2A8E2D9927F7 |
:10116000AA27BB27682A792A8A2A9B2A872F9927A8 |
:10117000AA27BB27B82FAA2799278827682A792A60 |
:101180008A2A9B2A611471048104910479F48A2DBE |
:101190009927782F6627852D9927682B792B61153C |
:1011A000710509F40DC13B0188249924832D9927E9 |
:1011B000982F88279FA38EA3822F99270EA11FA166 |
:1011C000082B192B1FA30EA3842D9927982F88274E |
:1011D0009AA789A7822D992769A57AA5682B792BCB |
:1011E0007AA769A7832F9927982F8827242F332739 |
:1011F000822B932B8C01222733270A8F1B8F2C8F56 |
:101200003D8FBF0188279927252F3327442755274E |
:101210000E94981B6E8F7F8F88A399A3840173010E |
:101220002A8D3B8D4C8D5D8DE21AF30A040B150B54 |
:10123000E61AF70A080B190B8EA19FA1019729A5A1 |
:101240003AA545E0220F331F4A95E1F7820F931F1D |
:101250006EA17FA10E94B71B88279927E61AF70A7B |
:10126000080B190B68A5262F332744275527C801DB |
:10127000B7010E94DE1B19012A01DA01C901855F4D |
:101280009F40A040B0408050904FA040B04008F038 |
:1012900097C086E0F60180870BA51CA50E5F1F4F47 |
:1012A00088E1D8011D928A95E9F7025010401CA7E9 |
:1012B0000BA7EEA1FFA15F01CC24DD24C401B30183 |
:1012C000A60195010E94981B60930401709305018B |
:1012D0008093060190930701C601B5012A8D3B8DCD |
:1012E0004C8D5D8D0E94981B7B018C012AA13BA136 |
:1012F0004CA15DA1E20EF31E041F151FE092080130 |
:10130000F092090100930A0110930B01220C331C87 |
:10131000441C551C44E050E060E070E0240E351E93 |
:10132000461E571E20920C0130920D0140920E0174 |
:1013300050920F016EA17FA1709311016093100173 |
:1013400078A5872F9927AEA1BFA1FC01AE9FC00150 |
:10135000AF9F900DBE9F900D112490931301809329 |
:1013600012016E8D7F8D88A199A1A60195010E9421 |
:10137000981B6E0D7F1D801F911F60931401709349 |
:101380001501809316019093170109A51AA59801DC |
:1013900044275527A5E0220F331F441F551FAA9548 |
:1013A000D1F7620F731F841F951F6093180170930C |
:1013B000190180931A0190931B018BA59CA506C06F |
:1013C000109203011092020180E090E0AC960FB6FB |
:1013D000F894DEBF0FBECDBFDF91CF911F910F916B |
:1013E000FF90EF90DF90CF90BF90AF909F908F9045 |
:1013F0007F906F905F904F903F902F9008952F9225 |
:101400003F924F925F926F927F928F929F92AF9294 |
:10141000BF92CF92DF92EF92FF920F931F93CF93E1 |
:10142000DF93CDB7DEB723970FB6F894DEBF0FBEBC |
:10143000CDBF1C019B01892B09F4C2C04115510588 |
:1014400009F4BEC0FA0101900020E9F7E41BF50B96 |
:10145000CF010B966DE070E00E94B71B6F5F6B834E |
:10146000F90143A054A04114510451F0662477249B |
:101470004301AA24BB246501EE24FF2487010BC08D |
:10148000F101A288B388C488D588E688F788008DE2 |
:10149000118D350146011A82AE14BF04C006D10673 |
:1014A00009F05EC04114510409F48AC0A114B104CA |
:1014B000C104D10479F1B201C1010E945602009722 |
:1014C00041F541E050E0B201C1010E942B038C01C3 |
:1014D000892B09F475C002501040B801882799275C |
:1014E0000E5F1F4FF10120893189442755270E9443 |
:1014F000981B3B014C01F10186899789A08DB18D24 |
:10150000680E791E8A1E9B1EB801C1010E94FC0351 |
:101510005AC02C01F101E088F188002711272EEF35 |
:101520003FEF420E531EB20188279927A2E0B0E098 |
:101530004A0E5B1EA80197010E94981B5B016C017B |
:10154000F10186899789A08DB18DA80EB91ECA1E9A |
:10155000DB1EEA0CFB1C0C1D1D1D350146011A8209 |
:10156000D101ED91FC910190F081E02D21E030E07E |
:10157000AE014F5F5F4FC601B5010995882301F1A8 |
:101580008981853E11F0882379F4BA81BF5FBA83DF |
:10159000EB81BE17C0F480E290E0A0E0B0E0A80EBE |
:1015A000B91ECA1EDB1E78CF90E2692E712C812CE9 |
:1015B000912C6A0C7B1C8C1C9D1C640153016BCF0D |
:1015C000662477244301C401B30123960FB6F8942F |
:1015D000DEBF0FBECDBFDF91CF911F910F91FF9066 |
:1015E000EF90DF90CF90BF90AF909F908F907F90C3 |
:1015F0006F905F904F903F902F9008954F925F9221 |
:101600007F928F929F92AF92BF92CF92DF92EF9292 |
:10161000FF920F931F93CF93DF93CDB7DEB7A097C1 |
:101620000FB6F894DEBF0FBECDBFFC018B01892B36 |
:1016300009F41AC16115710509F416C10190F08110 |
:10164000E02D44805580FB01A7A0B0A4C1A4D2A482 |
:1016500001900020E9F73197FE2EF61A8F2D992779 |
:101660000C966DE070E00E94CB1B762E4BE050E0B4 |
:1016700060E270E0CE0101960E94551B6EE270E0C0 |
:10168000C8010E948D1BFC010097C1F0DC0111967E |
:101690008181882399F0FD0101900020E9F73197BD |
:1016A000EA1BFB0BFE1AFA944E2FE43008F043E0DD |
:1016B0005527BD01CE0109960E944C1BCE01019613 |
:1016C000F8E0FF1588F04F2D5527B8010E944C1BFC |
:1016D000D8018C918E3219F5F80181818E3209F48E |
:1016E00082818823D9F01BC0DC01F80188E00190D9 |
:1016F0000D928150E1F7F80181A1982F92959F708A |
:10170000803A10F4905D01C09F598F708A3010F4B8 |
:10171000805D01C08F599F83888701C077248981AC |
:10172000853E11F485E089837CE0872E912C8C0E18 |
:101730009D1E85E1D4011D928A95E9F7F80180A1EB |
:101740008C8781A192A18B8F892F99278C8F83A160 |
:1017500094A1A5A1B6A18D8F292F3A2F4B2F5527E4 |
:101760002E8F9D01442755272F8F8B2F9927AA272E |
:10177000BB2788A3672D77278827992725E0660F41 |
:10178000771F881F991F2A95D1F76A0D7B1D8C1D25 |
:101790009D1D20E230E0AE014F5F5F4FF2010995E1 |
:1017A000882309F461C0E980FE01329694018E2DF0 |
:1017B0008695E794EE24E794E82A8191E80EE217F3 |
:1017C000F307A9F7F72C4E010894811C911C0D50CA |
:1017D000104044C040E250E06FEF70E0C4010E944E |
:1017E000551B8DE0F89ED0011124A00FB11F91E090 |
:1017F000F401E90FF11D8C918083892F8F5FF40133 |
:10180000E80FF11D10829E5F9B3021F09A3119F490 |
:101810009CE101C09EE08C91882321F09F3110F45F |
:101820001196E6CFF982F71419F48F2D806489831D |
:101830008FE08C87EE861D861B8E1C8E20E230E0AA |
:10184000A401C601B501F201099580E290E0A0E093 |
:10185000B0E0A80EB91ECA1EDB1EFA94FF2009F0E4 |
:10186000B9CF81E090E002C080E090E0A0960FB692 |
:10187000F894DEBF0FBECDBFDF91CF911F910F91C6 |
:10188000FF90EF90DF90CF90BF90AF909F908F90A0 |
:101890007F905F904F9008952F923F924F925F926A |
:1018A0006F927F928F929F92AF92BF92CF92DF9270 |
:1018B000EF92FF920F931F93CF93DF93CDB7DEB7D5 |
:1018C0002E970FB6F894DEBF0FBECDBF6C011A0184 |
:1018D0002B01009709F4E2C0FC01E3A0F4A0019001 |
:1018E000F081E02D80899189E114F10431F44115F2 |
:1018F00051056105710509F4BDC0420131019C012A |
:10190000442755272F83388749875A875095409514 |
:10191000309521953F4F4F4F5F4F2B873C874D8729 |
:101920005E8711C0B701D6018D919C910E9456022D |
:101930000097B9F02B853C854D855E85620E731E40 |
:10194000841E951E7C018F819885A985BA858B831D |
:101950009C83AD83BE8386159705A805B90510F352 |
:10196000A0C05701C401B3012B813C814D815E8130 |
:101970000E94DE1B8901B901882799272B813C81B0 |
:101980004D815E810E94981B661577058805990533 |
:1019900010F40F5F1F4FA801B701D6018D919C91E4 |
:1019A0000E942B03009709F479C0EF2821F4F60177 |
:1019B00094A383A35C01F60125A236A247A250A6F8 |
:1019C000211431044104510411F414A213A2B601EC |
:1019D0006E5F7F4FD6018D919C910E94FE0A8823F5 |
:1019E00009F45CC0211431044104510429F4B50107 |
:1019F000F601808191813CC02B813C814D815E81CB |
:101A00002615370548055905A8F1D6010D911C91F9 |
:101A10000115110579F1B2E0AB16B10458F1B50129 |
:101A2000C8010E9456027C018FEF89838A83F801E6 |
:101A300080809180AA0CBB1CB5018827992726813C |
:101A4000378140855185620F731F841F951FF401F4 |
:101A5000A481B58122E030E0AE014F5F5F4FFD0110 |
:101A60000995882339F0E114F10421F0B701C80188 |
:101A70000E94A802F60185A596A5A7A5B0A92816DB |
:101A800039064A065B0638F4F60125A636A647A6AF |
:101A900050AA12AA11AA81E090E009C080E090E06B |
:101AA00006C05701E114F10409F45CCF84CF2E96EF |
:101AB0000FB6F894DEBF0FBECDBFDF91CF911F915F |
:101AC0000F91FF90EF90DF90CF90BF90AF909F90DD |
:101AD0008F907F906F905F904F903F902F900895E0 |
:101AE000CF92DF92EF92FF920F931F93CF93DF93EA |
:101AF000EC016B01892B09F446C06115710509F4ED |
:101B000042C08DA59EA5AFA5B8A9413059F041307E |
:101B100018F04230C1F50CC0FB01E080F180028179 |
:101B2000138113C0FB01E080F1800281138109C0A1 |
:101B3000FB01E080F180028113818DA19EA1AFA104 |
:101B4000B8A5E80EF91E0A1F1B1F8DA19EA1AFA10B |
:101B5000B8A58E159F05A007B10738F4B801A701F5 |
:101B6000CE010E944C0C882371F0EDA6FEA60FA7B3 |
:101B700018AB1AAA19AAF601E082F1820283138334 |
:101B800081E090E002C080E090E0DF91CF911F9172 |
:101B90000F91FF90EF90DF90CF9008952F923F929A |
:101BA0004F925F926F927F928F929F92AF92BF926D |
:101BB000CF92DF92EF92FF920F931F93CF93DF9319 |
:101BC000CDB7DEB72A970FB6F894DEBF0FBECDBFF4 |
:101BD0005C011B0158874F83009709F43BC1672BB9 |
:101BE00009F438C1452B09F435C1FC0165A476A47C |
:101BF00087A490A885A196A1A7A1B0A58615970551 |
:101C0000A805B90508F426C120813181F9010088B1 |
:101C1000F189E02DFA83E983F50101A8F2A9E02D0D |
:101C2000FA87E98789819A81AA27BB278B839C83BE |
:101C3000AD83BE83EF2B09F059C0F50103A0F4A1D9 |
:101C4000E02DFA87E987EF2BA9F461147104810470 |
:101C5000910409F0FFC041E050E060E070E0C9018C |
:101C60000E942B039A878987F50194A383A3892B6C |
:101C700009F4F0C0F501E5A4F6A407A510A9E11444 |
:101C8000F1040105110549F531C08B819C81AD81BD |
:101C9000BE81E81AF90A0A0B1B0B69857A85D50102 |
:101CA0008D919C910E945602009719F09A8789871E |
:101CB00014C0E114F1040105110509F0CBC041E0A5 |
:101CC00050E069857A85F501808191810E942B031E |
:101CD000009709F4BFC09A8789878B819C81AD8169 |
:101CE000BE81E816F9060A071B0778F6C401B3019E |
:101CF0002B813C814D815E810E94DE1B2B016F8018 |
:101D00007884D5018D919C9189809A80841895085A |
:101D10006814790408F44301FC01C080D180720189 |
:101D20000027112786899789A08DB18DE80EF91EAD |
:101D30000A1F1B1F29853A8522503040B901882788 |
:101D400099272E5F3F4F3A8729872B813C814D8110 |
:101D50005E810E94981BE60EF71E081F191FF601F0 |
:101D6000A481B5819401A101C801B701FD010995C4 |
:101D7000882309F446C068187908C401AA27BB273C |
:101D8000F50125A536A547A550A9280F391F4A1FDB |
:101D90005B1F25A736A747A750ABC401840D951D2F |
:101DA00029813A818217930708F169857A858081B4 |
:101DB00091810E945602009719F09A87898714C072 |
:101DC0006114710459F041E050E069857A85D501CC |
:101DD0008D919C910E942B03009721F4F50112AA8A |
:101DE00011AA0FC09A8789874424552429853A85EA |
:101DF000F50132AB21AB6114710419F0280C391CC8 |
:101E000080CFF50185A596A5A7A5B0A9E5A0F6A068 |
:101E100007A110A5E816F9060A071B07B0F485A369 |
:101E200096A3A7A3B0A7B5016E5F7F4F8081918174 |
:101E30000E94FE0A882349F4F50165A476A46E1871 |
:101E40007F08E5A6F6A607A710AB8F8198858619AF |
:101E5000970902C08FEF9FEF2A960FB6F894DEBF66 |
:101E60000FBECDBFDF91CF911F910F91FF90EF90EB |
:101E7000DF90CF90BF90AF909F908F907F906F90AA |
:101E80005F904F903F902F900895CF93DF939C01E8 |
:101E9000FB01892B21F1672B11F180A184FF1FC069 |
:101EA00080914F0190915001892B19F4AFE4B1E07A |
:101EB00008C080917E0190917F01892B81F4AEE76B |
:101EC000B1E0ED0122968BE2019009928150E1F799 |
:101ED00011963C932E93FD0116A615A602C0A0E014 |
:101EE000B0E0CD01DF91CF910895CF93DF939C01B6 |
:101EF000FB01892B49F16115710531F180A184FD48 |
:101F000023C080911C0190911D01892BE9F4CEE141 |
:101F1000D1E0DB018BE20D9009928150E1F7309323 |
:101F20001D0120931C011092490110924A01109248 |
:101F30004B0110924C0181A192A190934E0180938C |
:101F40004D018CE191E002C080E090E0DF91CF9103 |
:101F50000895CF92DF92EF92FF920F931F93CF934A |
:101F6000DF937C018B01EA01892B09F443C06115E1 |
:101F7000710509F43FC0FB0180818823D9F1452B0D |
:101F8000C9F1BE01C7010E94F206882351F0BE01CB |
:101F9000C8010E94671B892BA1F7F70116A615A699 |
:101FA00029C0F701C080D1808BE2FE0111928A9591 |
:101FB000E9F74FE150E0B801CE010E947E1BAE016F |
:101FC000B701C6010E94FF096FA378A789A79AA746 |
:101FD000611571058105910569F0BE01C6010E9478 |
:101FE000FE0A90E0882309F491E081E09827892F88 |
:101FF000992702C080E090E0DF91CF911F910F916F |
:10200000FF90EF90DF90CF9008956F927F928F9224 |
:102010009F92AF92BF92CF92DF92EF92FF920F9377 |
:102020001F93CF93DF933C018B017A01892B09F435 |
:1020300061C06115710509F45DC0FB0180818823D1 |
:1020400009F458C0452B09F455C08F3211F40F5FC5 |
:102050001F4F8BE2F70111928A95E9F780E1F701B2 |
:1020600080A3F8018081882309F447C0B701C30128 |
:102070000E94450F5C01892BE9F16FE270E0C80115 |
:102080000E945C1B6C01892B41F4F8010190002037 |
:10209000E9F76F010894C108D1088C2D801B882EA8 |
:1020A000992421C0E70109900020E9F72197CE1972 |
:1020B000DF09C815D905B9F4AE01B701C8010E94FE |
:1020C000701B892B81F4F50111821082C00FD11F82 |
:1020D0008881882391F0F70180A184FF0BC08601DD |
:1020E0000F5F1F4FC3CFB701C5010E94F2068823BF |
:1020F000C9F606C080E090E007C081E090E004C02F |
:10210000F50111821082B2CFDF91CF911F910F9113 |
:10211000FF90EF90DF90CF90BF90AF909F908F9007 |
:102120007F906F9008959F92AF92BF92CF92DF926F |
:10213000EF92FF920F931F93CF93DF936C015B019C |
:10214000EA01892B09F495C06115710509F491C064 |
:10215000FB018081882309F48CC0452B09F489C0D8 |
:10216000BE01C6010E94F206882351F0BE01C501DE |
:102170000E94671B892BA1F7F60116A615A679C048 |
:10218000F601E080F18041E050E060E070E0C701DE |
:102190000E942B038C01009709F46BC0BC01C7019E |
:1021A0000E94FC038BE2FE0111928A95E9F780E11F |
:1021B00088A302501040B801882799270E5F1F4F4F |
:1021C000F70120893189442755270E94981BF70180 |
:1021D00026893789408D518D260F371F481F591F7B |
:1021E0002FA338A749A75AA7BEE29B2E98821AA30D |
:1021F00009A3BE01C7010E94FE0A8823B1F18FA185 |
:1022000098A5A9A5BAA58096A11DB11D8FA398A7D1 |
:10221000A9A7BAA79982F60183A194A19AA389A339 |
:10222000BE01C7010E94FE0A8823F9F04FE150E089 |
:10223000B501CE010E947E1B1AA309A3AE01B6010F |
:10224000C7010E94FF096FA378A789A79AA7611504 |
:1022500071058105910549F0BE01C7010E94FE0A82 |
:10226000882319F081E090E006C0B801C7010E9400 |
:10227000A80280E090E0DF91CF911F910F91FF9035 |
:10228000EF90DF90CF90BF90AF909F900895EF9226 |
:10229000FF920F931F93FC01DB01B80187ED97E0DC |
:1022A0009183808381E08C93FA018083F90110820D |
:1022B000FB011082F70110821F910F91FF90EF90A8 |
:1022C00008950F931F93CF93DF93CDB7DEB7699730 |
:1022D0000FB6F894DEBF0FBECDBF8C01892B09F479 |
:1022E0009CC0CE0101960E940319882309F495C071 |
:1022F0008FE292E00E94101B89810E94261A8AE0D8 |
:102300000E94171A86E292E00E94101BCE010296EC |
:102310000E94031B8AE00E94171A8DE192E00E943E |
:10232000101BCE0105960E94031B8AE00E94171A1B |
:1023300084E192E00E94101B8B850E94261A8AE09D |
:102340000E94171A89E092E00E94101B6C857D851F |
:102350008E859F850E944F1A8AE00E94171A80E09E |
:1023600092E00E94101B898999270E94621A8FE2CD |
:102370000E94171A888999270E94621A8AE00E948F |
:10238000171A87EF91E00E94101B6A897B898C895C |
:102390009D890E94A21A8AE00E94171A8EEE91E08F |
:1023A0000E94101B8E8999270E94621A8AE00E945F |
:1023B000171A85EE91E00E94101B888D99270E94C4 |
:1023C000621A8FE20E94171A8F8999270E94621A57 |
:1023D0008AE00E94171A8CED91E00E94101B898DF3 |
:1023E00099270E94621A8AE00E94171A83ED91E0F1 |
:1023F0000E94101BC8010E943A060E94A21A8FE296 |
:102400000E94171AC8010E941F060E94A21A8AE0A1 |
:102410000E94171A81E090E002C080E090E0699687 |
:102420000FB6F894DEBF0FBECDBFDF91CF911F91E5 |
:102430000F910895EF92FF920F931F93CF93DF9325 |
:102440008B017A01E9010CC0B701CE010E94671B24 |
:10245000892B31F4C8010E94920581E090E008C008 |
:10246000BE01C8010E94F206882371F780E090E067 |
:10247000DF91CF911F910F91FF90EF900895EF9210 |
:10248000FF920F931F93CF93DF93CDB7DEB7AB9738 |
:102490000FB6F894DEBF0FBECDBF8C017E0108944D |
:1024A000E11CF11C97010E941A12882319F480E0A4 |
:1024B00090E004C0B701C8010E94750FAB960FB63B |
:1024C000F894DEBF0FBECDBFDF91CF911F910F916A |
:1024D000FF90EF900895AF92BF92DF92EF92FF923C |
:1024E0000F931F93CF93DF937C01062F1127A80131 |
:1024F00060E070E00E94551BDD2458010894A1089B |
:10250000B10823C00E941E1B182F883011F08F378E |
:1025100089F4DD20D1F0DA94F701ED0DF11D108280 |
:1025200088E00E94171A80E20E94171A88E00E9431 |
:10253000171A0BC00E94171AF701EC0FFD1F1A3073 |
:1025400011F4108207C01083D394CD2DDD27CA1556 |
:10255000DB05C4F2CE01DF91CF911F910F91FF9067 |
:10256000EF90DF90BF90AF900895C6E8D4E0DEBF53 |
:10257000CDBF83B7817F83BF0E940B1A0E94901842 |
:10258000882319F485EB91E068C200E020EC37E184 |
:102590004DE057E16AE178E186E796E10E943D155A |
:1025A000009781F40FEF20EC37E14DE057E16AE14D |
:1025B00078E186E796E10E943D15009719F48BE9D2 |
:1025C00091E04BC20E9424082C01009719F480E886 |
:1025D00091E043C28E010E5D1F4FA80160E071E0E3 |
:1025E0000E940510B801C2010E94450F3C01892BD1 |
:1025F00019F481E691E031C2C2010E9461110E948A |
:102600001E1B8432E1F70E941E1B8C32E1F78E0103 |
:10261000025F1F4F680164E1E62EF12CEC0EFD1EF7 |
:102620000E941E1BD8018D938D01AE15BF05C1F709 |
:102630001C8AAE01435B5F4FB601C3010E94A90F24 |
:102640001A821B821C821D825EE0A52EB12CAC0E6C |
:10265000BD1E42E0C42ED12CCC0EDD1E7E0108949E |
:10266000E11CF11CA501B301C2010E943F128C01C3 |
:1026700040E0B6010E94700D0E941E1B898341E05C |
:1026800050E0B701C8010E94CE0D89810E94171A3F |
:102690008A819B81AC81BD810196A11DB11D8A8378 |
:1026A0009B83AC83BD8389818A3011F0803421F70C |
:1026B000C8010E94490489818034A1F63EE0A32E1E |
:1026C000B12CAC0EBD1E2DE4222E312C2C0E3D1E45 |
:1026D000EA96BFAEAEAEEA978EE30E94171A80E28A |
:1026E0000E94171A64E1C5010E946B128823A1F3AE |
:1026F00043E050E06DE571E0C5010E943E1B892B6F |
:10270000F9F4E3E0F0E0AE0EBF1ED5018C91882312 |
:1027100019F39101A501B301C2010E941A12882385 |
:1027200061F0B101C2010E94450F8C01892B29F093 |
:10273000C3010E948C053801CFCF87E491E084C1AA |
:1027400064E471E0C5010E94351B892B81F528C026 |
:10275000F10101900020E9F78F01015010400219AA |
:102760001309C1010E94031BF10180A184FF02C073 |
:102770008FE201C080E294E2F92EF01A01C080E2FB |
:102780000E94171AFA94FFEFFF16C9F7F10163A12F |
:1027900074A185A196A10E94A21A8AE00E94171A2C |
:1027A000B101C3010E94F206882391F695CF44E05F |
:1027B00050E06FE371E0C5010E943E1B892B09F0D8 |
:1027C00049C084E090E0A80EB91ED5018C91882301 |
:1027D00009F482CFA501B301C2010E943F124C014E |
:1027E000892B21F0CC24DD24760127C080E391E001 |
:1027F0002BC1C701B6010E944F1A8AE30E94171A23 |
:102800008E010A5F1F4F80E20E94171AF801819122 |
:102810008F010E94261AEA968EAD9FADEA9708179F |
:10282000190789F78AE00E94171A88E090E0A0E073 |
:10283000B0E0C80ED91EEA1EFB1E48E050E0BE0103 |
:102840006A5F7F4FC4010E944F04181619068CF26C |
:10285000C401BAC06BE271E0C5010E94351B892B2F |
:1028600059F4C2010E946111882309F035CF82E139 |
:1028700091E00E94101B30CF43E050E06EE071E029 |
:10288000C5010E943E1B892BD9F4A3E0B0E0AA0E3B |
:10289000BB1EF5018081882309F41ECF9101A5019B |
:1028A000B301C2010E941A12882339F0B101C2019A |
:1028B0000E949D05882309F00FCF88EF90E0C4C0E7 |
:1028C00046E050E061EF70E0C5010E943E1B892B9D |
:1028D000A1F486E090E0A80EB91ED5018C91882362 |
:1028E00009F4FACEA101B501C3010E94A90F882302 |
:1028F00009F0F2CE8BED90E0A7C046E050E064ED29 |
:1029000070E0C5010E943E1B892B09F07EC0E6E005 |
:10291000F0E0AE0EBF1ED5018C91882309F4DCCE09 |
:10292000850102C00F5F1F4FF8018081803219F0CE |
:102930008823C1F7D1CED8011C92A501B301C201F1 |
:102940000E943F127C01892B19F485EC90E07CC039 |
:1029500020E030E040E050E017C0CA01B9012AE0B1 |
:1029600030E040E050E00E94981B9B01AC018D2DAF |
:10297000992787FD9095C097AA2797FDA095BA2F14 |
:10298000280F391F4A1F5B1FF801D1800F5F1F4FAF |
:102990008D2D80538A3008F32A833B834C835D83DB |
:1029A00040E0BE016E5F7F4FC7010E94700D88231B |
:1029B00071F483EB90E00E94101BC5010E94031B81 |
:1029C0008AE00E94171AC7010E94490485CE8CE351 |
:1029D0000E94171A80E20E94171A64E1CE010E9637 |
:1029E0000E946B12882379F3082F1127A801BE01DA |
:1029F000625F7F4FC7010E94CE0D8017910739F3A8 |
:102A00008CE990E00E94101BDECF46E050E065E9C3 |
:102A100070E0C5010E943E1B892BA1F486E090E086 |
:102A2000A80EB91ED5018C91882309F455CEA101B9 |
:102A3000B501C3010E949310882309F04DCE8AE7A7 |
:102A400090E002C088E690E00E94101BC5010E9441 |
:102A5000031B8AE00E94171A3FCE0E94101B81E0E0 |
:102A600090E00C94001CFC01892B19F480E090E0AC |
:102A70000895108681E090E008958F929F92AF9222 |
:102A8000BF92CF92DF92EF92FF920F93CF93DF939B |
:102A9000CDB7DEB760970FB6F894DEBF0FBECDBFDF |
:102AA0007C016B015A014901892B09F4AAC0672BEB |
:102AB00009F4A7C004300CF0A4C007FD1DC0602FAE |
:102AC000772767FD7095E4E0660F771FEA95E1F7D9 |
:102AD00062547E4F882777FD8095982F20E130E063 |
:102AE000AE014F5F5F4FF7010995882309F489C054 |
:102AF0008D81882309F485C08091B501882309F070 |
:102B000080C0EDEAF1E081E1DF011D928A95E9F7ED |
:102B1000F092AE01E092AD01D092B001C092AF014F |
:102B2000B092B201A092B1019092B4018092B3012F |
:102B300007FD62C08D818093B5012A853327442724 |
:102B40005527542F432F322F22278B859927AA27C9 |
:102B5000BB27DC0199278827282B392B4A2B5B2B95 |
:102B600089859927AA27BB27282B392B4A2B5B2B32 |
:102B70008C859927AA27BB27B82FAA2799278827AA |
:102B8000282B392B4A2B5B2B2093B6013093B701AE |
:102B90004093B8015093B9012E8533274427552718 |
:102BA000542F432F322F22278F859927AA27BB27FF |
:102BB000DC0199278827282B392B4A2B5B2B8D8505 |
:102BC0009927AA27BB27282B392B4A2B5B2B8889CF |
:102BD0009927AA27BB27B82FAA2799278827282B08 |
:102BE000392B4A2B5B2B2093BA013093BB014093C6 |
:102BF000BC015093BD0103C08FEF8093B501CF019D |
:102C000002C080E090E060960FB6F894DEBF0FBE81 |
:102C1000CDBFDF91CF910F91FF90EF90DF90CF90DC |
:102C2000BF90AF909F908F90089586B182958F70DE |
:102C300099278095909581709070089586B18295BE |
:102C400086958770992780959095817090700895EA |
:102C50008EBD0DB407FEFDCF8DB58F778DBD089568 |
:102C60008FEF8EBD0DB407FEFDCF8DB58F778DBD77 |
:102C70008EB599270895DF92EF92FF920F931F93DD |
:102C8000D82E7A018B010E9430168D2D80640E940F |
:102C90002816812F9927AA27BB270E942816C8012A |
:102CA000AA27BB270E942816BB27A12F902F8F2D64 |
:102CB0000E9428168E2D0E942816DD2011F485E929 |
:102CC00001C08FEF0E94281610E00E9430168F3F3F |
:102CD00019F41F5F1A30C9F799271F910F91FF90C0 |
:102CE000EF90DF90089581E090E008952F923F9259 |
:102CF0004F925F926F927F928F929F92AF92BF920C |
:102D0000CF92DF92EF92FF920F931F93CF93DF93B7 |
:102D10003B014C012A01190167C0C12C4EEFD42E92 |
:102D20004FEFE42E4FEFF42EC620D720E820F920F5 |
:102D300083011170A12C32E0B32EA01AB10A2A141B |
:102D40003B0408F451018091BE039091BF03A09110 |
:102D5000C003B091C103C816D906EA06FB0691F17B |
:102D60002A98B701A60181E10E943B16882321F031 |
:102D70002A9A80E090E03EC00E9430168E3FE1F734 |
:102D8000CEEBD1E00E943016899383E0CE3BD8078A |
:102D9000C9F7C092BE03D092BF03E092C003F09285 |
:102DA000C10302541E4FA501B801C2010E944C1B71 |
:102DB0004A0C5B1C0E9430160E9430162A9A0E9410 |
:102DC000301609C002541E4FA501B801C2010E946D |
:102DD0004C1B4A0C5B1C2A183B08C501AA27BB27C1 |
:102DE000680E791E8A1E9B1E2114310409F095CFAE |
:102DF00081E090E0DF91CF911F910F91FF90EF90D4 |
:102E0000DF90CF90BF90AF909F908F907F906F900A |
:102E10005F904F903F902F9008952F923F924F9246 |
:102E20005F926F927F928F929F92AF92BF92CF925A |
:102E3000DF92EF92FF920F931F93CF93DF935B018B |
:102E40006C012A01390186B182958695877080FFD1 |
:102E500077C081C0E12C7EEFF72E7FEF072F7FEF49 |
:102E6000172FEA20FB200C211D21E501D170812CB8 |
:102E700062E0962E8C1A9D0A6814790408F44301C6 |
:102E80008091BE039091BF03A091C003B091C10394 |
:102E9000E816F9060A071B07C9F0209729F480E015 |
:102EA000881682E0980650F420E032E0A101C801C3 |
:102EB000B7010E947616882309F44DC0E092BE0344 |
:102EC000F092BF030093C0031093C1038EEB48162A |
:102ED00081E0580639F0A401B201CE0182549E4F20 |
:102EE0000E944C1B2A98B801A70188E10E943B165A |
:102EF000882311F02A9A2FC08EEF0E942816E10134 |
:102F000089910E94281683E0CE3BD807C9F78FEF3E |
:102F10000E9428168FEF0E9428160E9430168F3FBD |
:102F2000E1F7480C591C0E9430162A9A6818790853 |
:102F3000C401AA27BB27A80EB91ECA1EDB1E04C0E7 |
:102F40005EEB252E51E0352E6114710409F082CF1D |
:102F500081E090E002C080E090E0DF91CF911F918E |
:102F60000F91FF90EF90DF90CF90BF90AF909F9028 |
:102F70008F907F906F905F904F903F902F9008952B |
:102F80004F925F926F927F928F929F92AF92BF9279 |
:102F9000CF92DF92EF92FF920F931F93CF93DF9325 |
:102FA0005B016C014A01E90138012701452B61F100 |
:102FB000012B51F1FF24232B11F5FF24F3941FC0A3 |
:102FC0009201B601A501C401F30109958C01009796 |
:102FD000F1F0FF2019F4C817D907B0F09801A40147 |
:102FE000C601B5010E940D17882371F0C801AA27F8 |
:102FF000BB27A80EB91ECA1EDB1EC01BD10BFF20AB |
:10300000F9F62097E9F603C080E090E002C081E085 |
:1030100090E0DF91CF911F910F91FF90EF90DF90A3 |
:10302000CF90BF90AF909F908F907F906F905F9068 |
:103030004F9008952F923F924F925F926F927F929E |
:103040008F929F92AF92BF92CF92DF92EF92FF92B8 |
:103050000F931F93CF93DF93CDB7DEB724970FB6AF |
:10306000F894DEBF0FBECDBF4B015C013A013C833B |
:103070002B832701DA82C982452BA1F12115310565 |
:1030800089F10217130770F1EF2861F119013094EB |
:10309000219431083394021B130B6901EE24FF24A1 |
:1030A0002B813C81A301C501B4010E9476168823BF |
:1030B000C9F029813A81B501A401C301F201099542 |
:1030C000882399F0020D131D8B819C81800F911F25 |
:1030D0002B813C818217930740F08C0C9D1CAE1C09 |
:1030E000BF1CDECF80E090E002C081E090E024963B |
:1030F0000FB6F894DEBF0FBECDBFDF91CF911F9109 |
:103100000F91FF90EF90DF90CF90BF90AF909F9086 |
:103110008F907F906F905F904F903F902F90089589 |
:103120001F93CF93DF933C983D98239A259A229A38 |
:1031300024982A9A83E58CBD8DB58E7F8DBD86B18E |
:1031400082958F7080FD17C010E00E9430161F5FBF |
:103150001A30D9F72A98C0E0D0E040E050E060E0B3 |
:1031600070E080E00E943B16813051F081E0CF3F5B |
:10317000D80721F42A9A80E090E041C02196EDCF53 |
:10318000C0E0D0E040E050E060E070E081E00E940C |
:103190003B1680FF06C08FE7CF3FD80759F3219633 |
:1031A000F1CF40E052E060E070E080E10E943B1629 |
:1031B000882301F72A9A8CB58C7F8CBD8DB58160F0 |
:1031C0008DBD8FEF9FEFAFEFBFEF8093BE03909366 |
:1031D000BF03A093C003B093C10320E032E04EEBE5 |
:1031E00051E060E070E080E090E00E94761690E0B0 |
:1031F000882309F491E081E09827892F9927DF91AE |
:10320000CF911F910895CF92DF92EF92FF920F938B |
:103210001F93CF93DF93EC01892B09F4F1C086B1A2 |
:1032200082958F7080FDECC089E1FE0111928A9534 |
:10323000E9F72A9840E050E060E070E08AE00E9400 |
:103240003B16882309F061C00E9430168E3FE1F7DB |
:103250008E0120E6E22EF12C0E943016282F802FBE |
:103260008C1B883028F4833090F4882359F00CC0EC |
:103270008D3018F4893080F40DC08D3029F18E30F6 |
:1032800079F526C028832CC0F801208329C0F801D5 |
:10329000218326C02A8724C03327442755270E2C94 |
:1032A00004C0220F331F441F551F0A94D2F78B8589 |
:1032B0009C85AD85BE85822B932BA42BB52B8B874C |
:1032C0009C87AD87BE870CC02295207F2F8708C0C2 |
:1032D000922F92959F708F85892B8F872F70288BC7 |
:1032E0000F5F1F4F88EF9FEFE80EF91E90EDE91674 |
:1032F0009FEFF90609F0B0CF40E050E060E070E0E9 |
:1033000089E00E943B16882311F02A9A79C00E9416 |
:1033100030168E3FE1F7CC24DD24EE24FF2400E0BC |
:1033200010E00E943016083021F1093040F40630D8 |
:1033300091F00730B0F4053009F058C008C00A30E9 |
:1033400041F10A3008F10E3009F050C03AC09FE058 |
:10335000C92EC8224BC0992783709070F82EEE2496 |
:1033600045C09927E82AF92AEE0CFF1CEE0CFF1C39 |
:103370003DC082958695869583709927E82AF92A1B |
:103380000894E11CF11C32C0F3E0DF2ED822DD0CE2 |
:103390002DC0881F8827881FD82A970144275527C2 |
:1033A0008C2D992702968D0D911D04C0220F331F7D |
:1033B000441F551F8A95D2F7298B3A8B4B8B5C8B18 |
:1033C00015C0282F332726FF02C081E08D8B25FFF3 |
:1033D00002C081E08E8B24FF02C081E08F8B2C70B5 |
:1033E00030703595279535952795288F0F5F1F4F9E |
:1033F0000231110509F095CF2A9A81E090E002C0D0 |
:1034000080E090E0DF91CF911F910F91FF90EF90BE |
:10341000DF90CF9008951092C50087E68093C40096 |
:1034200086E08093C20088E98093C10008951F93CD |
:10343000182F8A3019F48DE00E94171A8091C0006D |
:1034400085FFFCCF1093C6001F9108951F93182F7E |
:1034500082958F708A3010F4805D01C0895A0E9475 |
:10346000171A812F99278F709070212F2F700A972C |
:103470001CF4822F805D02C0822F895A0E94171A85 |
:103480001F9108950F931F938C01812F99270E94FC |
:10349000261A802F0E94261A1F910F910895EF92ED |
:1034A000FF920F931F937B018C01C801AA27BB27B2 |
:1034B0000E94421AC7010E94421A1F910F91FF9069 |
:1034C000EF900895DF92EF92FF920F931F93CF93A7 |
:1034D000DF93EC0100E117E220E0EE24FF24CE01AF |
:1034E000B8010E94B71BD62E662329F4222319F4B3 |
:1034F0000130110529F48D2D805D0E94171A21E0FD |
:10350000C8016AE070E00E94B71B0894E11CF11C3E |
:1035100045E0E416F10471F08D2D9927AC01409F30 |
:10352000C001419F900D509F900D1124C81BD90BD5 |
:103530008B01D5CFDF91CF911F910F91FF90EF902D |
:10354000DF9008954F925F926F927F928F929F9239 |
:10355000AF92BF92CF92DF92EF92FF920F931F93A1 |
:10356000CF93DF937B018C01A12C2AECB22E2AE9A8 |
:10357000C22E2BE3D22E4424C0E0D0E0C801B70114 |
:10358000A60195010E94DE1B522E222341F4442005 |
:1035900031F481E0A816B104C104D10431F4852DC1 |
:1035A000805D0E94171A44244394C601B5012AE0A5 |
:1035B00030E040E050E00E94DE1B39014A012196D4 |
:1035C000CA30D10579F0652D772788279927A6017C |
:1035D00095010E94981BE61AF70A080B190B640163 |
:1035E0005301CCCFDF91CF911F910F91FF90EF90BE |
:1035F000DF90CF90BF90AF909F908F907F906F9013 |
:103600005F904F900895CF93DF93EC0103C0219614 |
:103610000E94171A88818823D1F7DF91CF910895EE |
:10362000CF93DF93EC01FE0121968491882319F05A |
:103630000E94171AF8CFDF91CF9108959FB7789421 |
:1036400007C083B7816083BF889583B78E7F83BFB0 |
:103650008091C00087FFF5CF9FBF8091C6008D305D |
:1036600009F48AE0992708951895FB01DC018D91F2 |
:10367000059080190110D9F3990B0895FB01DC0125 |
:103680004150504030F08D910590801919F4002080 |
:10369000B9F7881B990B0895FB01DC0102C001906A |
:1036A0000D9241505040D8F70895DC0101C06D9350 |
:1036B00041505040E0F70895FC018191861721F0B8 |
:1036C0008823D9F7992708953197CF010895FB01F1 |
:1036D000DC018D91019080190110D9F3990B0895A7 |
:1036E000FB01DC014150504030F08D910190801978 |
:1036F00019F40020B9F7881B990B0895FB01DC0130 |
:103700004150504048F001900D920020C9F701C08F |
:103710001D9241505040E0F70895FC0181E090E097 |
:103720000190061609F4CF010020D1F70197089502 |
:10373000629FD001739FF001829FE00DF11D649F95 |
:10374000E00DF11D929FF00D839FF00D749FF00D21 |
:10375000659FF00D9927729FB00DE11DF91F639FC2 |
:10376000B00DE11DF91FBD01CF0111240895AA1B61 |
:10377000BB1B51E107C0AA1FBB1FA617B70710F05C |
:10378000A61BB70B881F991F5A95A9F7809590958E |
:10379000BC01CD01089597FB092E07260AD077FDBD |
:1037A00004D0E5DF06D000201AF4709561957F4FB4 |
:1037B0000895F6F7909581959F4F0895A1E21A2EEE |
:1037C000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1FC5 |
:1037D000A217B307E407F50720F0A21BB30BE40B15 |
:1037E000F50B661F771F881F991F1A9469F760955C |
:1037F0007095809590959B01AC01BD01CF01089516 |
:02380000FFCFF8 |
:023802002F0095 |
:00000001FF |
/Designs/GPSRL02A/SW/logger/sd-reader.map |
---|
0,0 → 1,525 |
Archive member included because of file (symbol) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
fat16.o (__mulsi3) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
fat16.o (__udivmodhi4) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
fat16.o (__divmodhi4) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
fat16.o (__udivmodsi4) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o (exit) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
fat16.o (__do_copy_data) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
fat16.o (__do_clear_bss) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
main.o (strcmp_P) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
main.o (strncmp_P) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
fat16.o (memcpy) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
fat16.o (memset) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
fat16.o (strchr) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
fat16.o (strcmp) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
fat16.o (strncmp) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
fat16.o (strncpy) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
fat16.o (strrchr) |
Memory Configuration |
Name Origin Length Attributes |
text 0x00000000 0x00020000 xr |
data 0x00800060 0x0000ffa0 rw !x |
eeprom 0x00810000 0x00010000 rw !x |
fuse 0x00820000 0x00000400 rw !x |
lock 0x00830000 0x00000400 rw !x |
signature 0x00840000 0x00000400 rw !x |
*default* 0x00000000 0xffffffff |
Linker script and memory map |
Address of section .data set to 0x800100 |
LOAD /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
LOAD fat16.o |
LOAD main.o |
LOAD partition.o |
LOAD sd_raw.o |
LOAD uart.o |
LOAD /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a |
LOAD /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a |
LOAD /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a |
.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 0x00000000 0x3802 |
*(.vectors) |
.vectors 0x00000000 0x68 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
0x00000000 __vectors |
0x00000000 __vector_default |
*(.vectors) |
*(.progmem.gcc*) |
*(.progmem*) |
.progmem.data 0x00000068 0x1d2 main.o |
0x0000023a . = ALIGN (0x2) |
0x0000023a __trampolines_start = . |
*(.trampolines) |
.trampolines 0x0000023a 0x0 linker stubs |
*(.trampolines*) |
0x0000023a __trampolines_end = . |
*(.jumptables) |
*(.jumptables*) |
*(.lowtext) |
*(.lowtext*) |
0x0000023a __ctors_start = . |
*(.ctors) |
0x0000023a __ctors_end = . |
0x0000023a __dtors_start = . |
*(.dtors) |
0x0000023a __dtors_end = . |
SORT(*)(.ctors) |
SORT(*)(.dtors) |
*(.init0) |
.init0 0x0000023a 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
0x0000023a __init |
*(.init0) |
*(.init1) |
*(.init1) |
*(.init2) |
.init2 0x0000023a 0xc /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
*(.init2) |
*(.init3) |
*(.init3) |
*(.init4) |
.init4 0x00000246 0x16 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
0x00000246 __do_copy_data |
.init4 0x0000025c 0x10 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
0x0000025c __do_clear_bss |
*(.init4) |
*(.init5) |
*(.init5) |
*(.init6) |
*(.init6) |
*(.init7) |
*(.init7) |
*(.init8) |
*(.init8) |
*(.init9) |
.init9 0x0000026c 0x8 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
*(.init9) |
*(.text) |
.text 0x00000274 0x4 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
0x00000274 __vector_22 |
0x00000274 __vector_1 |
0x00000274 __vector_24 |
0x00000274 __vector_12 |
0x00000274 __bad_interrupt |
0x00000274 __vector_6 |
0x00000274 __vector_3 |
0x00000274 __vector_23 |
0x00000274 __vector_25 |
0x00000274 __vector_11 |
0x00000274 __vector_13 |
0x00000274 __vector_17 |
0x00000274 __vector_19 |
0x00000274 __vector_7 |
0x00000274 __vector_5 |
0x00000274 __vector_4 |
0x00000274 __vector_9 |
0x00000274 __vector_2 |
0x00000274 __vector_21 |
0x00000274 __vector_15 |
0x00000274 __vector_8 |
0x00000274 __vector_14 |
0x00000274 __vector_10 |
0x00000274 __vector_16 |
0x00000274 __vector_20 |
.text 0x00000278 0x2016 fat16.o |
0x00001898 fat16_resize_file |
0x00000278 fat16_close |
0x00000b24 fat16_reset_dir |
0x00000b3a fat16_delete_file |
0x00000c74 fat16_get_fs_free |
0x00000c3a fat16_get_file_modification_date |
0x00000de4 fat16_read_dir |
0x00000c3c fat16_get_file_modification_time |
0x00001ae0 fat16_seek_file |
0x00000c3e fat16_get_fs_size |
0x00000892 fat16_close_file |
0x00001eea fat16_open_file |
0x0000089e fat16_read_file |
0x00001048 fat16_open |
0x00001f52 fat16_create_file |
0x00002126 fat16_create_dir |
0x0000200a fat16_get_dir_entry_of_path |
0x00001b9c fat16_write_file |
0x00001e8a fat16_open_dir |
0x00000b18 fat16_close_dir |
.text 0x0000228e 0x7d8 main.o |
0x0000228e get_datetime |
0x0000256a main |
.text 0x00002a66 0x1c4 partition.o |
0x00002a66 partition_close |
0x00002a7a partition_open |
.text 0x00002c2a 0x7ec sd_raw.o |
0x00002c2a sd_raw_available |
0x00002f80 sd_raw_write_interval |
0x00002cec sd_raw_read |
0x00003120 sd_raw_init |
0x00003034 sd_raw_read_interval |
0x00003206 sd_raw_get_info |
0x00002ce6 sd_raw_sync |
0x00002c3c sd_raw_locked |
0x00002e1a sd_raw_write |
.text 0x00003416 0x254 uart.o |
0x00003544 uart_putdw_dec |
0x0000344c uart_putc_hex |
0x00003606 uart_puts |
0x00003620 uart_puts_p |
0x00003416 uart_init |
0x000034c4 uart_putw_dec |
0x0000363c uart_getc |
0x0000349e uart_putdw_hex |
0x0000342e uart_putc |
0x00003668 __vector_18 |
0x00003484 uart_putw_hex |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
.text 0x0000366a 0x12 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
0x0000366a strcmp_P |
.text 0x0000367c 0x1c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
0x0000367c strncmp_P |
.text 0x00003698 0x12 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
0x00003698 memcpy |
.text 0x000036aa 0xe /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
0x000036aa memset |
.text 0x000036b8 0x16 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
0x000036b8 strchr |
.text 0x000036ce 0x12 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
0x000036ce strcmp |
.text 0x000036e0 0x1c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
0x000036e0 strncmp |
.text 0x000036fc 0x1e /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
0x000036fc strncpy |
.text 0x0000371a 0x16 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
0x0000371a strrchr |
0x00003730 . = ALIGN (0x2) |
*(.text.*) |
.text.libgcc 0x00003730 0x3e /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
0x00003730 __mulsi3 |
.text.libgcc 0x0000376e 0x28 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
0x0000376e __udivmodhi4 |
.text.libgcc 0x00003796 0x26 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
0x00003796 __divmodhi4 |
0x00003796 _div |
.text.libgcc 0x000037bc 0x44 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
0x000037bc __udivmodsi4 |
.text.libgcc 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.text.libgcc 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.text.libgcc 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
0x00003800 . = ALIGN (0x2) |
*(.fini9) |
.fini9 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
0x00003800 exit |
0x00003800 _exit |
*(.fini9) |
*(.fini8) |
*(.fini8) |
*(.fini7) |
*(.fini7) |
*(.fini6) |
*(.fini6) |
*(.fini5) |
*(.fini5) |
*(.fini4) |
*(.fini4) |
*(.fini3) |
*(.fini3) |
*(.fini2) |
*(.fini2) |
*(.fini1) |
*(.fini1) |
*(.fini0) |
.fini0 0x00003800 0x2 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
*(.fini0) |
0x00003802 _etext = . |
.data 0x00800100 0x2 load address 0x00003802 |
0x00800100 PROVIDE (__data_start, .) |
*(.data) |
.data 0x00800100 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.data 0x00800100 0x0 fat16.o |
.data 0x00800100 0x2 main.o |
.data 0x00800102 0x0 partition.o |
.data 0x00800102 0x0 sd_raw.o |
.data 0x00800102 0x0 uart.o |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
*(.data*) |
*(.rodata) |
*(.rodata*) |
*(.gnu.linkonce.d*) |
0x00800102 . = ALIGN (0x2) |
0x00800102 _edata = . |
0x00800102 PROVIDE (__data_end, .) |
.bss 0x00800102 0x2c0 load address 0x00003804 |
0x00800102 PROVIDE (__bss_start, .) |
*(.bss) |
.bss 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.bss 0x00800102 0xab fat16.o |
.bss 0x008001ad 0x0 main.o |
.bss 0x008001ad 0x11 partition.o |
.bss 0x008001be 0x204 sd_raw.o |
.bss 0x008003c2 0x0 uart.o |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
*(.bss*) |
*(COMMON) |
0x008003c2 PROVIDE (__bss_end, .) |
0x00003802 __data_load_start = LOADADDR (.data) |
0x00003804 __data_load_end = (__data_load_start + SIZEOF (.data)) |
.noinit 0x008003c2 0x0 |
0x008003c2 PROVIDE (__noinit_start, .) |
*(.noinit*) |
0x008003c2 PROVIDE (__noinit_end, .) |
0x008003c2 _end = . |
0x008003c2 PROVIDE (__heap_start, .) |
.eeprom 0x00810000 0x0 |
*(.eeprom*) |
0x00810000 __eeprom_end = . |
.fuse |
*(.fuse) |
*(.lfuse) |
*(.hfuse) |
*(.efuse) |
.lock |
*(.lock*) |
.signature |
*(.signature*) |
.stab 0x00000000 0x6228 |
*(.stab) |
.stab 0x00000000 0x378 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.stab 0x00000378 0x2e14 fat16.o |
0x2e20 (size before relaxing) |
.stab 0x0000318c 0x1158 main.o |
0x135c (size before relaxing) |
.stab 0x000042e4 0x300 partition.o |
0x4ec (size before relaxing) |
.stab 0x000045e4 0xf24 sd_raw.o |
0x10d4 (size before relaxing) |
.stab 0x00005508 0x7a4 uart.o |
0x9d8 (size before relaxing) |
.stab 0x00005cac 0x84 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
0x90 (size before relaxing) |
.stab 0x00005d30 0xc0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
0xcc (size before relaxing) |
.stab 0x00005df0 0x84 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
0x90 (size before relaxing) |
.stab 0x00005e74 0x6c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
0x78 (size before relaxing) |
.stab 0x00005ee0 0x9c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
0xa8 (size before relaxing) |
.stab 0x00005f7c 0x84 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
0x90 (size before relaxing) |
.stab 0x00006000 0xc0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
0xcc (size before relaxing) |
.stab 0x000060c0 0xcc /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
0xd8 (size before relaxing) |
.stab 0x0000618c 0x9c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
0xa8 (size before relaxing) |
.stabstr 0x00000000 0x2db7 |
*(.stabstr) |
.stabstr 0x00000000 0x2db7 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.stab.excl |
*(.stab.excl) |
.stab.exclstr |
*(.stab.exclstr) |
.stab.index |
*(.stab.index) |
.stab.indexstr |
*(.stab.indexstr) |
.comment |
*(.comment) |
.debug |
*(.debug) |
.line |
*(.line) |
.debug_srcinfo |
*(.debug_srcinfo) |
.debug_sfnames |
*(.debug_sfnames) |
.debug_aranges |
*(.debug_aranges) |
.debug_pubnames |
*(.debug_pubnames) |
.debug_info |
*(.debug_info) |
*(.gnu.linkonce.wi.*) |
.debug_abbrev |
*(.debug_abbrev) |
.debug_line |
*(.debug_line) |
.debug_frame |
*(.debug_frame) |
.debug_str |
*(.debug_str) |
.debug_loc |
*(.debug_loc) |
.debug_macinfo |
*(.debug_macinfo) |
OUTPUT(sd-reader.out elf32-avr) |
LOAD linker stubs |
/Designs/GPSRL02A/SW/logger/sd-reader.out |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/GPSRL02A/SW/logger/sd-reader_config.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 |
/** |
* \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 fat16_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 |
/** |
* @} |
*/ |
#endif |
/Designs/GPSRL02A/SW/logger/sd_raw.c |
---|
0,0 → 1,912 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 <string.h> |
#include <avr/io.h> |
#include "sd_raw.h" |
/** |
* \addtogroup sd_raw MMC/SD card raw access |
* |
* This module implements read and write access to MMC and |
* SD cards. It serves as a low-level driver for the higher |
* level modules such as partition and file system access. |
* |
* @{ |
*/ |
/** |
* \file |
* MMC/SD 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 |
/* 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 |
/* CMD42: arg0[31:0]: stuff bits, response R1b */ |
#define CMD_LOCK_UNLOCK 0x2a |
/* CMD58: 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 |
#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 uint32_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 |
/* 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_r1(uint8_t command, uint32_t arg); |
static uint16_t sd_raw_send_command_r2(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 */ |
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_r1(CMD_GO_IDLE_STATE, 0); |
if(response == (1 << R1_IDLE_STATE)) |
break; |
if(i == 0x1ff) |
{ |
unselect_card(); |
return 0; |
} |
} |
/* wait for card to get ready */ |
for(uint16_t i = 0; ; ++i) |
{ |
response = sd_raw_send_command_r1(CMD_SEND_OP_COND, 0); |
if(!(response & (1 << R1_IDLE_STATE))) |
break; |
if(i == 0x7fff) |
{ |
unselect_card(); |
return 0; |
} |
} |
/* set block size to 512 bytes */ |
if(sd_raw_send_command_r1(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 = 0xffffffff; |
#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. |
* |
* \param[in] command The command to send. |
* \param[in] arg The argument for command. |
* \returns The command answer. |
*/ |
uint8_t sd_raw_send_command_r1(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); |
sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); |
/* receive response */ |
for(uint8_t i = 0; i < 10; ++i) |
{ |
response = sd_raw_rec_byte(); |
if(response != 0xff) |
break; |
} |
return response; |
} |
/** |
* \ingroup sd_raw |
* Send a command to the memory card which responses with a R2 response. |
* |
* \param[in] command The command to send. |
* \param[in] arg The argument for command. |
* \returns The command answer. |
*/ |
uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg) |
{ |
uint16_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); |
sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); |
/* receive response */ |
for(uint8_t i = 0; i < 10; ++i) |
{ |
response = sd_raw_rec_byte(); |
if(response != 0xff) |
break; |
} |
response <<= 8; |
response |= sd_raw_rec_byte(); |
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(uint32_t offset, uint8_t* buffer, uint16_t length) |
{ |
uint32_t block_address; |
uint16_t block_offset; |
uint16_t read_length; |
while(length > 0) |
{ |
/* determine byte count to read at once */ |
block_address = offset & 0xfffffe00; |
block_offset = offset & 0x01ff; |
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(!raw_block_written) |
{ |
if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) |
return 0; |
} |
#endif |
/* address card */ |
select_card(); |
/* send single block request */ |
if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address)) |
{ |
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(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_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_send_command_r1(CMD_READ_SINGLE_BLOCK, offset & 0xfffffe00)) |
{ |
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 & 0xfffffe00) + 512; |
} while(!finished); |
/* deaddress card */ |
unselect_card(); |
/* let card some time to finish */ |
sd_raw_rec_byte(); |
return 1; |
#endif |
} |
/** |
* \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(uint32_t offset, const uint8_t* buffer, uint16_t length) |
{ |
#if SD_RAW_WRITE_SUPPORT |
if(get_pin_locked()) |
return 0; |
uint32_t block_address; |
uint16_t block_offset; |
uint16_t write_length; |
while(length > 0) |
{ |
/* determine byte count to write at once */ |
block_address = offset & 0xfffffe00; |
block_offset = offset & 0x01ff; |
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(!raw_block_written) |
{ |
if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) |
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 |
} |
buffer += write_length; |
/* address card */ |
select_card(); |
/* send single block request */ |
if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address)) |
{ |
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(); |
length -= write_length; |
offset += write_length; |
#if SD_RAW_WRITE_BUFFERING |
raw_block_written = 1; |
#endif |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \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(uint32_t offset, uint8_t* buffer, uint16_t length, sd_raw_write_interval_handler_t callback, void* p) |
{ |
#if SD_RAW_WRITE_SUPPORT |
#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; |
#else |
return 0; |
#endif |
} |
/** |
* \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_SUPPORT |
#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; |
#endif |
return 1; |
#else |
return 0; |
#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_r1(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; |
uint16_t csd_c_size = 0; |
if(sd_raw_send_command_r1(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(); |
switch(i) |
{ |
case 5: |
csd_read_bl_len = b & 0x0f; |
break; |
case 6: |
csd_c_size = (uint16_t) (b & 0x03) << 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) << 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; |
case 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; |
break; |
} |
} |
unselect_card(); |
return 1; |
} |
/Designs/GPSRL02A/SW/logger/sd_raw.h |
---|
0,0 → 1,139 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 <stdint.h> |
#include "sd_raw_config.h" |
/** |
* \addtogroup sd_raw |
* |
* @{ |
*/ |
/** |
* \file |
* MMC/SD 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. |
*/ |
uint32_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, uint32_t offset, void* p); |
typedef uint16_t (*sd_raw_write_interval_handler_t)(uint8_t* buffer, uint32_t offset, void* p); |
uint8_t sd_raw_init(); |
uint8_t sd_raw_available(); |
uint8_t sd_raw_locked(); |
uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length); |
uint8_t sd_raw_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, sd_raw_read_interval_handler_t callback, void* p); |
uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length); |
uint8_t sd_raw_write_interval(uint32_t offset, uint8_t* buffer, uint16_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); |
/** |
* @} |
*/ |
#endif |
/Designs/GPSRL02A/SW/logger/sd_raw_config.h |
---|
0,0 → 1,109 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 |
/** |
* \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 0 |
/** |
* \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 |
/* defines for customisation of sd/mmc port access */ |
#if defined(__AVR_ATmega8__) || \ |
defined(__AVR_ATmega48__) || \ |
defined(__AVR_ATmega88__) || \ |
defined(__AVR_ATmega168__) |
#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 << PB2) |
#define unselect_card() PORTB |= (1 << PB2) |
#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 << PB4) |
#define unselect_card() PORTB |= (1 << PB4) |
#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 << PB0) |
#define unselect_card() PORTB |= (1 << PB0) |
#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 >> PC4) & 0x01) |
#define get_pin_locked() ((PINC >> PC5) & 0x01) |
/** |
* @} |
*/ |
/* 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 |
#endif |
/Designs/GPSRL02A/SW/logger/uart.c |
---|
0,0 → 1,198 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 <stdio.h> |
#include <avr/interrupt.h> |
#include <avr/io.h> |
#include <avr/pgmspace.h> |
#include <avr/sfr_defs.h> |
#include <avr/sleep.h> |
#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) |
/Designs/GPSRL02A/SW/logger/uart.h |
---|
0,0 → 1,33 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* 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 <stdint.h> |
#include <avr/pgmspace.h> |
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(); |
#endif |