diff --git a/Doc/Doxyfile b/Doc/Doxyfile new file mode 100644 index 00000000..9c0b3051 --- /dev/null +++ b/Doc/Doxyfile @@ -0,0 +1,1904 @@ +# Doxyfile 1.8.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed +# in front of the TAG it is preceding . +# 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 sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Chameleon-Mini" + +# 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 = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# 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 = Doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# 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. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +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 if your file system +# 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 = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# 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 = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# 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 makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE respectively 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_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# 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 namespaces 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 = NO + +# 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 = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = 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 = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = 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 section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro 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 macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# 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 + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = 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 , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 + +# The WARN_NO_PARAMDOC option can be enabled 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 = DoxygenPages ../Firmware/Chameleon-Mini + +# 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++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.txt *.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 = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# 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. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system 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 = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +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 or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +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 + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If CLANG_ASSISTED_PARSING is set to YES, then doxygen will use the clang parser +# for more acurate parsing at the cost of reduced performance. This can be +# particularly helpful with template rich C++ code for which doxygen's built-in +# parser lacks the necessairy type information. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified at INPUT and INCLUDE_PATH. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +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 left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# 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 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# 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. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +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, letter, legal and +# executive. If left blank a4 will be used. + +PAPER_TYPE = a4 + +# 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 = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + +# 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 = YES + +# 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 = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# 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 style sheet 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 related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK 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 docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# 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 +# pointed to by INCLUDE_PATH will be searched when 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 = + +# 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 that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these 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. For each +# tag file the location of the external documentation should be added. 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. 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 + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = 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 also works with HAVE_DOT disabled, but 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 + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# 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 the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH 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 svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# 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 MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/Doc/Doxygen/html/Page_14443AReader.html b/Doc/Doxygen/html/Page_14443AReader.html new file mode 100644 index 00000000..96804db1 --- /dev/null +++ b/Doc/Doxygen/html/Page_14443AReader.html @@ -0,0 +1,168 @@ + + + + + + +Chameleon-Mini: ISO14443A Reader Functionality + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
ISO14443A Reader Functionality
+
+
+

The ChameleonMini is able to act as an ISO 14443A reader. This page describes how to use this configuration (See Configurations) correctly.

+

Supported Commands

+

Using the ISO 14443A reader configuration enables the usage of some commands that are only available within this configuration.

+
Note
Technically, the SEND and SEND_RAW commands are also timeout commands, but they end successfully (either with NO DATA or the response) nearly immediately on every call.
+
+Each of the following commands returns INVALID COMMAND USAGE on a non-reader configuration.
+
Warning
The reader field is only turned on if this is necessary. Some commands deactivate the reader field after they are done, some do not deactivate the reader field after finishing. Please be aware, that the reader field takes a massive amount of energy and thus the voltage of the battery can drop to a critical level fastly. If not mentioned differently, all of the commands below deactivate the reader field after work.
+

SEND <BYTEVALUE>

+

There are two cases what is done, depending on the parameter:

    +
  1. If the parameter is one byte, no parity bits are added, since this must be a short frame command. In this case the seven least significant bits are sent.
  2. +
  3. If the parameter consists of more than one byte, parity bits are added and afterwards the whole sequence is sent.
  4. +
+

After sending, the ChameleonMini waits for an answer and returns either

    +
  • NO DATA if no answer could be detected or
  • +
  • the received data with removed parity bits, a 2-byte big-endian value indicating the bit count and either the string PARITY OK or PARITY ERR indicating whether the parity check failed or not.
  • +
+

In each case, the ChameleonMini code 101:OK WITH TEXT is returned.

+

Examples

+
    +
  • SEND 52 sends the WUPA command
  • +
  • SEND 9320 sends the ANTICOLLISION command
  • +
  • SEND AB2 returns INVALID PARAMETER since the parameter is no byte sequence
  • +
+
Warning
This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card.
+

SEND <2-BYTEVALUE> <BYTEVALUE>

+

Does the same like the command with only one parameter, but the first parameter indicates the to-be-sent bit count.

+
Warning
If the bit count parameter is neither 7 or a multiple of 8, no parity bits will be appended, but the remaining functionality is the exact same!
+

Examples

+
    +
  • SEND 0007 26 sends the REQA command
  • +
  • SEND 0010 9320 sends the ANTICOLLISION command
  • +
  • SEND 0012 13DE4A sends (on bit-processing-layer) SOC - 1100 1000 0111 1011 01 - EOC. The remaining bits are discarded. Note that the byte sequence is interpreted as little-endian and the bits are sent in reverse-order, just like defined in the ISO. Note also, that no parity bits are added, since 0x12 is neither 7 nor a multiple of 8.
  • +
  • SEND 0300 52 returns INVALID PARAMETER since the second parameter does not contain 768 bits.
  • +
+
Warning
This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card.
+

SEND_RAW <BYTEVALUE>

+

Sends the given byte sequence. The ChameleonMini assumes that the parameter has the parity bits already appended and thus calculates the bit count itself:

    +
  • If the parameter is one byte, the bit count is set to 7, since this seems to be a short frame.
  • +
  • If the parameter is n bytes long, the ChameleonMini sends floor(n * 16 / 9) bits.
  • +
+

After sending, the ChameleonMini waits for an answer and returns either

    +
  • NO DATA if no answer could be detected or
  • +
  • the raw received data (including parity bits) and a 2-byte big-endian value indicating the bit count
  • +
+

Examples

+
    +
  • SEND_RAW 52 sends the WUPA command.
  • +
  • SEND_RAW 934100 sends the ANTICOLLISION command as the bit sequence SOC - 1100 1001 1 0000 0100 0 - EOC is sent, which is the same as 0x9320 with parity bits.
  • +
  • SEND_RAW AB2 returns INVALID PARAMETER since the parameter is no byte sequence
  • +
+
Warning
This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card.
+

SEND <2-BYTEVALUE> <BYTEVALUE>

+

Does the same like the command with only one parameter, but the first parameter indicates the to-be-sent bit count.

+

Examples

+
    +
  • SEND_RAW 0007 26 sends the REQA command
  • +
  • SEND_RAW 0012 934100 sends the ANTICOLLISION command
  • +
  • SEND_RAW 0012 934100AB also sends the ANTICOLLISION command, since remaining bits are discarded
  • +
  • SEND_RAW 0300 52 returns INVALID PARAMETER since the second parameter does not contain 768 bits.
  • +
+
Warning
This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card.
+

GETUID

+

This is a timeout command. It tries to obtain the UID from a card that is in reader range and returns it.

+

If this command is called within the reader configuration, it either ends up returning 101:OK WITH TEXT and the UID or with a timeout (no matter if on setting/configuration change or on real timeout).

+

DUMP_MFU

+

This is a timeout command. It tries to read the whole content of a MiFare Ultralight card that is in reader range and returns the content.

+

If this command is called within the reader configuration, it either ends up returning 101:OK WITH TEXT and the card content in 4 lines (each line contains 16 bytes) or with a timeout (no matter if on setting/configuration change or on real timeout).

+

IDENTIFY

+

This is a timeout command. Tries to identify the type of a card in reader range and returns the type.

+

If this command is called within the reader configuration, it ends in one of three ways:

    +
  1. Return code 101:OK WITH TEXT, the card type and ATQA value, UID value and SAK value of the highest cascade level.
  2. +
  3. Return code 101:OK WITH TEXT, the information that this card type is unknown to the ChameleonMini ("Unknown card.") and ATQA value, UID value and SAK value of the highest cascade level.
  4. +
  5. Timeout (no matter if on setting/configuration change or on real timeout).
  6. +
+
+ + + + diff --git a/Doc/Doxygen/html/Page_Buttons.html b/Doc/Doxygen/html/Page_Buttons.html new file mode 100644 index 00000000..cc339234 --- /dev/null +++ b/Doc/Doxygen/html/Page_Buttons.html @@ -0,0 +1,133 @@ + + + + + + +Chameleon-Mini: Buttons + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
Buttons
+
+
+

For user interaction, ChameleonMini provides two configurable push buttons, i.e., LBUTTON on the left side and RBUTTON on the right side of Chameleon. Chameleon distinguishes between

    +
  1. a short (< ~1.28 s) press of the button and
  2. +
  3. a long (≥ ~1.28 s) press of the button.
  4. +
+

Thus, there are four different commands for configuring the buttons:

    +
  1. LBUTTON
  2. +
  3. RBUTTON
  4. +
  5. LBUTTON_LONG
  6. +
  7. RBUTTON_LONG
  8. +
+

Each of these commands can be used in the getting ("?"), setting ("=") and suggesting ("=?") version.

+

Supported Configurations

+

The following table describes all currently implemented options for the button configuration.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Configuration name Description
NONE No function, the button is disabled
UID_RANDOM Sets a random UID for the current card slot.
UID_LEFT_INCREMENT Increments the UID for the current card slot. The UID is interpreted as little-endian.
UID_RIGHT_INCREMENTIncrements the UID for the current card slot. The UID is interpreted as big-endian.
UID_LEFT_DECREMENT Decrements the UID for the current card slot. The UID is interpreted as little-endian.
UID_RIGHT_DECREMENTDecrements the UID for the current card slot. The UID is interpreted as big-endian.
CYCLE_SETTINGS Cycles through the slots/settings. If the configuration of a slot is set to NONE, this slot is skipped. When the last slot is reached, the next button press selects the first slot, again.
STORE_MEM Stores the current setting into the permanent Flash memory. Equivalent to the STORE command.
RECALL_MEM Recalls a setting from the permanent Flash memory. Equivalent to the RECALL command.
TOGGLE_FIELD Activates the reader field if it was deactivated, deactivates the reader field if it was activated.
STORE_LOG Writes the current log from SRAM to FRAM and clears the SRAM log. Equivalent to the STORE_LOG command.
+

Note the UID commands have no effect when the slot is configured as reader.

+
+ + + + diff --git a/Doc/Doxygen/html/Page_CommandLine.html b/Doc/Doxygen/html/Page_CommandLine.html new file mode 100644 index 00000000..98afee1d --- /dev/null +++ b/Doc/Doxygen/html/Page_CommandLine.html @@ -0,0 +1,292 @@ + + + + + + +Chameleon-Mini: The Chameleon Command Structure + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
The Chameleon Command Structure
+
+
+

After plugging in a USB cable, the ChameleonMini enumerates as a virtual serial interface. The settings of the serial interface, e.g. baudrate, stop and parity bits, are ignored by the Chameleon. For a high level of compatibility towards both humans and computers, Chameleon can be set up and controlled by means of a text-based command line interface, which can be accessed by using simple terminal software like hyper-terminal or teraterm. The command line is optimized to cooperate with script languages such as Python or TCL.

+

Chameleon Command Structure

+

For communicating with the Chameleon via USB, there exist four different syntax types:

    +
  • <COMMAND>=<VALUE> sets a parameter of the Chameleon ('set')
  • +
  • <COMMAND>=? lists all possible values for the parameter ('suggest')
  • +
  • <COMMAND>? returns the current value of a parameter ('get')
  • +
  • <COMMAND> Executes a function with an optional response ('execute')
  • +
+

For example, CONFIG=? lists the available types of virtualized cards and other options to configure a slot, while CONFIG=MF_CLASSIC_1K sets the current slot to Mifare Classic 1k emulation. In consequence, CONFIG? will return MF_CLASSIC_1K. Examples for commands executing a function are CLEAR, RESET or UPLOAD.

+

The responses of Chameleon indicate whether an action was successful or whether (and why) an error occurred. Examples: In case of an invalid command, the Chameleon replies with 200:UNKNOWN COMMAND. In case of a known command, but a wrong syntax, the Chameleon replies with 201:INVALID COMMAND USAGE.

+

Note: Each command has to be followed by a carriage return (CR, 0D hexadecimal). The backspace (08 hexadecimal) and escape (1B hexadecimal) keys are supported. All other control characters of the ASCII character set are ignored. The Chameleon commands are not case-sensitive. There is no echo of entered characters by the Chameleon, thus remember to switch on the 'local echo' in your terminal program.

+

Responses

+

Subsequent to any command sent, the Chameleon responds with a status number and a corresponding status message, separated by a colon and terminated with a carriage return and line feed (CR+LF, 0D+0A hexadecimal). Status numbers are of a three-digit decimal format with the first digit showing the severity of the answer. Status numbers beginning with a '1' denote an informational item and those beginning with a '2' denote an error.

+ + + + + + + + + + + + + + + + + + + + +
Response Description
100:OK The command has been successfully executed
101:OK WITH TEXT The command has been successfully executed and this response is appended with an additional line of information, terminated with CR+LF
110:WAITING FOR XMODEM The Chameleon is waiting for an XMODEM connection to be established
120:FALSE The request is answered with false
121:TRUE The request is answered with true
200:UNKNOWN COMMAND This command is unknown to the Chameleon
201:INVALID COMMAND USAGE This action is not supported by this command
202:INVALID PARAMETER The format or value of the given parameter value is invalid
203:TIMEOUT The timeout of the currently active command has expired
+

Chameleon Command Set

+

The current firmware supports the following global commands.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Command Description
CHARGING? Returns if the battery is currently being charged (TRUE) or not (FALSE)
HELP Returns a comma-separated list of all commands supported by the current firmware
RESET Reboots the Chameleon, i.e., power down and subsequent power-up. Note: A reset usually requires a new Terminal session.
RSSI? Returns the voltage measured at the antenna of the Chameleon, e.g., to detect the presence of an RF field or compare the field strength of different RFID readers.
SYSTICK? Returns the system tick value in ms. Note: An overflow occurs every 65,536 ms.
UPGRADE Sets the Chameleon into firmware upgrade mode (DFU). This command can be used instead of holding the RBUTTON while power-on to trigger the bootloader.
VERSION? Requests version information of the current firmware
Button CommandsSee also Buttons
RBUTTON=? Returns a comma-separated list of supported actions for pressing the right button shortly.
RBUTTON? Returns the currently set action for pressing the right button shortly. DEFAULT: SETTING_CHANGE
RBUTTON=<NAME> Sets the action for pressing the right button shortly.
LBUTTON=? Returns a comma-separated list of supported actions for pressing the left button shortly.
LBUTTON? Returns the currently set action for pressing the left button shortly. DEFAULT: RECALL_MEM
LBUTTON=<NAME> Sets the action for pressing the left button shortly.
RBUTTON_LONG=? Returns a comma-separated list of supported actions for pressing the right button a long time.
RBUTTON_LONG? Returns the currently set action for pressing the right button a long time. DEFAULT: SETTING_CHANGE
RBUTTON_LONG=<NAME> Sets the action for pressing the right button a long time.
LBUTTON_LONG=? Returns a comma-separated list of supported actions for pressing the left button a long time.
LBUTTON_LONG? Returns the currently set action for pressing the left button a long time. DEFAULT: RECALL_MEM
LBUTTON_LONG=<NAME> Sets the action for pressing the left button a long time.
LED Commands See also LED functionality
LEDGREEN=? Returns a comma-separated list of supported events for illuminating the green LED
LEDGREEN? Returns the currently set event for lighting the green LED
LEDGREEN=<NAME> Sets the event for which the green LED is lit. DEFAULT: POWERED
LEDRED=? Returns a comma-separated list of supported events for illuminating the red LED
LEDRED? Returns the currently set event for lighting the red LED
LEDRED=<NAME> Sets the event for which the green LED is lit. DEFAULT: SETTING_CHANGE
Log Commands See also Log functionality
LOGMODE=? Returns a comma-separated list of supported log modes
LOGMODE? Returns the current state of the log mode
LOGMODE=<NAME> Sets the current log mode. DEFAULT = OFF
LOGMEM? Returns the remaining free space for logging data to the SRAM (max. 2048 byte)
LOGDOWNLOAD Waits for an XModem connection and then downloads the binary log - including any log data in FRAM.
LOGCLEAR Clears the log memory (SRAM and FRAM)
LOGSTORE Writes the current log from SRAM to FRAM and clears the SRAM log.
Warning
If the FRAM is full, currently no error message is shown. If calling LOGMEM? after executing this command returns any other value than the maximum SRAM log size, there was not sufficient space in the FRAM and nothing has been done.
+
+

ChameleonMini provides eight 'slots' that can be configured to store different virtualized cards, or as active NFC reader, or as completely passive device for sniffing purposes. Each slot stores its configuration and, if applicable, card content. To select a particular slot, use the following command (or configure a button accordingly):

+ + + + + + +
Command Description
SETTING? Returns the currently activated slot
SETTING=<NUMBER> Sets the active slot, where <NUMBER> is a number between 1 and 8 (see Settings)
+

The following commands have an effect on the currently selected slot only:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Command Description
CONFIG=? Returns a comma-separated list of all supported configurations
CONFIG? Returns the configuration of the current slot
CONFIG=<NAME> Sets the configuration of the surrent slot to <NAME> (See Configurations)
UIDSIZE? Returns the UID size of the currently selected card type in Byte
UID? Returns the UID of a card in the current slot
UID=<UID> Sets a new UID, passed in hexadecimal notation.
READONLY? Returns the current state of the read-only mode
READONLY=[0;1] Activates (1) or deactivates (0) the read-only mode (Any writing to the memory is silently ignored)
MEMSIZE? Returns the memory size occupied by the current configuration in Byte
UPLOAD Waits for an XModem connection in order to upload a new virtualized card into the currently selected slot, with a size up to the current memory size
DOWNLOAD Waits for an XModem connection in order to download a virtualized card with the current memory size
CLEAR Clears the content of the current slot
STORE Stores the content of the current slot from FRAM into the Flash memory
RECALL Recalls/restores the content of the current slot from the Flash memory into the FRAM
TIMEOUT=? Returns the possible number range for timeouts. See also Timeout commands.
TIMEOUT=<NUMBER> Sets the timeout for the current slot in multiples of 128 ms. If set to zero, there is no timeout. See also Timeout commands.
TIMEOUT? Returns the timeout for the current slot. See also Timeout commands.
Reader CommandsUsing these commands only makes sense, if the slot is configured as reader. See also ISO14443A Reader Functionality
SEND <BYTEVALUE> Adds parity bits, sends the given byte string <BYTEVALUE>, and returns the cards answer
SEND_RAW <BYTEVALUE>Does NOT add parity bits, sends the given byte string <BYTEVALUE> and returns the cards answer
GETUID Obtains the UID of a card that is in the range of the antenna and returns it. This command is a Timeout command.
DUMP_MFU Reads the whole content of a Mifare Ultralight card that is in the range of the antenna and returns it. This command is a Timeout command.
IDENTIFY Identifies the type of a card in the range of the antenna and returns it.
THRESHOLD=? Returns the possible number range for the reader threshold.
THRESHOLD=<NUMBER> Globally sets the reader threshold. The <NUMBER> influences the reader function and range. Setting a wrong value may result in malfunctioning of the reader. DEFAULT: 400
THRESHOLD? Returns the current reader threshold.
FIELD? Returns whether (1) or not (0) the reader field is active.
FIELD=[0;1] Enables/disables the reader field.
+

Timeout Commands

+

Some commands start a process with an unpredictable termination time. In these cases, ChameleonMini waits with its response, until the result of this process is obtained. In order to prevent an infinite waiting time, an individual timeout value can be set for each slot, in multiples of roughly 100 ms up to 60,000 ms. When a timeout occurs or if a respective command is aborted by means of a setting change, the return code 203:TIMEOUT is sent and a command-specific shutdown function is called, which terminates the timeout process gracefully.

+
Warning
Any terminal input is completely ignored during the waiting period.
+
+When setting the timeout to zero, there is no timeout and thus a process may continue forever. Such a process can only be terminated by changing the setting, if a button is configured accordingly, or by restarting the ChameleonMini (power off, power on).
+

Accessing the command-line using a terminal software

+

In order to have quick access to the Chameleon's command-line without using any complicated software, we suggest using the TeraTerm terminal emulation software available for windows based operating systems.

+

Connecting and setting up

+

For establishing a connection to the Chameleon's command line, select File -> New Connection, choose the virtual serial port of the Chameleon and hit the "OK" button. TeraTerm now tries to open the serial port and should succeed without any error.

+

For easier use of the command-line using a terminal software the local-echo functionality should be activated, to be able to see what is typed into the chameleon. When using TeraTerm, this can be achieved by selecting Setup -> Terminal and check "Local Echo".

+

Uploading and Downloading dump files

+

In some configurations of the Chameleon, it is necessary to upload a card dump before it can be accessed by a reader. For doing so, the relatively simple and widely known XMODEM protocol is used.

+

To upload a dump file using TeraTerm, follow these steps.

    +
  1. Enter UPLOAD and wait for the 110:WAITING FOR XMODEM response
  2. +
  3. Select File -> Transfer -> XMODEM -> Send
  4. +
  5. In the dialog choose the binary dumpfile to be uploaded and make sure the option "Checksum" is checked in the lower left corner
  6. +
  7. Hitting the "Open" button will start the transfer. If no error is given to the user, the file has been uploaded sucessfully.
  8. +
+

To download the Chameleon's memory again, follow the instructions above except for using DOWNLOAD instead of UPLOAD and the Receive function of TeraTerm

+

Note that there is a 10 second timeout after entering UPLOAD respectively DOWNLOAD after which the standard command-line is activated again. So try again if the timeout is already over when the XMODEM transfer is about to start.

+
+ + + + diff --git a/Doc/Doxygen/html/Page_Configurations.html b/Doc/Doxygen/html/Page_Configurations.html new file mode 100644 index 00000000..a109330a --- /dev/null +++ b/Doc/Doxygen/html/Page_Configurations.html @@ -0,0 +1,129 @@ + + + + + + +Chameleon-Mini: Configurations + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
Configurations
+
+
+

Each setting of the Chameleon-Mini has an active configuration, which defines the behavior of the Chameleon-Mini. A detailed description of what defines a configuration can be found at ConfigurationType.

+

Supported Codecs

+

A Configuration basically is defined by the codec it uses and by the application functions that use this codec. Currently there are two different codecs implemented:

    +
  1. The ISO14443A codec for emulation.
  2. +
  3. The ISO14443A codec for the reader function.
  4. +
+

Supported Configurations

+

The following table shows which configurations are available currently.

+ + + + + + + + + + + + + + + + + + +
Configuration name Codec Description
NONE None No functionality, Chameleon-Mini does nothing, the current setting is skipped when cycling through the settings
MF_ULTRALIGHT ISO14443A emulation Emulates a MiFare Ultralight card
MF_CLASSIC_1K ISO14443A emulation Emulates a MiFare Classic 1k card
MF_CLASSIC_4K ISO14443A emulation Emulates a MiFare Classic 4k card
MF_CLASSIC_1K_7B ISO14443A emulation Emulates a MiFare Classic 1k card with 7-byte UID.
MF_CLASSIC_4K_7B ISO14443A emulation Emulates a MiFare Classic 4k card with 7-byte UID.
ISO14443A_SNIFF ISO14443A emulation Currently incomplete. Sniffs ISO14443A communication between a reader and a card.
ISO14443A_READER ISO14443A reader The Chameleon-Mini works as a reader and can process different procedures in order to obtain a cards UID etc.
+

Configuration Changing procedure

+

When the configuration is changed, no matter whether by command line or during a setting change, the following steps are done:

    +
  1. The codec deinitialization function of the currently active configuration is called.
  2. +
  3. Possibly pending timeout commands are aborted.
  4. +
  5. The configuration struct (ConfigurationType) for the currently active configuration is overwritten with the new configuration struct.
  6. +
  7. The codec initialization function of the new configuration is called.
  8. +
  9. The application initialization function of the new configuration is called.
  10. +
+
+ + + + diff --git a/Doc/Doxygen/html/Page_GettingStarted.html b/Doc/Doxygen/html/Page_GettingStarted.html new file mode 100644 index 00000000..7754ff93 --- /dev/null +++ b/Doc/Doxygen/html/Page_GettingStarted.html @@ -0,0 +1,117 @@ + + + + + + +Chameleon-Mini: Getting Started + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
Getting Started
+
+
+

Finally, you hold your brand-new ChameleonMini RevG in your hands! What to do now?! In the factory, a test firmware including a USB bootloader has been programmed into the microcontroller of the Chameleon. This page describes the next steps in order to upload the current firmware, as developed in this project, via the USB bootloader.

+

Step 1: Trigger the USB Bootloader

+

The bootloader can be executed in two different ways:

    +
  1. Make sure the Chameleon is switched off (power switch on the side is in the position OFF). Now, hold down the right button (RBUTTON) and keep it pressed while connecting the Chameleon to a PC via a USB cable.
  2. +
  3. OR: Plug your Chameleon via USB to a PC and use your favorite terminal application to connect with the test firmware of the ChameleonMini. Type upgrade and hit Enter.
  4. +
+

In either way, the ChameleonMini now jumps to the bootloader and waits patiently for a firmware upgrade.

+

Step 2: Upgrade the Firmware

+

Once the ChameleonMini is in the bootloader, you can flash a new firmware, i.e., the files Chameleon-Mini.hex and the Chameleon-Mini.hex, into the microcontroller. The source code directory contains these files precompiled but you can of course also compile the code yourself. Create a new folder and copy the two files into it. The following depends on your operating system:

+

Upgrade Procedure for Linux Users

+

In order to upgrade the firmware under Linux you first have to install avrdude, e.g. under Ubuntu with the command sudo apt-get install avra avrdude. Then change to the directory where you have saved the hex and eep files and run sudo avrdude -c flip2 -p ATXMega128A4U -B 60 -P usb -U application:w:Chameleon-Mini.hex:i -U eeprom:w:Chameleon-Mini.eep:i.

+

You also can use sudo make program in the source code directory, which basically does the same.

+

After running this command you need to restart your Chameleon, e.g. by reattaching the Chameleon to the PC.

+

Upgrade Procedure for Windows Users

+

For upgrading the firmware under Windows please

    +
  1. download https://sourceforge.net/projects/dfu-programmer/files/dfu-programmer/0.7.2/dfu-programmer-win-0.7.2.zip/download and extract to an arbitrary directory. Make sure to use the DFU programmer Version 0.7.2!
  2. +
  3. Go to the extraction directory and then open the folder dfu-prog-usb-1.2.2. Install the atmel_usb_dfu.inf driver (right click -> install).
  4. +
  5. Copy dfu-programmer.exe from the extraction directory to the directory where you have saved the hex and eep files.
  6. +
  7. Save the ChameleonFirmwareUpgrade.bat in the same directory as the hex and eep files.
  8. +
  9. Run the ChameleonFirmwareUpgrade.bat as Administrator (right click -> run as Administrator) and wait for the firmware upgrade to terminate. Upon success, the green LED of the ChameleonMini should light up.
  10. +
+

Finally, install the driver for Chameleon: Download both ChameleonDriver.inf and ChameleonDriver.cat from the Drivers directory and install the INF file (right click -> install).

+

Now, Chameleon should appear in the Windows device manager and you should be able to open a terminal program such as TeraTerm and connect to the Chameleon-Mini via the COM port shown in the device manager. Further information about how to "talk" to the Chameleon can be found here: The Chameleon Command Structure.

+
+ + + + diff --git a/Doc/Doxygen/html/Page_LED.html b/Doc/Doxygen/html/Page_LED.html new file mode 100644 index 00000000..2b741ddd --- /dev/null +++ b/Doc/Doxygen/html/Page_LED.html @@ -0,0 +1,117 @@ + + + + + + +Chameleon-Mini: LED functionality + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ +
+
+
+
LED functionality
+
+
+

The Chameleon-Mini has two fully configurable LEDs: one red LED and one green LED. The configuration is done with the commands LEDRED and LEDGREEN, which both can be called as the getting ("?"), setting ("=") and suggesting ("=?") version.

+

The following table shows which LED functions are currently available.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Function name Description
NONE No function, the LED is deactivated.
POWERED The LED lights up if the Chameleon-Mini is powered, regardless whether powered by USB or by battery.
TERMINAL_CONN The LED is turned on when the Chameleon-Mini is connected via USB and is turned off when no USB connection is established.
TERMINAL_RXTX The according LED blinks shortly when sending or receiving data via the USB interface.
SETTING_CHANGE The LED blinks one time if the new setting is setting 1, two times for setting 2, ..., eight times for setting 8.
MEMORY_STORED The LED flashes everytime when a setting is stored to the permanent flash. This is currently the case when calling the command STORE, the button event STORE_MEM occurs or the setting is changed.
MEMORY_CHANGED The LED turns on when the FRAM is changed and is turned off when the currently active setting is written to the permanent flash. Thus, this function indicates when the current setting is changed.
CODEC_RX The LED flashes when the currently active codec (e.g. ISO14443A emulation) receives data. Note that this is implemented on codec layer and the flashing is triggered before the received data are interpreted by the application.
CODEC_TX The LED flashes when the currently active codec sends data. This function also is implemented on codec layer.
FIELD_DETECTED The LED is turned on if and only if a reader field is detected, which is recognized by the RSSI module (when the RSSI value hits a hardcoded threshold, it is assumed that there is a reader field). It is irrelevant whether the field comes from another reader or from the Chameleon-Mini itself.
LOGMEM_FULL Lights up the LED, if the SRAM log memory is full.
+
+ + + + diff --git a/Doc/Doxygen/html/Page_LEDs.html b/Doc/Doxygen/html/Page_LEDs.html new file mode 100644 index 00000000..80f9ca37 --- /dev/null +++ b/Doc/Doxygen/html/Page_LEDs.html @@ -0,0 +1,121 @@ + + + + + + +Chameleon-Mini: LED functionality + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
LED functionality
+
+
+

For giving user feedback, ChameleonMini provides two LEDs that can be configured to indicate various conditions, events, or internal state changes of ChameleonMini: a red LED and a green LED. Their individual configuration is controlled with the commands LEDRED and LEDGREEN, which can be called in the getting ("?"), setting ("=") and suggesting ("=?") variants.

+

The following table shows the currently supported LED functions.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Condition/Event Description
NONE Nothing happens, the LED remains dark.
POWERED The LED lights up, if the ChameleonMini is powered by USB or by battery.
TERMINAL_CONN The LED is turned on when the ChameleonMini is connected via USB and is turned off when no USB connection is established.
TERMINAL_RXTX The LED blinks shortly when sending or receiving data via the USB interface.
SETTING_CHANGE The LED blinks one time if the new setting is setting 1, two times for setting 2, ..., eight times for setting 8.
MEMORY_STORED The LED flashes everytime when a setting is stored to the permanent flash. This is currently the case when calling the command STORE, the button event STORE_MEM occurs or the setting is changed.
MEMORY_CHANGED The LED turns on when the content of the FRAM has been modified and is turned off when the currently active setting is written to the permanent Flash memory. Thus, this function indicates when the current content has been changed.
CODEC_RX The LED flashes when the currently active codec (e.g. ISO14443A emulation) receives data via the RFID interface. Note that this is implemented on the codec layer and the flashing is triggered before the received data is interpreted by the application.
CODEC_TX The LED flashes when the currently active codec sends data via the RFID interface. This function is also implemented on the codec layer.
FIELD_DETECTED The LED is turned on, if a reader field is detected via the RSSI module (when the RSSI value hits a hardcoded threshold, it is assumed that there is a reader field). It is irrelevant whether the field comes from another reader or from the ChameleonMini itself.
LOGMEM_FULL Lights up the LED, if the SRAM log memory is full.
+
+ + + + diff --git a/Doc/Doxygen/html/Page_Log.html b/Doc/Doxygen/html/Page_Log.html new file mode 100644 index 00000000..44e4eef4 --- /dev/null +++ b/Doc/Doxygen/html/Page_Log.html @@ -0,0 +1,120 @@ + + + + + + +Chameleon-Mini: Log functionality + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
Log functionality
+
+
+

The ChameleonMini provides a configurable log functionality. This page describes how to use it.

+

Log Entry Format

+

The log entries use a TLV (Type Length Value)-like format:

+ + + + + + + + + + +
Name Size Description
Entry type 1 byte See LogEntryEnum
Data length 1 byte This is the length of the appended data.
Timestamp 2 bytes This is the current systick value.
Data Data length bytes It is also possible that no data is appended, then the Data length field is zero.
+

Entry Types

+

See LogEntryEnum.

+

Log Modes

+

Currently there exist three log modes:

    +
  • OFF, which means that nothing is logged.
  • +
  • LIVE, which means that log events are written directly to the terminal (untested).
  • +
  • MEMORY, where the log events are written to SRAM.
  • +
+
Note
If there is not enough log memory, the log mode is automatically set to OFF.
+
Warning
Since the MEMORY log mode writes to SRAM, the log memory is cleared by power off or restarting the Chameleon.
+

Related Commands, Button event and LED functions

+

There are various commands to configure the log functionality. See Page Command Line. Equivalently to the LOGSTORE command, the buttons are configurable to STORE_LOG, which does the same. Also, there exists a LOGMEM_FULL function for the LEDs, which lights up the LED if the SRAM log memory is full. See also the Pages Buttons and LED functionality. The 'chamlog' Python script in the project (Software folder) automatizes the process of downloading the binary log data, e.g., sending the following command under Windows with a ChameleonMini connected on port COM6 results in downloading the binary log file, clearing the log memory, and setting the log mode to MEMORY: chamlog -p COM6 -c -m MEMORY -v. Repeatedly executing this command always outputs the recently logged commands in user-readable form. Make sure that no other program, e.g., terminal software, is blocking the serial port.

+
+ + + + diff --git a/Doc/Doxygen/html/Page_Settings.html b/Doc/Doxygen/html/Page_Settings.html new file mode 100644 index 00000000..5520e8c6 --- /dev/null +++ b/Doc/Doxygen/html/Page_Settings.html @@ -0,0 +1,108 @@ + + + + + + +Chameleon-Mini: Settings + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
Settings
+
+
+

The ChameleonMini can act in different ways, the behavior is defined by configurations. But also, the ChameleonMini has slots, which are a layer above the configurations. With the slots, it is possible to switch between different configurations and respective content, e.g., a card dump together with the configuration as Mifare Classic 1k card.

+

Properties

+

A slot is defined by settings: SettingsEntryType.

+

Slot Changing Procedure

+

When the current slot is changed, the following procedure is applied:

    +
  1. Break potentially pending timeout commands.
  2. +
  3. Store the memory of the setting to the Flash.
  4. +
  5. Set the slot number of the currently active slot to the number of the new slot.
  6. +
  7. Set the slot pointer of the currently active slot to the pointer of the new slot.
  8. +
  9. Since the slot also contains the configuration, apply the configuration changing procedure with the new configuration for the new slot.
  10. +
  11. Log the slot change.
  12. +
  13. Recall the new content of the slot from the permanent Flash.
  14. +
  15. Signalize the slot change with an LED, if an LED is configured to SETTING_CHANGE.
  16. +
+
+ + + + diff --git a/Doc/Doxygen/html/Page_UploadingDownloading.html b/Doc/Doxygen/html/Page_UploadingDownloading.html new file mode 100644 index 00000000..93d9e429 --- /dev/null +++ b/Doc/Doxygen/html/Page_UploadingDownloading.html @@ -0,0 +1,99 @@ + + + + + + +Chameleon-Mini: Uploading and Downloading Memory dumps + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+
+ + +
+ +
+ + +
+
+
+
Uploading and Downloading Memory dumps
+
+
+

In order to be able to emulate different cards, one can upload or download the content used for the emulation.

+

The layout of the memory dump depends on the chosen configuration and is usually the same as the memory layout of the currently chosen card emulation. The size of the memory dump also depends on the currently chosen configuration and can be requested with a specific command on the command-line.

+

In order to upload or download a memory dump, the user has to send the corresponding command on the command-line first and the Chameleon responds with a status message indicating that it is waiting for an X-MODEM connection. Depending on whether upload or download is chosen, the Chameleon then waits for 10 seconds to initiate an X-MODEM receive or send connection.

+

When waiting for a receiving X-MODEM connection, the X-MODEM NAK byte is sent upto 20 times with a delay of 500ms in order to establish a standard 128 byte frame-size X-MODEM connection with the simple checksum scheme. Within this time, the user has to get his X-MODEM client ready and choose the binary file to be uploaded into the memory.

+

In case of waiting for an X-MODEM send connection to establish, a wait time of 10 seconds is performed to receive the X-MODEM NAK byte. Within this time, the user has to start the X-MODEM receiver and set it to the standard 128 byte frame using the simple checksum scheme in order to receive the binary memory dump.

+
+ + + + diff --git a/Doc/Doxygen/html/_antenna_level_8h_source.html b/Doc/Doxygen/html/_antenna_level_8h_source.html new file mode 100644 index 00000000..639b4ee5 --- /dev/null +++ b/Doc/Doxygen/html/_antenna_level_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: AntennaLevel.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
AntennaLevel.h
+
+
+
1 /*
2  * AntennaLevel.h
3  *
4  * Created on: 24.11.2013
5  * Author: skuser
6  */
7 
8 #ifndef ANTENNALEVEL_H_
9 #define ANTENNALEVEL_H_
10 
11 #include "Common.h"
12 
13 #define ANTENNA_LEVEL_R1 47E3
14 #define ANTENNA_LEVEL_R2 1E3
15 #define ANTENNA_LEVEL_VREF 1.0
16 #define ANTENNA_LEVEL_RES 4096
17 #define ANTENNA_LEVEL_OFFSET 190 /* LSB */
18 
19 #define ANTENNA_LEVEL_MILLIVOLT 1E3
20 #define ANTENNA_LEVEL_FACTOR (ANTENNA_LEVEL_VREF * (ANTENNA_LEVEL_R1 + ANTENNA_LEVEL_R2) / (ANTENNA_LEVEL_RES * ANTENNA_LEVEL_R2) )
21 #define ANTENNA_LEVEL_SCALE ((uint32_t) 1<<16)
22 #define ANTENNA_LEVEL_NUMERATOR ((uint32_t) (ANTENNA_LEVEL_MILLIVOLT * ANTENNA_LEVEL_FACTOR * ANTENNA_LEVEL_SCALE + .5))
23 #define ANTENNA_LEVEL_DENOMINATOR (ANTENNA_LEVEL_SCALE)
24 
25 static inline
26 void AntennaLevelInit(void)
27 {
28  ADCA.CTRLA = ADC_ENABLE_bm;
29  ADCA.CTRLB = ADC_RESOLUTION_12BIT_gc;
30  ADCA.REFCTRL = ADC_REFSEL_INT1V_gc | ADC_BANDGAP_bm;
31  ADCA.PRESCALER = ADC_PRESCALER_DIV32_gc;
32  ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc;
33  ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN1_gc;
34 
35 }
36 
37 static inline
38 uint16_t AntennaLevelGet(void)
39 {
40  ADCA.CH0.CTRL |= ADC_CH_START_bm;
41  while( !(ADCA.CH0.INTFLAGS & ADC_CH_CHIF_bm) );
42 
43  ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm;
44 
45  int16_t Result = ADCA.CH0RES - ANTENNA_LEVEL_OFFSET;
46  if (Result < 0) Result = 0;
47 
48  return (uint16_t) (((uint32_t) Result * ANTENNA_LEVEL_NUMERATOR) / ANTENNA_LEVEL_DENOMINATOR);
49 }
50 
51 void AntennaLevelTick(void);
52 void AntennaLevelResetMaxRssi(void);
53 
54 #endif /* ANTENNALEVEL_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_application_8h_source.html b/Doc/Doxygen/html/_application_8h_source.html new file mode 100644 index 00000000..984ad33f --- /dev/null +++ b/Doc/Doxygen/html/_application_8h_source.html @@ -0,0 +1,109 @@ + + + + + + +Chameleon-Mini: Application.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Application.h
+
+
+
1 /*
2  * Application.h
3  *
4  * Created on: 18.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef APPLICATION_H_
9 #define APPLICATION_H_
10 
11 #include "../Common.h"
12 #include "../Configuration.h"
13 #include "../Log.h"
14 
15 /* Applications */
16 #include "MifareUltralight.h"
17 #include "MifareClassic.h"
18 #include "Reader14443A.h"
19 
20 /* Function wrappers */
21 INLINE void ApplicationInit(void) {
22  ActiveConfiguration.ApplicationInitFunc();
23 }
24 
25 INLINE void ApplicationTask(void) {
26  ActiveConfiguration.ApplicationTaskFunc();
27 }
28 
29 INLINE void ApplicationTick(void) {
30  ActiveConfiguration.ApplicationTickFunc();
31 }
32 
33 INLINE uint16_t ApplicationProcess(uint8_t* ByteBuffer, uint16_t ByteCount) {
34  return ActiveConfiguration.ApplicationProcessFunc(ByteBuffer, ByteCount);
35 }
36 
37 INLINE void ApplicationReset(void) {
38  ActiveConfiguration.ApplicationResetFunc();
39  //LogEntry(LOG_INFO_RESET_APP, NULL, 0);
40 }
41 
42 INLINE void ApplicationGetUid(ConfigurationUidType Uid) {
43  ActiveConfiguration.ApplicationGetUidFunc(Uid);
44 }
45 
46 INLINE void ApplicationSetUid(ConfigurationUidType Uid) {
47  ActiveConfiguration.ApplicationSetUidFunc(Uid);
48  LogEntry(LOG_INFO_UID_SET, Uid, ActiveConfiguration.UidSize);
49 }
50 
51 #endif /* APPLICATION_H_ */
void(* ApplicationSetUidFunc)(ConfigurationUidType Uid)
Definition: Configuration.h:103
+
uint16_t(* ApplicationProcessFunc)(uint8_t *ByteBuffer, uint16_t BitCount)
Definition: Configuration.h:93
+
void(* ApplicationResetFunc)(void)
Definition: Configuration.h:77
+
UID change.
Definition: Log.h:16
+
void(* ApplicationGetUidFunc)(ConfigurationUidType Uid)
Definition: Configuration.h:98
+
void(* ApplicationTickFunc)(void)
Definition: Configuration.h:81
+
void(* ApplicationTaskFunc)(void)
Definition: Configuration.h:79
+
void(* ApplicationInitFunc)(void)
Definition: Configuration.h:75
+
uint8_t UidSize
Definition: Configuration.h:120
+
+ + + + diff --git a/Doc/Doxygen/html/_battery_8h_source.html b/Doc/Doxygen/html/_battery_8h_source.html new file mode 100644 index 00000000..7944b5e9 --- /dev/null +++ b/Doc/Doxygen/html/_battery_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Battery.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Battery.h
+
+
+
1 /*
2  * Battery.h
3  *
4  * Created on: 20.08.2014
5  * Author: sk
6  */
7 
8 #ifndef BATTERY_H_
9 #define BATTERY_H_
10 
11 #include "Common.h"
12 
13 #define BATTERY_PORT PORTD
14 #define BATTERY_STAT_PIN PIN0_bm
15 #define BATTERY_STAT_PINCTRL PIN0CTRL
16 #define BATTERY_PORT_MASK (BATTERY_STAT_PIN)
17 
18 INLINE void BatteryInit(void) {
19  BATTERY_PORT.DIRCLR = BATTERY_PORT_MASK;
20  BATTERY_PORT.BATTERY_STAT_PINCTRL = PORT_OPC_PULLUP_gc;
21 }
22 
23 INLINE bool BatteryIsCharging(void) {
24  if (!(BATTERY_PORT.IN & BATTERY_STAT_PIN)) {
25  return true;
26  } else {
27  return false;
28  }
29 }
30 
31 #endif /* BATTERY_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_button_8h_source.html b/Doc/Doxygen/html/_button_8h_source.html new file mode 100644 index 00000000..5a246c09 --- /dev/null +++ b/Doc/Doxygen/html/_button_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Button.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Button.h
+
+
+
1 /*
2  * Button.h
3  *
4  * Created on: 13.05.2013
5  * Author: skuser
6  */
7 
8 #ifndef BUTTON_H_
9 #define BUTTON_H_
10 
11 #include "Common.h"
12 
13 typedef enum {
14  BUTTON_R_PRESS_SHORT = 0,
15  BUTTON_R_PRESS_LONG,
16  BUTTON_L_PRESS_SHORT,
17  BUTTON_L_PRESS_LONG,
18 
19  /* Must be last element */
20  BUTTON_TYPE_COUNT
21 } ButtonTypeEnum;
22 
23 typedef enum {
24  BUTTON_ACTION_NONE,
25  BUTTON_ACTION_UID_RANDOM,
26  BUTTON_ACTION_UID_LEFT_INCREMENT,
27  BUTTON_ACTION_UID_RIGHT_INCREMENT,
28  BUTTON_ACTION_UID_LEFT_DECREMENT,
29  BUTTON_ACTION_UID_RIGHT_DECREMENT,
30  BUTTON_ACTION_CYCLE_SETTINGS,
31  BUTTON_ACTION_STORE_MEM,
32  BUTTON_ACTION_RECALL_MEM,
33  BUTTON_ACTION_TOGGLE_FIELD,
34  BUTTON_ACTION_STORE_LOG,
35 
36  /* This has to be last element */
37  BUTTON_ACTION_COUNT
38 } ButtonActionEnum;
39 
40 void ButtonInit(void);
41 void ButtonTick(void);
42 
43 void ButtonGetActionList(char* List, uint16_t BufferSize);
44 void ButtonSetActionById(ButtonTypeEnum Type, ButtonActionEnum Action);
45 void ButtonGetActionByName(ButtonTypeEnum Type, char* Action, uint16_t BufferSize);
46 bool ButtonSetActionByName(ButtonTypeEnum Type, const char* Action);
47 
48 #endif /* BUTTON_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_buttons_8txt.html b/Doc/Doxygen/html/_buttons_8txt.html new file mode 100644 index 00000000..49be2b27 --- /dev/null +++ b/Doc/Doxygen/html/_buttons_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: Buttons.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
Buttons.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_chameleon-_mini_8h_source.html b/Doc/Doxygen/html/_chameleon-_mini_8h_source.html new file mode 100644 index 00000000..08b031b0 --- /dev/null +++ b/Doc/Doxygen/html/_chameleon-_mini_8h_source.html @@ -0,0 +1,103 @@ + + + + + + +Chameleon-Mini: Chameleon-Mini.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Chameleon-Mini.h
+
+
+
1 #ifndef CHAMELEON_MINI_H
2 #define CHAMELEON_MINI_H
3 
4 #include <avr/io.h>
5 #include <avr/wdt.h>
6 #include <avr/interrupt.h>
7 #include <avr/power.h>
8 
9 #include "System.h"
10 #include "Memory.h"
11 #include "LED.h"
12 #include "LEDHook.h"
13 #include "Terminal/Terminal.h"
14 #include "Codec/Codec.h"
15 #include "Application/Application.h"
16 #include "Configuration.h"
17 #include "Random.h"
18 #include "Button.h"
19 #include "Log.h"
20 #include "AntennaLevel.h"
21 #include "Settings.h"
22 
23 #define CHAMELEON_MINI_VERSION_STRING BUILD_DATE
24 
25 #endif //CHAMELEON_MINI_H
26 
+ + +
+ + + + diff --git a/Doc/Doxygen/html/_codec_8h_source.html b/Doc/Doxygen/html/_codec_8h_source.html new file mode 100644 index 00000000..bb9a36a0 --- /dev/null +++ b/Doc/Doxygen/html/_codec_8h_source.html @@ -0,0 +1,103 @@ + + + + + + +Chameleon-Mini: Codec.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Codec.h
+
+
+
1 /*
2  * CODEC.h
3  *
4  * Created on: 18.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef CODEC_H_
9 #define CODEC_H_
10 
11 #include <avr/io.h>
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include "../Common.h"
15 #include "../Configuration.h"
16 
17 #include "ISO14443-2A.h"
18 #include "Reader14443-2A.h"
19 
20 /* Timing definitions for ISO14443A */
21 #define ISO14443A_SUBCARRIER_DIVIDER 16
22 #define ISO14443A_BIT_GRID_CYCLES 128
23 #define ISO14443A_BIT_RATE_CYCLES 128
24 #define ISO14443A_FRAME_DELAY_PREV1 1236
25 #define ISO14443A_FRAME_DELAY_PREV0 1172
26 #define ISO14443A_RX_PENDING_TIMEOUT 1 // ms
27 
28 /* Peripheral definitions */
29 #define CODEC_DEMOD_POWER_PORT PORTB
30 #define CODEC_DEMOD_POWER_MASK PIN0_bm
31 #define CODEC_DEMOD_IN_PORT PORTB
32 #define CODEC_DEMOD_IN_MASK (CODEC_DEMOD_IN_MASK0 | CODEC_DEMOD_IN_MASK1)
33 #define CODEC_DEMOD_IN_MASK0 PIN1_bm
34 #define CODEC_DEMOD_IN_MASK1 PIN2_bm
35 #define CODEC_DEMOD_IN_PINCTRL0 PIN1CTRL
36 #define CODEC_DEMOD_IN_PINCTRL1 PIN2CTRL
37 #define CODEC_DEMOD_IN_EVMUX0 EVSYS_CHMUX_PORTB_PIN1_gc
38 #define CODEC_DEMOD_IN_EVMUX1 EVSYS_CHMUX_PORTB_PIN2_gc
39 #define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect
40 #define CODEC_LOADMOD_PORT PORTC
41 #define CODEC_LOADMOD_MASK PIN6_bm
42 #define CODEC_CARRIER_IN_PORT PORTC
43 #define CODEC_CARRIER_IN_MASK PIN2_bm
44 #define CODEC_CARRIER_IN_PINCTRL PIN2CTRL
45 #define CODEC_CARRIER_IN_EVMUX EVSYS_CHMUX_PORTC_PIN2_gc
46 #define CODEC_CARRIER_IN_DIV 2 /* external clock division factor */
47 #define CODEC_SUBCARRIER_PORT PORTC
48 #define CODEC_SUBCARRIER_MASK_PSK PIN4_bm
49 #define CODEC_SUBCARRIER_MASK_OOK PIN5_bm
50 #define CODEC_SUBCARRIER_MASK (CODEC_SUBCARRIER_MASK_PSK | CODEC_SUBCARRIER_MASK_OOK)
51 #define CODEC_SUBCARRIER_TIMER TCC1
52 #define CODEC_SUBCARRIER_CC_PSK CCA
53 #define CODEC_SUBCARRIER_CC_OOK CCB
54 #define CODEC_SUBCARRIER_CCEN_PSK TC1_CCAEN_bm
55 #define CODEC_SUBCARRIER_CCEN_OOK TC1_CCBEN_bm
56 #define CODEC_TIMER_SAMPLING TCD0
57 #define CODEC_TIMER_SAMPLING_CCA_VECT TCD0_CCA_vect
58 #define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect
59 #define CODEC_TIMER_LOADMOD TCE0
60 #define CODEC_TIMER_LOADMOD_OVF_VECT TCE0_OVF_vect
61 #define CODEC_TIMER_LOADMOD_CCA_VECT TCE0_CCA_vect
62 #define CODEC_TIMER_LOADMOD_CCB_VECT TCE0_CCB_vect
63 #define CODEC_TIMER_LOADMOD_CCC_VECT TCE0_CCC_vect
64 #define CODEC_TIMER_MODSTART_EVSEL TC_EVSEL_CH0_gc
65 #define CODEC_TIMER_MODEND_EVSEL TC_EVSEL_CH1_gc
66 #define CODEC_TIMER_CARRIER_CLKSEL TC_CLKSEL_EVCH6_gc
67 #define CODEC_READER_TIMER TCC0
68 #define CODEC_READER_PORT PORTC
69 #define CODEC_READER_MASK_LEFT PIN0_bm
70 #define CODEC_READER_MASK_RIGHT PIN1_bm
71 #define CODEC_READER_MASK (CODEC_READER_MASK_LEFT | CODEC_READER_MASK_RIGHT)
72 #define CODEC_READER_PINCTRL_LEFT PIN0CTRL
73 #define CODEC_READER_PINCTRL_RIGHT PIN1CTRL
74 #define CODEC_AC_DEMOD_SETTINGS AC_HSMODE_bm | AC_HYSMODE_NO_gc
75 #define CODEC_MAXIMUM_THRESHOLD 0xFFF // the maximum voltage can be calculated with ch0data * Vref / 0xFFF
76 #define CODEC_TIMER_TIMESTAMPS TCD1
77 #define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect
78 
79 #define CODEC_BUFFER_SIZE 256
80 
81 #define CODEC_CARRIER_FREQ 13560000
82 
83 #define Codec8Reg0 GPIOR0
84 #define Codec8Reg1 GPIOR1
85 #define Codec8Reg2 GPIOR2
86 #define Codec8Reg3 GPIOR3
87 #define CodecCount16Register1 (*((volatile uint16_t*) &GPIOR4)) /* GPIOR4 & GPIOR5 */
88 #define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR4 & GPIOR5 */
89 #define CodecPtrRegister1 (*((volatile uint8_t**) &GPIOR8))
90 #define CodecPtrRegister2 (*((volatile uint8_t**) &GPIORA))
91 
92 extern uint16_t ReaderThreshold;
93 
94 typedef enum {
95  CODEC_SUBCARRIERMOD_OFF,
96  CODEC_SUBCARRIERMOD_OOK
97 } SubcarrierModType;
98 
99 extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE];
100 
101 INLINE void CodecInit(void) {
102  ActiveConfiguration.CodecInitFunc();
103 }
104 
105 INLINE void CodecDeInit(void) {
106  ActiveConfiguration.CodecDeInitFunc();
107 }
108 
109 INLINE void CodecTask(void) {
110  ActiveConfiguration.CodecTaskFunc();
111 }
112 
113 /* Helper Functions for Codec implementations */
114 INLINE void CodecInitCommon(void)
115 {
116  /* Configure CARRIER input pin and route it to EVSYS.
117  * Multiply by 2 again by using both edges when externally
118  * dividing by 2 */
119 #if CODEC_CARRIER_IN_DIV == 2
120  CODEC_CARRIER_IN_PORT.CODEC_CARRIER_IN_PINCTRL = PORT_ISC_BOTHEDGES_gc;
121 #else
122 #error Option not supported
123 #endif
124  CODEC_CARRIER_IN_PORT.DIRCLR = CODEC_CARRIER_IN_MASK;
125  EVSYS.CH6MUX = CODEC_CARRIER_IN_EVMUX;
126 
127  /* Configure two DEMOD pins for input.
128  * Configure event channel 0 for rising edge (begin of modulation pause)
129  * Configure event channel 1 for falling edge (end of modulation pause) */
130  CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK;
131  CODEC_DEMOD_POWER_PORT.DIRSET = CODEC_DEMOD_POWER_MASK;
132  CODEC_DEMOD_IN_PORT.DIRCLR = CODEC_DEMOD_IN_MASK;
133  CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL0 = PORT_ISC_RISING_gc;
134  CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL1 = PORT_ISC_FALLING_gc;
135  CODEC_DEMOD_IN_PORT.INT0MASK = 0;
136  CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc;
137  EVSYS.CH0MUX = CODEC_DEMOD_IN_EVMUX0;
138  EVSYS.CH1MUX = CODEC_DEMOD_IN_EVMUX1;
139 
140  /* Configure loadmod pin configuration and use a virtual port configuration
141  * for single instruction cycle access */
142  CODEC_LOADMOD_PORT.DIRSET = CODEC_LOADMOD_MASK;
143  CODEC_LOADMOD_PORT.OUTCLR = CODEC_LOADMOD_MASK;
144  PORTCFG.VPCTRLA &= ~PORTCFG_VP0MAP_gm;
145  PORTCFG.VPCTRLA |= PORTCFG_VP02MAP_PORTC_gc;
146 
147  /* Configure subcarrier pins for output */
148  CODEC_SUBCARRIER_PORT.DIRSET = CODEC_SUBCARRIER_MASK;
149  CODEC_SUBCARRIER_PORT.OUTCLR = CODEC_SUBCARRIER_MASK;
150 
151  /* Configure pins for reader field with the LEFT output being inverted
152  * and all bridge outputs static high */
153  CODEC_READER_PORT.CODEC_READER_PINCTRL_LEFT = PORT_INVEN_bm;
154  CODEC_READER_PORT.OUTCLR = CODEC_READER_MASK_LEFT;
155  CODEC_READER_PORT.OUTSET = CODEC_READER_MASK_RIGHT;
156  CODEC_READER_PORT.DIRSET = CODEC_READER_MASK;
157 
158  /* Configure timer for generating reader field and configure AWEX for outputting pattern
159  * with disabled outputs. */
160  CODEC_READER_TIMER.CTRLB = TC0_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc;
161  CODEC_READER_TIMER.PER = F_CPU / CODEC_CARRIER_FREQ - 1;
162  CODEC_READER_TIMER.CCA = F_CPU / CODEC_CARRIER_FREQ / 2 ;
163 
164  AWEXC.OUTOVEN = 0x00;
165  AWEXC.CTRL = AWEX_CWCM_bm | AWEX_DTICCAEN_bm | AWEX_DTICCBEN_bm;
166 
167  /* Configure DAC for the reference voltage */
168  DACB.EVCTRL = 0;
169  DACB.CTRLB = DAC_CHSEL_SINGLE_gc;
170  DACB.CTRLC = DAC_REFSEL_AVCC_gc;
171  DACB.CTRLA = DAC_IDOEN_bm | DAC_ENABLE_bm;
172  DACB.CH0DATA = ReaderThreshold; // real threshold voltage can be calculated with ch0data * Vref / 0xFFF
173 
174  /* Configure Analog Comparator 0 to detect changes in demodulated reader field */
175  ACA.AC0MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc;
176  ACA.AC0CTRL = CODEC_AC_DEMOD_SETTINGS;
177 
178  /* Configure Analog Comparator 1 to detect SOC */
179  ACA.AC1MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc;
180  ACA.AC1CTRL = CODEC_AC_DEMOD_SETTINGS;
181 }
182 
183 INLINE void CodecSetSubcarrier(SubcarrierModType ModType, uint16_t Divider)
184 {
185  if (ModType == CODEC_SUBCARRIERMOD_OFF) {
186  CODEC_SUBCARRIER_TIMER.CTRLA = TC_CLKSEL_OFF_gc;
187  CODEC_SUBCARRIER_TIMER.CTRLB = 0;
188  } else if (ModType == CODEC_SUBCARRIERMOD_OOK) {
189  /* Configure subcarrier generation with 50% DC output using OOK */
190  CODEC_SUBCARRIER_TIMER.CNT = 0;
191  CODEC_SUBCARRIER_TIMER.PER = Divider - 1;
192  CODEC_SUBCARRIER_TIMER.CODEC_SUBCARRIER_CC_OOK = Divider/2;
193  CODEC_SUBCARRIER_TIMER.CTRLB = CODEC_SUBCARRIER_CCEN_OOK | TC_WGMODE_SINGLESLOPE_gc;
194  }
195 }
196 
197 INLINE void CodecStartSubcarrier(void)
198 {
199  CODEC_SUBCARRIER_TIMER.CTRLA = CODEC_TIMER_CARRIER_CLKSEL;
200 }
201 
202 INLINE void CodecSetDemodPower(bool bOnOff)
203 {
204  if (bOnOff) {
205  CODEC_DEMOD_POWER_PORT.OUTSET = CODEC_DEMOD_POWER_MASK;
206  } else {
207  CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK;
208  }
209 }
210 
211 INLINE bool CodecGetLoadmodState(void) {
212  if (ACA.STATUS & AC_AC0STATE_bm) {
213  return true;
214  } else {
215  return false;
216  }
217 }
218 
219 INLINE void CodecSetLoadmodState(bool bOnOff) {
220  if (bOnOff) {
221  VPORT0.OUT |= CODEC_LOADMOD_MASK;
222  } else {
223  VPORT0.OUT &= ~CODEC_LOADMOD_MASK;
224  }
225 }
226 
227 INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turning on/off the reader field dumbly; before using this function, please consider to use CodecReaderField{Start,Stop}
228 
229  if (bOnOff) {
230  /* Start timer for field generation and unmask outputs */
231  CODEC_READER_TIMER.CTRLA = TC_CLKSEL_DIV1_gc;
232  AWEXC.OUTOVEN = CODEC_READER_MASK;
233  } else {
234  /* Disable outputs of AWEX and stop field generation */
235  AWEXC.OUTOVEN = 0x00;
236  CODEC_READER_TIMER.CTRLA = TC_CLKSEL_OFF_gc;
237  }
238 }
239 
240 INLINE bool CodecGetReaderField(void) {
241  return (CODEC_READER_TIMER.CTRLA == TC_CLKSEL_DIV1_gc) && (AWEXC.OUTOVEN == CODEC_READER_MASK);
242 }
243 
244 void CodecReaderFieldStart(void);
245 void CodecReaderFieldStop(void);
246 bool CodecIsReaderFieldReady(void);
247 
248 #endif /* CODEC_H_ */
void(* CodecInitFunc)(void)
Definition: Configuration.h:57
+
void(* CodecTaskFunc)(void)
Definition: Configuration.h:63
+
void(* CodecDeInitFunc)(void)
Definition: Configuration.h:59
+
+ + + + diff --git a/Doc/Doxygen/html/_command_line_8h_source.html b/Doc/Doxygen/html/_command_line_8h_source.html new file mode 100644 index 00000000..a4b2aab1 --- /dev/null +++ b/Doc/Doxygen/html/_command_line_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: CommandLine.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
CommandLine.h
+
+
+
1 /*
2  * CommandLine.h
3  *
4  * Created on: 04.05.2013
5  * Author: skuser
6  */
7 
8 #ifndef COMMANDLINE_H_
9 #define COMMANDLINE_H_
10 
11 #include "Terminal.h"
12 #include "Commands.h"
13 
14 void CommandLineInit(void);
15 bool CommandLineProcessByte(uint8_t Byte);
16 void CommandLineTick(void);
17 
18 void CommandLineAppendData(void const * const Buffer, uint16_t Bytes);
19 
20 /* Functions for timeout commands */
21 void CommandLinePendingTaskFinished(CommandStatusIdType ReturnStatusID, char const * const OutMessage); // must be called, when the intended task is finished
22 extern void (*CommandLinePendingTaskTimeout) (void); // gets called on timeout to end the pending task
23 void CommandLinePendingTaskBreak(void); // this manually triggers a timeout
24 
25 #endif /* COMMANDLINE_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_command_line_8txt.html b/Doc/Doxygen/html/_command_line_8txt.html new file mode 100644 index 00000000..ec600b35 --- /dev/null +++ b/Doc/Doxygen/html/_command_line_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: CommandLine.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
CommandLine.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_commands_8h_source.html b/Doc/Doxygen/html/_commands_8h_source.html new file mode 100644 index 00000000..3f02d248 --- /dev/null +++ b/Doc/Doxygen/html/_commands_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Commands.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Commands.h
+
+
+
1 
2 
3 #ifndef COMMANDS_H_
4 #define COMMANDS_H_
5 
6 #include "../Common.h"
7 
8 #define MAX_COMMAND_LENGTH 16
9 #define MAX_STATUS_LENGTH 32
10 
11 
12 #define COMMAND_INFO_OK_ID 100
13 #define COMMAND_INFO_OK "OK"
14 #define COMMAND_INFO_OK_WITH_TEXT_ID 101
15 #define COMMAND_INFO_OK_WITH_TEXT "OK WITH TEXT"
16 #define COMMAND_INFO_XMODEM_WAIT_ID 110
17 #define COMMAND_INFO_XMODEM_WAIT "WAITING FOR XMODEM"
18 #define COMMAND_INFO_FALSE_ID 120
19 #define COMMAND_INFO_FALSE "FALSE"
20 #define COMMAND_INFO_TRUE_ID 121
21 #define COMMAND_INFO_TRUE "TRUE"
22 #define COMMAND_ERR_UNKNOWN_CMD_ID 200
23 #define COMMAND_ERR_UNKNOWN_CMD "UNKNOWN COMMAND"
24 #define COMMAND_ERR_INVALID_USAGE_ID 201
25 #define COMMAND_ERR_INVALID_USAGE "INVALID COMMAND USAGE"
26 #define COMMAND_ERR_INVALID_PARAM_ID 202
27 #define COMMAND_ERR_INVALID_PARAM "INVALID PARAMETER"
28 #define COMMAND_ERR_TIMEOUT_ID 203
29 #define COMMAND_ERR_TIMEOUT "TIMEOUT"
30 #define TIMEOUT_COMMAND 255 // this is just for the CommandLine module to know that this is a timeout command
31 
32 
33 #define COMMAND_CHAR_TRUE '1'
34 #define COMMAND_CHAR_FALSE '0'
35 #define COMMAND_CHAR_SUGGEST '?' /* <CMD>=? for help */
36 
37 #define COMMAND_UID_BUFSIZE 32
38 
39 #define COMMAND_IS_SUGGEST_STRING(x) ( ((x)[0] == COMMAND_CHAR_SUGGEST) && ((x)[1] == '\0') )
40 
41 typedef uint8_t CommandStatusIdType;
42 typedef const char CommandStatusMessageType[MAX_STATUS_LENGTH];
43 
44 typedef CommandStatusIdType (*CommandExecFuncType) (char* OutMessage);
45 typedef CommandStatusIdType (*CommandExecParamFuncType) (char* OutMessage, const char* InParams);
46 typedef CommandStatusIdType (*CommandSetFuncType) (char* OutMessage, const char* InParam);
47 typedef CommandStatusIdType (*CommandGetFuncType) (char* OutParam);
48 
49 typedef struct {
50  char Command[MAX_COMMAND_LENGTH];
51  CommandExecFuncType ExecFunc;
52  CommandExecParamFuncType ExecParamFunc;
53  CommandSetFuncType SetFunc;
54  CommandGetFuncType GetFunc;
55 } CommandEntryType;
56 
57 #define COMMAND_VERSION "VERSION"
58 CommandStatusIdType CommandGetVersion(char* OutParam);
59 
60 #define COMMAND_CONFIG "CONFIG"
61 CommandStatusIdType CommandGetConfig(char* OutParam);
62 CommandStatusIdType CommandSetConfig(char* OutMessage, const char* InParam);
63 
64 #define COMMAND_UID "UID"
65 #define COMMAND_UID_RANDOM "RANDOM"
66 CommandStatusIdType CommandGetUid(char* OutParam);
67 CommandStatusIdType CommandSetUid(char* OutMessage, const char* InParam);
68 
69 #define COMMAND_READONLY "READONLY"
70 CommandStatusIdType CommandGetReadOnly(char* OutParam);
71 CommandStatusIdType CommandSetReadOnly(char* OutMessage, const char* InParam);
72 
73 #define COMMAND_UPLOAD "UPLOAD"
74 CommandStatusIdType CommandExecUpload(char* OutMessage);
75 
76 #define COMMAND_DOWNLOAD "DOWNLOAD"
77 CommandStatusIdType CommandExecDownload(char* OutMessage);
78 
79 #define COMMAND_RESET "RESET"
80 CommandStatusIdType CommandExecReset(char* OutMessage);
81 
82 #define COMMAND_UPGRADE "UPGRADE"
83 CommandStatusIdType CommandExecUpgrade(char* OutMessage);
84 
85 #define COMMAND_MEMSIZE "MEMSIZE"
86 CommandStatusIdType CommandGetMemSize(char* OutParam);
87 
88 #define COMMAND_UIDSIZE "UIDSIZE"
89 CommandStatusIdType CommandGetUidSize(char* OutParam);
90 
91 #define COMMAND_RBUTTON "RBUTTON"
92 CommandStatusIdType CommandGetRButton(char* OutParam);
93 CommandStatusIdType CommandSetRButton(char* OutMessage, const char* InParam);
94 
95 #define COMMAND_RBUTTON_LONG "RBUTTON_LONG"
96 CommandStatusIdType CommandGetRButtonLong(char* OutParam);
97 CommandStatusIdType CommandSetRButtonLong(char* OutMessage, const char* InParam);
98 
99 #define COMMAND_LBUTTON "LBUTTON"
100 CommandStatusIdType CommandGetLButton(char* OutParam);
101 CommandStatusIdType CommandSetLButton(char* OutMessage, const char* InParam);
102 
103 #define COMMAND_LBUTTON_LONG "LBUTTON_LONG"
104 CommandStatusIdType CommandGetLButtonLong(char* OutParam);
105 CommandStatusIdType CommandSetLButtonLong(char* OutMessage, const char* InParam);
106 
107 
108 #define COMMAND_LEDGREEN "LEDGREEN"
109 CommandStatusIdType CommandGetLedGreen(char* OutParam);
110 CommandStatusIdType CommandSetLedGreen(char* OutMessage, const char* InParam);
111 
112 #define COMMAND_LEDRED "LEDRED"
113 CommandStatusIdType CommandGetLedRed(char* OutParam);
114 CommandStatusIdType CommandSetLedRed(char* OutMessage, const char* InParam);
115 
116 #define COMMAND_LOGMODE "LOGMODE"
117 CommandStatusIdType CommandGetLogMode(char* OutParam);
118 CommandStatusIdType CommandSetLogMode(char* OutMessage, const char* InParam);
119 
120 #define COMMAND_LOGMEM "LOGMEM"
121 CommandStatusIdType CommandGetLogMem(char* OutParam);
122 
123 #define COMMAND_LOGDOWNLOAD "LOGDOWNLOAD"
124 CommandStatusIdType CommandExecLogDownload(char* OutMessage);
125 
126 #define COMMAND_STORELOG "LOGSTORE"
127 CommandStatusIdType CommandExecStoreLog(char* OutMessage);
128 
129 #define COMMAND_LOGCLEAR "LOGCLEAR"
130 CommandStatusIdType CommandExecLogClear(char* OutMessage);
131 
132 #define COMMAND_SETTING "SETTING"
133 CommandStatusIdType CommandGetSetting(char* OutParam);
134 CommandStatusIdType CommandSetSetting(char* OutMessage, const char* InParam);
135 
136 #define COMMAND_CLEAR "CLEAR"
137 CommandStatusIdType CommandExecClear(char* OutMessage);
138 
139 #define COMMAND_STORE "STORE"
140 CommandStatusIdType CommandExecStore(char* OutMessage);
141 
142 #define COMMAND_RECALL "RECALL"
143 CommandStatusIdType CommandExecRecall(char* OutMessage);
144 
145 #define COMMAND_CHARGING "CHARGING"
146 CommandStatusIdType CommandGetCharging(char* OutParam);
147 
148 #define COMMAND_HELP "HELP"
149 CommandStatusIdType CommandExecHelp(char* OutMessage);
150 
151 #define COMMAND_RSSI "RSSI"
152 CommandStatusIdType CommandGetRssi(char* OutParam);
153 
154 #define COMMAND_SYSTICK "SYSTICK"
155 CommandStatusIdType CommandGetSysTick(char* OutParam);
156 
157 #define COMMAND_SEND_RAW "SEND_RAW"
158 CommandStatusIdType CommandExecParamSendRaw(char* OutMessage, const char* InParams);
159 
160 #define COMMAND_SEND "SEND"
161 CommandStatusIdType CommandExecParamSend(char* OutMessage, const char* InParams);
162 
163 #define COMMAND_GETUID "GETUID"
164 CommandStatusIdType CommandExecGetUid(char* OutMessage);
165 
166 #define COMMAND_DUMP_MFU "DUMP_MFU"
167 CommandStatusIdType CommandExecDumpMFU(char* OutMessage);
168 
169 #define COMMAND_IDENTIFY_CARD "IDENTIFY"
170 CommandStatusIdType CommandExecIdentifyCard(char* OutMessage);
171 
172 #define COMMAND_TIMEOUT "TIMEOUT"
173 CommandStatusIdType CommandGetTimeout(char* OutMessage);
174 CommandStatusIdType CommandSetTimeout(char* OutMessage, const char* InParam);
175 
176 #define COMMAND_THRESHOLD "THRESHOLD"
177 CommandStatusIdType CommandGetThreshold(char* OutParam);
178 CommandStatusIdType CommandSetThreshold(char* OutMessage, const char* InParam);
179 
180 #define COMMAND_FIELD "FIELD"
181 CommandStatusIdType CommandSetField(char* OutMessage, const char* InParam);
182 CommandStatusIdType CommandGetField(char* OutMessage);
183 
184 #define COMMAND_LIST_END ""
185 /* Defines the end of command list. This is no actual command */
186 
187 #endif /* COMMANDS_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_common_8h_source.html b/Doc/Doxygen/html/_common_8h_source.html new file mode 100644 index 00000000..283ba0ef --- /dev/null +++ b/Doc/Doxygen/html/_common_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Common.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Common.h
+
+
+
1 /*
2  * Common.h
3  *
4  * Created on: 20.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef COMMON_H_
9 #define COMMON_H_
10 
11 #include <stdio.h>
12 #include <stdbool.h>
13 #include <util/parity.h>
14 #include <util/delay.h>
15 #include <avr/pgmspace.h>
16 #include <avr/io.h>
17 
18 #define ODD_PARITY(Value) OddParityBit(Value)//(parity_even_bit(Value) ? 0 : 1)
19 
20 #define INLINE \
21  static inline __attribute__((always_inline))
22 
23 #define NIBBLE_TO_HEXCHAR(x) ( (x) < 0x0A ? (x) + '0' : (x) + 'A' - 0x0A )
24 #define HEXCHAR_TO_NIBBLE(x) ( (x) < 'A' ? (x) - '0' : (x) - 'A' + 0x0A )
25 #define VALID_HEXCHAR(x) ( ( (x) >= '0' && (x) <= '9' ) || ( (x) >= 'A' && (x) <= 'F' ) )
26 #define MIN(x,y) ( (x) < (y) ? (x) : (y) )
27 #define MAX(x,y) ( (x) > (y) ? (x) : (y) )
28 #define SYSTICK_DIFF(since) ((uint16_t) (SystemGetSysTick() - since))
29 #define SYSTICK_DIFF_100MS(since) (SYSTICK_DIFF(since) / 100)
30 
31 #define BITS_PER_BYTE 8
32 
33 uint16_t BufferToHexString(char* HexOut, uint16_t MaxChars, const void* Buffer, uint16_t ByteCount);
34 uint16_t HexStringToBuffer(void* Buffer, uint16_t MaxBytes, const char* HexIn);
35 
36 INLINE uint8_t BitReverseByte(uint8_t Byte)
37 {
38  extern const uint8_t PROGMEM BitReverseByteTable[];
39 
40  return pgm_read_byte(&BitReverseByteTable[Byte]);
41 }
42 
43 INLINE uint8_t OddParityBit(uint8_t Byte)
44 {
45  extern const uint8_t PROGMEM OddParityByteTable[];
46 
47  return pgm_read_byte(&OddParityByteTable[Byte]);
48 }
49 
50 INLINE uint8_t StringLength(const char* Str, uint8_t MaxLen)
51 {
52  uint8_t StrLen = 0;
53 
54  while(MaxLen > 0) {
55  if (*Str++ == '\0')
56  break;
57 
58  MaxLen--;
59  StrLen++;
60  }
61 
62  return StrLen;
63 }
64 
65 #endif /* COMMON_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_configuration_8h.html b/Doc/Doxygen/html/_configuration_8h.html new file mode 100644 index 00000000..7c10dd65 --- /dev/null +++ b/Doc/Doxygen/html/_configuration_8h.html @@ -0,0 +1,112 @@ + + + + + + +Chameleon-Mini: Configuration.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
Configuration.h File Reference
+
+
+
#include <stdint.h>
+#include <stdbool.h>
+
+

Go to the source code of this file.

+ + + + +

+Classes

struct  ConfigurationType
 
+
+ + + + diff --git a/Doc/Doxygen/html/_configuration_8h_source.html b/Doc/Doxygen/html/_configuration_8h_source.html new file mode 100644 index 00000000..e3dd132d --- /dev/null +++ b/Doc/Doxygen/html/_configuration_8h_source.html @@ -0,0 +1,104 @@ + + + + + + +Chameleon-Mini: Configuration.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Configuration.h
+
+
+Go to the documentation of this file.
1 /*
2  * Standards.h
3  *
4  * Created on: 15.02.2013
5  * Author: skuser
6  */
8 #ifndef STANDARDS_H_
9 #define STANDARDS_H_
10 
11 #include <stdint.h>
12 #include <stdbool.h>
13 
14 #define CONFIGURATION_NAME_LENGTH_MAX 32
15 #define CONFIGURATION_UID_SIZE_MAX 16
16 
17 typedef uint8_t ConfigurationUidType[CONFIGURATION_UID_SIZE_MAX];
18 
19 typedef enum {
20  /* This HAS to be the first element */
21  CONFIG_NONE = 0,
22 
23 #ifdef CONFIG_MF_ULTRALIGHT_SUPPORT
24  CONFIG_MF_ULTRALIGHT,
25 #endif
26 #ifdef CONFIG_MF_CLASSIC_1K_SUPPORT
27  CONFIG_MF_CLASSIC_1K,
28 #endif
29 #ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT
30  CONFIG_MF_CLASSIC_1K_7B,
31 #endif
32 #ifdef CONFIG_MF_CLASSIC_4K_SUPPORT
33  CONFIG_MF_CLASSIC_4K,
34 #endif
35 #ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT
36  CONFIG_MF_CLASSIC_4K_7B,
37 #endif
38 #ifdef CONFIG_ISO14443A_SNIFF_SUPPORT
39  CONFIG_ISO14443A_SNIFF,
40 #endif
41 #ifdef CONFIG_ISO14443A_READER_SUPPORT
42  CONFIG_ISO14443A_READER,
43 #endif
44  /* This HAS to be the last element */
45  CONFIG_COUNT
46 } ConfigurationEnum;
47 
49 typedef struct {
57  void (*CodecInitFunc) (void);
59  void (*CodecDeInitFunc) (void);
63  void (*CodecTaskFunc) (void);
75  void (*ApplicationInitFunc) (void);
77  void (*ApplicationResetFunc) (void);
79  void (*ApplicationTaskFunc) (void);
81  void (*ApplicationTickFunc) (void);
93  uint16_t (*ApplicationProcessFunc) (uint8_t* ByteBuffer, uint16_t BitCount);
98  void (*ApplicationGetUidFunc) (ConfigurationUidType Uid);
103  void (*ApplicationSetUidFunc) (ConfigurationUidType Uid);
114  uint16_t MemorySize;
120  uint8_t UidSize;
124  bool ReadOnly;
125 
127 
128 extern ConfigurationType ActiveConfiguration;
129 
130 void ConfigurationInit(void);
131 void ConfigurationSetById(ConfigurationEnum Configuration);
132 void ConfigurationGetByName(char* Configuration, uint16_t BufferSize);
133 bool ConfigurationSetByName(const char* Configuration);
134 void ConfigurationGetList(char* ConfigurationList, uint16_t BufferSize);
135 
136 #endif /* STANDARDS_H_ */
uint16_t MemorySize
Definition: Configuration.h:114
+
Definition: Configuration.h:49
+
bool ReadOnly
Definition: Configuration.h:124
+
uint8_t UidSize
Definition: Configuration.h:120
+
+ + + + diff --git a/Doc/Doxygen/html/_configurations_8txt.html b/Doc/Doxygen/html/_configurations_8txt.html new file mode 100644 index 00000000..92038b60 --- /dev/null +++ b/Doc/Doxygen/html/_configurations_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: Configurations.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
Configurations.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_crypto1_8h_source.html b/Doc/Doxygen/html/_crypto1_8h_source.html new file mode 100644 index 00000000..b782c2a4 --- /dev/null +++ b/Doc/Doxygen/html/_crypto1_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Crypto1.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Crypto1.h
+
+
+
1 #ifndef CRYPTO1_H
2 #define CRYPTO1_H
3 
4 #include <stdint.h>
5 #include <stdbool.h>
6 
7 /* Gets the current keystream-bit, without shifting the internal LFSR */
8 uint8_t Crypto1FilterOutput(void);
9 
10 /* Set up Crypto1 cipher using the given Key, Uid and CardNonce. Also encrypts
11  * the CardNonce in-place while in non-linear mode. */
12 void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4]);
13 
14 /* Set up Crypto1 cipher using the given Key, Uid and CardNonce. Nested indicates
15  * whether the CardNonce is encrypted (true) or not (false).
16  * If the CardNonce is encrypted, it will we decrypted in-place. If not, it will
17  * be fed into the LFSR, but remains unchanged. */
18 void Crypto1SetupReader(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], bool Nested);
19 
20 /* Load the decrypted ReaderNonce into the Crypto1 state LFSR */
21 void Crypto1Auth(uint8_t EncryptedReaderNonce[4]);
22 
23 /* Generate 8 Bits of key stream */
24 uint8_t Crypto1Byte(void);
25 
26 /* Generate 4 Bits of key stream */
27 uint8_t Crypto1Nibble(void);
28 
29 /* Execute 'ClockCount' cycles on the PRNG state 'State' */
30 void Crypto1PRNG(uint8_t State[4], uint16_t ClockCount);
31 
32 /* Encrypts buffer with consideration of parity bits */
33 void Crypto1EncryptWithParity(uint8_t * Buffer, uint16_t BitCount);
34 
35 /* Encrypts buffer with LFSR feedback within reader nonce and considers parity bits */
36 void Crypto1ReaderAuthWithParity(uint8_t PlainReaderAnswerWithParityBits[9]);
37 
38 #endif //CRYPTO1_H
+ + + + diff --git a/Doc/Doxygen/html/_getting_started_8txt.html b/Doc/Doxygen/html/_getting_started_8txt.html new file mode 100644 index 00000000..37eaeeaf --- /dev/null +++ b/Doc/Doxygen/html/_getting_started_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: GettingStarted.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
GettingStarted.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_i_s_o14443-2_a_8h_source.html b/Doc/Doxygen/html/_i_s_o14443-2_a_8h_source.html new file mode 100644 index 00000000..08a979cb --- /dev/null +++ b/Doc/Doxygen/html/_i_s_o14443-2_a_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: ISO14443-2A.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
ISO14443-2A.h
+
+
+
1 /*
2  * ISO14443-2A.h
3  *
4  * Created on: 18.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef ISO14443_2A_H_
9 #define ISO14443_2A_H_
10 
11 #include "Codec.h"
12 
13 #define ISO14443A_APP_NO_RESPONSE 0x0000
14 #define ISO14443A_APP_CUSTOM_PARITY 0x1000
15 
16 #define ISO14443A_BUFFER_PARITY_OFFSET (CODEC_BUFFER_SIZE/2)
17 
18 /* Codec Interface */
19 void ISO14443ACodecInit(void);
20 void ISO14443ACodecDeInit(void);
21 void ISO14443ACodecTask(void);
22 
23 
24 
25 #endif
+ + + + diff --git a/Doc/Doxygen/html/_i_s_o14443-3_a_8h_source.html b/Doc/Doxygen/html/_i_s_o14443-3_a_8h_source.html new file mode 100644 index 00000000..1acea102 --- /dev/null +++ b/Doc/Doxygen/html/_i_s_o14443-3_a_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: ISO14443-3A.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
ISO14443-3A.h
+
+
+
1 /*
2  * ISO14443-2A.h
3  *
4  * Created on: 19.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef ISO14443_3A_H_
9 #define ISO14443_3A_H_
10 
11 #include "../Common.h"
12 
13 #define ISO14443A_UID_SIZE_SINGLE 4 /* bytes */
14 #define ISO14443A_UID_SIZE_DOUBLE 7
15 #define ISO14443A_UID_SIZE_TRIPLE 10
16 
17 #define ISO14443A_CMD_REQA 0x26
18 #define ISO14443A_CMD_WUPA 0x52
19 #define ISO14443A_CMD_SELECT_CL1 0x93
20 #define ISO14443A_CMD_SELECT_CL2 0x95
21 #define ISO14443A_CMD_SELECT_CL3 0x97
22 #define ISO14443A_CMD_HLTA 0x50
23 
24 #define ISO14443A_NVB_AC_START 0x20
25 #define ISO14443A_NVB_AC_END 0x70
26 
27 #define ISO14443A_CL_UID_OFFSET 0
28 #define ISO14443A_CL_UID_SIZE 4
29 #define ISO14443A_CL_BCC_OFFSET 4
30 #define ISO14443A_CL_BCC_SIZE 1 /* Byte */
31 #define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */
32 #define ISO14443A_SAK_INCOMPLETE 0x04
33 #define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20
34 #define ISO14443A_SAK_COMPLETE_NOT_COMPLIANT 0x00
35 
36 #define ISO14443A_ATQA_FRAME_SIZE (2 * 8) /* Bit */
37 #define ISO14443A_SAK_FRAME_SIZE (3 * 8) /* Bit */
38 
39 #define ISO14443A_UID0_RANDOM 0x08
40 #define ISO14443A_UID0_CT 0x88
41 
42 #define ISO14443A_CRCA_SIZE 2
43 
44 #define ISO14443A_CALC_BCC(ByteBuffer) \
45  ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] )
46 
47 void ISO14443AAppendCRCA(void* Buffer, uint16_t ByteCount);
48 bool ISO14443ACheckCRCA(void* Buffer, uint16_t ByteCount);
49 
50 INLINE bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue);
51 INLINE bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue);
52 
53 INLINE
54 bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue)
55 {
56  uint8_t* DataPtr = (uint8_t*) Buffer;
57  uint8_t NVB = DataPtr[1];
58  //uint8_t CollisionByteCount = (NVB >> 4) & 0x0F;
59  //uint8_t CollisionBitCount = (NVB >> 0) & 0x0F;
60 
61  switch (NVB) {
62  case ISO14443A_NVB_AC_START:
63  /* Start of anticollision procedure.
64  * Send whole UID CLn + BCC */
65  DataPtr[0] = UidCL[0];
66  DataPtr[1] = UidCL[1];
67  DataPtr[2] = UidCL[2];
68  DataPtr[3] = UidCL[3];
69  DataPtr[4] = ISO14443A_CALC_BCC(DataPtr);
70 
71  *BitCount = ISO14443A_CL_FRAME_SIZE;
72 
73  return false;
74 
75  case ISO14443A_NVB_AC_END:
76  /* End of anticollision procedure.
77  * Send SAK CLn if we are selected. */
78  if ( (DataPtr[2] == UidCL[0]) &&
79  (DataPtr[3] == UidCL[1]) &&
80  (DataPtr[4] == UidCL[2]) &&
81  (DataPtr[5] == UidCL[3]) ) {
82 
83  DataPtr[0] = SAKValue;
84  ISO14443AAppendCRCA(Buffer, 1);
85 
86  *BitCount = ISO14443A_SAK_FRAME_SIZE;
87  return true;
88  } else {
89  /* We have not been selected. Don't send anything. */
90  *BitCount = 0;
91  return false;
92  }
93  default:
94  /* TODO: No anticollision supported */
95  *BitCount = 0;
96  return false;
97  }
98 }
99 
100 INLINE
101 bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue)
102 {
103  uint8_t* DataPtr = (uint8_t*) Buffer;
104 
105  if ( (DataPtr[0] == ISO14443A_CMD_REQA) || (DataPtr[0] == ISO14443A_CMD_WUPA) ){
106  DataPtr[0] = (ATQAValue >> 0) & 0x00FF;
107  DataPtr[1] = (ATQAValue >> 8) & 0x00FF;
108 
109  *BitCount = ISO14443A_ATQA_FRAME_SIZE;
110 
111  return true;
112  } else {
113  return false;
114  }
115 }
116 
117 #endif
+ + + + diff --git a/Doc/Doxygen/html/_l_e_d_8h_source.html b/Doc/Doxygen/html/_l_e_d_8h_source.html new file mode 100644 index 00000000..0ffac75c --- /dev/null +++ b/Doc/Doxygen/html/_l_e_d_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: LED.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
LED.h
+
+
+
1 /*
2  * LED.h
3  *
4  * Created on: 10.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef LED_H
9 #define LED_H
10 
11 #include <avr/io.h>
12 #include "Common.h"
13 
14 #define LED_PORT PORTA
15 #define LED_GREEN PIN4_bm
16 #define LED_RED PIN3_bm
17 #define LED_MASK (LED_GREEN | LED_RED)
18 
19 typedef enum LEDFunctionEnum {
20  LED_NO_FUNC = 0, /* Don't light up the LED */
21  LED_POWERED, /* Light up the LED whenever the Chameleon is powered */
22 
23  LED_TERMINAL_CONN, /* A Terminal/USB connection has been established */
24  LED_TERMINAL_RXTX, /* There is traffic on the terminal */
25 
26  LED_SETTING_CHANGE, /* Outputs a blink code that shows the current setting */
27 
28  LED_MEMORY_STORED, /* Blink once when memory has been stored to flash */
29  LED_MEMORY_CHANGED, /* Switch LED on when card memory has changed compared to flash */
30 
31  LED_FIELD_DETECTED, /* Shows LED while a reader field is being detected or turned on by the chameleon itself */
32 
33  LED_CODEC_RX, /* Blink LED when receiving codec data */
34  LED_CODEC_TX, /* Blink LED when transmitting codec data */
35 
36  LED_LOG_MEM_FULL, /* Light up if log memory is full. */
37 
38  //TODO: LED_APP_SELECTED, /* Show LED while the correct UID has been selected and the application is active */
39  /* Has to be last element */
40  LED_FUNC_COUNT
41 } LEDHookEnum;
42 
43 typedef enum LEDActionEnum {
44  LED_NO_ACTION = 0x00,
45  LED_OFF = 0x10,
46  LED_ON = 0x11,
47  LED_TOGGLE = 0x12,
48  LED_PULSE = 0x13,
49  LED_BLINK = 0x20,
50  LED_BLINK_1X = 0x20,
51  LED_BLINK_2X, /* Have to be sequentially ordered */
52  LED_BLINK_3X,
53  LED_BLINK_4X,
54  LED_BLINK_5X,
55  LED_BLINK_6X,
56  LED_BLINK_7X,
57  LED_BLINK_8X,
58 } LEDActionEnum;
59 
60 
61 
62 void LEDInit(void);
63 void LEDTick(void);
64 
65 void LEDGetFuncList(char* List, uint16_t BufferSize);
66 void LEDSetFuncById(uint8_t Mask, LEDHookEnum Func);
67 void LEDGetFuncByName(uint8_t Mask, char* Function, uint16_t BufferSize);
68 bool LEDSetFuncByName(uint8_t Mask, const char* Function);
69 
70 #endif /* LED_H */
+ + + + diff --git a/Doc/Doxygen/html/_l_e_d_8txt.html b/Doc/Doxygen/html/_l_e_d_8txt.html new file mode 100644 index 00000000..daade40c --- /dev/null +++ b/Doc/Doxygen/html/_l_e_d_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: LED.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
LED.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_l_e_d_hook_8h_source.html b/Doc/Doxygen/html/_l_e_d_hook_8h_source.html new file mode 100644 index 00000000..94471c50 --- /dev/null +++ b/Doc/Doxygen/html/_l_e_d_hook_8h_source.html @@ -0,0 +1,101 @@ + + + + + + +Chameleon-Mini: LEDHook.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
LEDHook.h
+
+
+
1 /*
2  * LEDHook.h
3  *
4  * Created on: 02.12.2014
5  * Author: sk
6  */
7 
8 #ifndef LEDHOOK_H_
9 #define LEDHOOK_H_
10 
11 #include "Settings.h"
12 
13 INLINE void LEDHook(LEDHookEnum Func, LEDActionEnum Action) {
14  extern LEDActionEnum LEDGreenAction;
15  extern LEDActionEnum LEDRedAction;
16 
17  if (GlobalSettings.ActiveSettingPtr->LEDGreenFunction == Func) {
18  LEDGreenAction = Action;
19  }
20 
21  if (GlobalSettings.ActiveSettingPtr->LEDRedFunction == Func) {
22  LEDRedAction = Action;
23  }
24 }
25 
26 #endif /* LEDHOOK_H_ */
+
+ + + + diff --git a/Doc/Doxygen/html/_l_e_ds_8txt.html b/Doc/Doxygen/html/_l_e_ds_8txt.html new file mode 100644 index 00000000..e2f029d9 --- /dev/null +++ b/Doc/Doxygen/html/_l_e_ds_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: LEDs.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
LEDs.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_l_u_f_a_config_8h.html b/Doc/Doxygen/html/_l_u_f_a_config_8h.html new file mode 100644 index 00000000..b0072661 --- /dev/null +++ b/Doc/Doxygen/html/_l_u_f_a_config_8h.html @@ -0,0 +1,109 @@ + + + + + + +Chameleon-Mini: LUFAConfig.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
LUFAConfig.h File Reference
+
+
+ +

LUFA Library Configuration Header File. +More...

+ +

Go to the source code of this file.

+

Detailed Description

+

LUFA Library Configuration Header File.

+

This header file is used to configure LUFA's compile time options, as an alternative to the compile time constants supplied through a makefile.

+

For information on what each token does, refer to the LUFA manual section "Summary of Compile Tokens".

+
+ + + + diff --git a/Doc/Doxygen/html/_l_u_f_a_config_8h_source.html b/Doc/Doxygen/html/_l_u_f_a_config_8h_source.html new file mode 100644 index 00000000..65f59a78 --- /dev/null +++ b/Doc/Doxygen/html/_l_u_f_a_config_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: LUFAConfig.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
LUFAConfig.h
+
+
+Go to the documentation of this file.
1 /*
2  LUFA Library
3  Copyright (C) Dean Camera, 2012.
4 
5  dean [at] fourwalledcubicle [dot] com
6  www.lufa-lib.org
7 */
8 
9 /*
10  Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 
12  Permission to use, copy, modify, distribute, and sell this
13  software and its documentation for any purpose is hereby granted
14  without fee, provided that the above copyright notice appear in
15  all copies and that both that the copyright notice and this
16  permission notice and warranty disclaimer appear in supporting
17  documentation, and that the name of the author not be used in
18  advertising or publicity pertaining to distribution of the
19  software without specific, written prior permission.
20 
21  The author disclaim all warranties with regard to this
22  software, including all implied warranties of merchantability
23  and fitness. In no event shall the author be liable for any
24  special, indirect or consequential damages or any damages
25  whatsoever resulting from loss of use, data or profits, whether
26  in an action of contract, negligence or other tortious action,
27  arising out of or in connection with the use or performance of
28  this software.
29 */
30 
42 #ifndef _LUFA_CONFIG_H_
43 #define _LUFA_CONFIG_H_
44 
45  /* Non-USB Related Configuration Tokens: */
46 // #define DISABLE_TERMINAL_CODES
47 
48  /* USB Class Driver Related Tokens: */
49 // #define HID_HOST_BOOT_PROTOCOL_ONLY
50 // #define HID_STATETABLE_STACK_DEPTH {Insert Value Here}
51 // #define HID_USAGE_STACK_DEPTH {Insert Value Here}
52 // #define HID_MAX_COLLECTIONS {Insert Value Here}
53 // #define HID_MAX_REPORTITEMS {Insert Value Here}
54 // #define HID_MAX_REPORT_IDS {Insert Value Here}
55 // #define NO_CLASS_DRIVER_AUTOFLUSH
56 
57  /* General USB Driver Related Tokens: */
58  #define USE_STATIC_OPTIONS \
59  (USB_OPT_BUSEVENT_PRIMED | USB_DEVICE_OPT_FULLSPEED | /*USB_OPT_PLLCLKSRC*/ USB_OPT_RC32MCLKSRC)
60  #define USB_DEVICE_ONLY
61 // #define USB_STREAM_TIMEOUT_MS {Insert Value Here}
62 // #define NO_LIMITED_CONTROLLER_CONNECT
63 // #define NO_SOF_EVENTS
64 
65  /* USB Device Mode Driver Related Tokens: */
66 // #define USE_RAM_DESCRIPTORS
67  #define USE_FLASH_DESCRIPTORS
68 // #define USE_EEPROM_DESCRIPTORS
69 // #define NO_INTERNAL_SERIAL
70  #define FIXED_CONTROL_ENDPOINT_SIZE 8
71 // #define DEVICE_STATE_AS_GPIOR {Insert Value Here}
72  #define FIXED_NUM_CONFIGURATIONS 1
73 // #define CONTROL_ONLY_DEVICE
74  #define MAX_ENDPOINT_INDEX 5
75 // #define NO_DEVICE_REMOTE_WAKEUP
76 // #define NO_DEVICE_SELF_POWER
77 
78 #endif
+ + + + diff --git a/Doc/Doxygen/html/_l_u_f_a_descriptors_8c.html b/Doc/Doxygen/html/_l_u_f_a_descriptors_8c.html new file mode 100644 index 00000000..3bcb050b --- /dev/null +++ b/Doc/Doxygen/html/_l_u_f_a_descriptors_8c.html @@ -0,0 +1,226 @@ + + + + + + +Chameleon-Mini: LUFADescriptors.c File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
LUFADescriptors.c File Reference
+
+
+
#include "LUFADescriptors.h"
+#include <LUFA/Version.h>
+
+ + + +

+Functions

uint16_t CALLBACK_USB_GetDescriptor (const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress)
 
+ + + + + + + + + + + +

+Variables

const USB_Descriptor_Device_t PROGMEM DeviceDescriptor
 
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor
 
const USB_Descriptor_String_t PROGMEM LanguageString
 
const USB_Descriptor_String_t PROGMEM ManufacturerString
 
const USB_Descriptor_String_t PROGMEM ProductString
 
+

Detailed Description

+

USB Device Descriptors, for library use when in USB device mode. Descriptors are special computer-readable structures which the host requests upon device enumeration, to determine the device's capabilities and functions.

+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16_t CALLBACK_USB_GetDescriptor (const uint16_t wValue,
const uint8_t wIndex,
const void **const DescriptorAddress 
)
+
+

This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" documentation) by the application code so that the address and size of a requested descriptor can be given to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the USB host.

+ +
+
+

Variable Documentation

+ +
+
+ + + + +
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor
+
+Initial value:
=
{
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
.USBSpecification = VERSION_BCD(01.10),
.Class = CDC_CSCP_CDCClass,
.SubClass = CDC_CSCP_NoSpecificSubclass,
.Protocol = CDC_CSCP_NoSpecificProtocol,
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
.VendorID = 0x16D0,
.ProductID = 0x04B2,
.ReleaseNumber = VERSION_BCD(00.01),
.ManufacturerStrIndex = 0x01,
.ProductStrIndex = 0x02,
.SerialNumStrIndex = USE_INTERNAL_SERIAL,
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
}

Device descriptor structure. This descriptor, located in FLASH memory, describes the overall device characteristics, including the supported USB version, control endpoint size and the number of device configurations. The descriptor is read out by the USB host when the enumeration process begins.

+ +
+
+ +
+
+ + + + +
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor
+
+

Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage of the device in one of its supported configurations, including information about any device interfaces and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting a configuration so that the host may correctly communicate with the USB device.

+ +
+
+ +
+
+ + + + +
const USB_Descriptor_String_t PROGMEM LanguageString
+
+Initial value:
=
{
.Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String},
.UnicodeString = {LANGUAGE_ID_ENG}
}

Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate via the language ID table available at USB.org what languages the device supports for its string descriptors.

+ +
+
+ +
+
+ + + + +
const USB_Descriptor_String_t PROGMEM ManufacturerString
+
+Initial value:
=
{
.Header = {.Size = USB_STRING_LEN(20), .Type = DTYPE_String},
.UnicodeString = L"Kasper & Oswald GmbH"
}

Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device Descriptor.

+ +
+
+ +
+
+ + + + +
const USB_Descriptor_String_t PROGMEM ProductString
+
+Initial value:
=
{
.Header = {.Size = USB_STRING_LEN(14), .Type = DTYPE_String},
.UnicodeString = L"Chameleon-Mini"
}

Product descriptor string. This is a Unicode string containing the product's details in human readable form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device Descriptor.

+ +
+
+
+ + + + diff --git a/Doc/Doxygen/html/_l_u_f_a_descriptors_8h.html b/Doc/Doxygen/html/_l_u_f_a_descriptors_8h.html new file mode 100644 index 00000000..16bb7eaf --- /dev/null +++ b/Doc/Doxygen/html/_l_u_f_a_descriptors_8h.html @@ -0,0 +1,234 @@ + + + + + + +Chameleon-Mini: LUFADescriptors.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
LUFADescriptors.h File Reference
+
+
+
#include <avr/pgmspace.h>
+#include <LUFA/Drivers/USB/USB.h>
+
+

Go to the source code of this file.

+ + + + +

+Classes

struct  USB_Descriptor_Configuration_t
 
+ + + + + + + + + + + +

+Macros

#define CDC_NOTIFICATION_EPADDR   (ENDPOINT_DIR_IN | 2)
 
#define CDC_TX_EPADDR   (ENDPOINT_DIR_IN | 3)
 
#define CDC_RX_EPADDR   (ENDPOINT_DIR_OUT | 4)
 
#define CDC_NOTIFICATION_EPSIZE   8
 
#define CDC_TXRX_EPSIZE   16
 
+ + + +

+Functions

uint16_t CALLBACK_USB_GetDescriptor (const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress) ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3)
 
+

Detailed Description

+

Header file for Descriptors.c.

+

Macro Definition Documentation

+ +
+
+ + + + +
#define CDC_NOTIFICATION_EPADDR   (ENDPOINT_DIR_IN | 2)
+
+

Endpoint address of the CDC device-to-host notification IN endpoint.

+ +
+
+ +
+
+ + + + +
#define CDC_TX_EPADDR   (ENDPOINT_DIR_IN | 3)
+
+

Endpoint address of the CDC device-to-host data IN endpoint.

+ +
+
+ +
+
+ + + + +
#define CDC_RX_EPADDR   (ENDPOINT_DIR_OUT | 4)
+
+

Endpoint address of the CDC host-to-device data OUT endpoint.

+ +
+
+ +
+
+ + + + +
#define CDC_NOTIFICATION_EPSIZE   8
+
+

Size in bytes of the CDC device-to-host notification IN endpoint.

+ +
+
+ +
+
+ + + + +
#define CDC_TXRX_EPSIZE   16
+
+

Size in bytes of the CDC data IN and OUT endpoints.

+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
uint16_t CALLBACK_USB_GetDescriptor (const uint16_t wValue,
const uint8_t wIndex,
const void **const DescriptorAddress 
)
+
+

This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" documentation) by the application code so that the address and size of a requested descriptor can be given to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the USB host.

+ +
+
+
+ + + + diff --git a/Doc/Doxygen/html/_l_u_f_a_descriptors_8h_source.html b/Doc/Doxygen/html/_l_u_f_a_descriptors_8h_source.html new file mode 100644 index 00000000..7d98772e --- /dev/null +++ b/Doc/Doxygen/html/_l_u_f_a_descriptors_8h_source.html @@ -0,0 +1,102 @@ + + + + + + +Chameleon-Mini: LUFADescriptors.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
LUFADescriptors.h
+
+
+Go to the documentation of this file.
1 /*
2  LUFA Library
3  Copyright (C) Dean Camera, 2012.
4 
5  dean [at] fourwalledcubicle [dot] com
6  www.lufa-lib.org
7 */
8 
9 /*
10  Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 
12  Permission to use, copy, modify, distribute, and sell this
13  software and its documentation for any purpose is hereby granted
14  without fee, provided that the above copyright notice appear in
15  all copies and that both that the copyright notice and this
16  permission notice and warranty disclaimer appear in supporting
17  documentation, and that the name of the author not be used in
18  advertising or publicity pertaining to distribution of the
19  software without specific, written prior permission.
20 
21  The author disclaim all warranties with regard to this
22  software, including all implied warranties of merchantability
23  and fitness. In no event shall the author be liable for any
24  special, indirect or consequential damages or any damages
25  whatsoever resulting from loss of use, data or profits, whether
26  in an action of contract, negligence or other tortious action,
27  arising out of or in connection with the use or performance of
28  this software.
29 */
30 
36 #ifndef _DESCRIPTORS_H_
37 #define _DESCRIPTORS_H_
38 
39  /* Includes: */
40  #include <avr/pgmspace.h>
41 
42  #include <LUFA/Drivers/USB/USB.h>
43 
44  /* Macros: */
46  #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2)
47 
49  #define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3)
50 
52  #define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4)
53 
55  #define CDC_NOTIFICATION_EPSIZE 8
56 
58  #define CDC_TXRX_EPSIZE 16
59 
60  /* Type Defines: */
65  typedef struct
66  {
67  USB_Descriptor_Configuration_Header_t Config;
68 
69  // CDC Control Interface
70  USB_Descriptor_Interface_t CDC_CCI_Interface;
71  USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header;
72  USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM;
73  USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union;
74  USB_Descriptor_Endpoint_t CDC_NotificationEndpoint;
75 
76  // CDC Data Interface
77  USB_Descriptor_Interface_t CDC_DCI_Interface;
78  USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
79  USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
81 
82  /* Function Prototypes: */
83  uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
84  const uint8_t wIndex,
85  const void** const DescriptorAddress)
86  ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
87 
88 #endif
89 
Definition: LUFADescriptors.h:65
+
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress) ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3)
Definition: LUFADescriptors.c:228
+
+ + + + diff --git a/Doc/Doxygen/html/_log_8h.html b/Doc/Doxygen/html/_log_8h.html new file mode 100644 index 00000000..fdb1987f --- /dev/null +++ b/Doc/Doxygen/html/_log_8h.html @@ -0,0 +1,191 @@ + + + + + + +Chameleon-Mini: Log.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
Log.h File Reference
+
+
+
#include "Common.h"
+
+

Go to the source code of this file.

+ + +

+Enumerations

+

Enumeration Type Documentation

+ +
+
+ + + + +
enum LogEntryEnum
+
+

Enum for log entry type.

Note
Every entry type has a specific integer value, which can be found in the source code.
+ + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
LOG_INFO_GENERIC  +

Unspecific log entry.

+
LOG_INFO_CONFIG_SET  +

Configuration change.

+
LOG_INFO_SETTING_SET  +

Setting change.

+
LOG_INFO_UID_SET  +

UID change.

+
LOG_INFO_RESET_APP  +

Application reset.

+
LOG_INFO_CODEC_RX_DATA  +

Currently active codec received data.

+
LOG_INFO_CODEC_TX_DATA  +

Currently active codec sent data.

+
LOG_INFO_APP_CMD_READ  +

Application processed read command.

+
LOG_INFO_APP_CMD_WRITE  +

Application processed write command.

+
LOG_INFO_APP_CMD_INC  +

Application processed increment command.

+
LOG_INFO_APP_CMD_DEC  +

Application processed decrement command.

+
LOG_INFO_APP_CMD_TRANSFER  +

Application processed transfer command.

+
LOG_INFO_APP_CMD_RESTORE  +

Application processed restore command.

+
LOG_INFO_APP_CMD_AUTH  +

Application processed authentication command.

+
LOG_INFO_APP_CMD_HALT  +

Application processed halt command.

+
LOG_INFO_APP_CMD_UNKNOWN  +

Application processed an unknown command.

+
LOG_INFO_APP_AUTHING  +

Application is in authing state.

+
LOG_INFO_APP_AUTHED  +

Application is in auth state.

+
LOG_ERR_APP_AUTH_FAIL  +

Application authentication failed.

+
LOG_ERR_APP_CHECKSUM_FAIL  +

Application had a checksum fail.

+
LOG_ERR_APP_NOT_AUTHED  +

Application is not authenticated.

+
LOG_EMPTY  +

Empty Log Entry. This is not followed by a length byte nor the two systick bytes nor any data.

+
+ +
+
+
+ + + + diff --git a/Doc/Doxygen/html/_log_8h_source.html b/Doc/Doxygen/html/_log_8h_source.html new file mode 100644 index 00000000..e33f3232 --- /dev/null +++ b/Doc/Doxygen/html/_log_8h_source.html @@ -0,0 +1,123 @@ + + + + + + +Chameleon-Mini: Log.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Log.h
+
+
+Go to the documentation of this file.
1 #ifndef LOG_H_
2 #define LOG_H_
3 
4 #include "Common.h"
5 
6 #define LOG_SIZE 2048
7 #define FRAM_LOG_START_ADDR 0x4000 // from the start of the second half of FRAM
8 #define FRAM_LOG_SIZE 0x4000 // the whole second half
9 
11 typedef enum {
12  /* Generic */
18 
19  /* Codec */
22 
23  /* App */
38 
39  LOG_EMPTY = 0x00
40 } LogEntryEnum;
41 
42 typedef enum {
43  LOG_MODE_OFF,
44  LOG_MODE_MEMORY,
45  LOG_MODE_LIVE
46 } LogModeEnum;
47 
48 typedef void (*LogFuncType) (LogEntryEnum Entry, const void* Data, uint8_t Length);
49 
50 extern LogFuncType CurrentLogFunc;
51 
52 void LogInit(void);
53 void LogTick(void);
54 void LogTask(void);
55 
56 void LogMemClear(void);
57 uint16_t LogMemFree(void);
58 /* XModem callback */
59 bool LogMemLoadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount);
60 
61 void LogSetModeById(LogModeEnum Mode);
62 bool LogSetModeByName(const char* Mode);
63 void LogGetModeByName(char* Mode, uint16_t BufferSize);
64 void LogGetModeList(char* List, uint16_t BufferSize);
65 void LogSRAMToFRAM(void);
66 
67 /* Wrapper function to call current logging function */
68 INLINE void LogEntry(LogEntryEnum Entry, const void* Data, uint8_t Length) { CurrentLogFunc(Entry, Data, Length); }
69 
70 #endif /* LOG_H_ */
Application processed authentication command.
Definition: Log.h:30
+
Application authentication failed.
Definition: Log.h:35
+
Application is in auth state.
Definition: Log.h:34
+
Application processed increment command.
Definition: Log.h:26
+
Currently active codec sent data.
Definition: Log.h:21
+
UID change.
Definition: Log.h:16
+
Empty Log Entry. This is not followed by a length byte nor the two systick bytes nor any data...
Definition: Log.h:39
+
LogEntryEnum
Definition: Log.h:11
+
Currently active codec received data.
Definition: Log.h:20
+
Application processed write command.
Definition: Log.h:25
+
Application processed halt command.
Definition: Log.h:31
+
Application processed an unknown command.
Definition: Log.h:32
+
Application reset.
Definition: Log.h:17
+
Unspecific log entry.
Definition: Log.h:13
+
Application processed restore command.
Definition: Log.h:29
+
Application processed read command.
Definition: Log.h:24
+
Application had a checksum fail.
Definition: Log.h:36
+
Application processed transfer command.
Definition: Log.h:28
+
Setting change.
Definition: Log.h:15
+
Application is not authenticated.
Definition: Log.h:37
+
Application processed decrement command.
Definition: Log.h:27
+
Configuration change.
Definition: Log.h:14
+
Application is in authing state.
Definition: Log.h:33
+
+ + + + diff --git a/Doc/Doxygen/html/_log_8txt.html b/Doc/Doxygen/html/_log_8txt.html new file mode 100644 index 00000000..d0755857 --- /dev/null +++ b/Doc/Doxygen/html/_log_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: Log.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
Log.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_main_page_8txt.html b/Doc/Doxygen/html/_main_page_8txt.html new file mode 100644 index 00000000..4e79484a --- /dev/null +++ b/Doc/Doxygen/html/_main_page_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: MainPage.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
MainPage.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_map_8h_source.html b/Doc/Doxygen/html/_map_8h_source.html new file mode 100644 index 00000000..82ec57aa --- /dev/null +++ b/Doc/Doxygen/html/_map_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Map.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Map.h
+
+
+
1 /*
2  * Map.h
3  *
4  * Created on: 07.12.2014
5  * Author: sk
6  */
7 
8 #ifndef MAP_H_
9 #define MAP_H_
10 
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include <avr/pgmspace.h>
14 
15 #define MAP_TEXT_BUF_SIZE 32
16 #define MAP_MAX_TEXT_SIZE (MAP_TEXT_BUF_SIZE - 1)
17 
18 typedef uint8_t MapIdType;
19 typedef const char* MapTextPtrType;
20 
21 const typedef struct {
22  MapIdType Id;
23  const char Text[MAP_TEXT_BUF_SIZE];
24 } MapEntryType;
25 
26 bool MapIdToText(const MapEntryType* MapPtr, uint8_t MapSize, MapIdType Id, char* Text, uint16_t MaxBufferSize);
27 bool MapTextToId(const MapEntryType* MapPtr, uint8_t MapSize, MapTextPtrType Text, MapIdType* IdPtr);
28 void MapToString(const MapEntryType* MapPtr, uint8_t MapSize, char* String, uint16_t MaxBufferSize);
29 
30 #endif /* MAP_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_memory_8h_source.html b/Doc/Doxygen/html/_memory_8h_source.html new file mode 100644 index 00000000..da80ced8 --- /dev/null +++ b/Doc/Doxygen/html/_memory_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Memory.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Memory.h
+
+
+
1 /*
2  * Flash.h
3  *
4  * Created on: 20.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef MEMORY_H_
9 #define MEMORY_H_
10 
11 #define MEMORY_SIZE (FLASH_DATA_SIZE) /* From makefile */
12 #define MEMORY_INIT_VALUE 0x00
13 #define MEMORY_SIZE_PER_SETTING 8192
14 
15 #ifndef __ASSEMBLER__
16 #include "Common.h"
17 
18 void MemoryInit(void);
19 void MemoryReadBlock(void* Buffer, uint16_t Address, uint16_t ByteCount);
20 void MemoryWriteBlock(const void* Buffer, uint16_t Address, uint16_t ByteCount);
21 void MemoryClear(void);
22 
23 
24 void MemoryRecall(void);
25 void MemoryStore(void);
26 
27 /* For use with XModem */
28 bool MemoryUploadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount);
29 bool MemoryDownloadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount);
30 
31 #endif /* __ASSEMBLER__ */
32 
33 #endif /* MEMORY_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_mifare_classic_8h_source.html b/Doc/Doxygen/html/_mifare_classic_8h_source.html new file mode 100644 index 00000000..9b7d1bdf --- /dev/null +++ b/Doc/Doxygen/html/_mifare_classic_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: MifareClassic.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
MifareClassic.h
+
+
+
1 /*
2  * MifareClassic.h
3  *
4  * Created on: 13.05.2013
5  * Author: skuser
6  */
7 
8 #ifndef MIFARECLASSIC_H_
9 #define MIFARECLASSIC_H_
10 
11 #include "Application.h"
12 #include "ISO14443-3A.h"
13 
14 #define MIFARE_CLASSIC_UID_SIZE ISO14443A_UID_SIZE_SINGLE
15 #define MIFARE_CLASSIC_1K_MEM_SIZE 1024
16 #define MIFARE_CLASSIC_4K_MEM_SIZE 4096
17 
18 void MifareClassicAppInit1K(void);
19 void MifareClassicAppInit4K(void);
20 void MifareClassicAppReset(void);
21 void MifareClassicAppTask(void);
22 
23 uint16_t MifareClassicAppProcess(uint8_t* Buffer, uint16_t BitCount);
24 
25 void MifareClassicGetUid(ConfigurationUidType Uid);
26 void MifareClassicSetUid(ConfigurationUidType Uid);
27 
28 
29 #endif /* MIFARECLASSIC_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_mifare_ultralight_8h_source.html b/Doc/Doxygen/html/_mifare_ultralight_8h_source.html new file mode 100644 index 00000000..cf6631ef --- /dev/null +++ b/Doc/Doxygen/html/_mifare_ultralight_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: MifareUltralight.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
MifareUltralight.h
+
+
+
1 /*
2  * MifareUltralight.h
3  *
4  * Created on: 20.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef MIFAREULTRALIGHT_H_
9 #define MIFAREULTRALIGHT_H_
10 
11 #include "Application.h"
12 #include "ISO14443-3A.h"
13 
14 #define MIFARE_ULTRALIGHT_UID_SIZE ISO14443A_UID_SIZE_DOUBLE
15 #define MIFARE_ULTRALIGHT_MEM_SIZE 64
16 
17 void MifareUltralightAppInit(void);
18 void MifareUltralightAppReset(void);
19 void MifareUltralightAppTask(void);
20 
21 uint16_t MifareUltralightAppProcess(uint8_t* Buffer, uint16_t BitCount);
22 
23 void MifareUltralightGetUid(ConfigurationUidType Uid);
24 void MifareUltralightSetUid(ConfigurationUidType Uid);
25 
26 
27 
28 #endif /* MIFAREULTRALIGHT_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_random_8h_source.html b/Doc/Doxygen/html/_random_8h_source.html new file mode 100644 index 00000000..2335faee --- /dev/null +++ b/Doc/Doxygen/html/_random_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Random.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Random.h
+
+
+
1 /*
2  * Random.h
3  *
4  * Created on: 22.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef RANDOM_H_
9 #define RANDOM_H_
10 
11 #include "Common.h"
12 
13 void RandomInit(void);
14 uint8_t RandomGetByte(void);
15 void RandomGetBuffer(void* Buffer, uint8_t ByteCount);
16 void RandomTick(void);
17 
18 #endif /* RANDOM_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_reader14443-2_a_8h_source.html b/Doc/Doxygen/html/_reader14443-2_a_8h_source.html new file mode 100644 index 00000000..42a2e95b --- /dev/null +++ b/Doc/Doxygen/html/_reader14443-2_a_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Reader14443-2A.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Reader14443-2A.h
+
+
+
1 /*
2  * Reader14443-2A.h
3  *
4  * Created on: 26.08.2014
5  * Author: sk
6  */
7 
8 #ifndef READER14443_2A_H_
9 #define READER14443_2A_H_
10 
11 #include "Codec.h"
12 #include "Terminal/CommandLine.h"
13 
14 /* Codec Interface */
15 void Reader14443ACodecInit(void);
16 void Reader14443ACodecDeInit(void);
17 void Reader14443ACodecTask(void);
18 
19 /* Application Interface */
20 void Reader14443ACodecStart(void);
21 void Reader14443ACodecReset(void);
22 
23 #endif /* READER14443_2A_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_reader14443_a_8h_source.html b/Doc/Doxygen/html/_reader14443_a_8h_source.html new file mode 100644 index 00000000..5085f8db --- /dev/null +++ b/Doc/Doxygen/html/_reader14443_a_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Reader14443A.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Reader14443A.h
+
+
+
1 #ifndef READER14443A_H
2 #define READER14443A_H
3 
4 #include "Application.h"
5 #include "Codec/Codec.h"
6 
7 #define CRC_INIT 0x6363
8 
9 uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE];
10 uint16_t ReaderSendBitCount;
11 
12 void Reader14443AAppInit(void);
13 void Reader14443AAppReset(void);
14 void Reader14443AAppTask(void);
15 void Reader14443AAppTick(void);
16 void Reader14443AAppTimeout(void);
17 
18 uint16_t Reader14443AAppProcess(uint8_t* Buffer, uint16_t BitCount);
19 
20 uint16_t addParityBits(uint8_t * Buffer, uint16_t bits);
21 uint16_t removeParityBits(uint8_t * Buffer, uint16_t BitCount);
22 uint16_t removeSOC(uint8_t * Buffer, uint16_t BitCount);
23 bool checkParityBits(uint8_t * Buffer, uint16_t BitCount);
24 uint16_t ISO14443_CRCA(uint8_t * Buffer, uint8_t ByteCount);
25 
26 typedef enum {
27  Reader14443_Do_Nothing,
28  Reader14443_Send,
29  Reader14443_Send_Raw,
30  Reader14443_Get_UID,
31  Reader14443_Read_MF_Ultralight,
32  Reader14443_Indentify
33 } Reader14443Command;
34 
35 
36 #endif //READER14443A_H
+ + + + diff --git a/Doc/Doxygen/html/_reader_8txt.html b/Doc/Doxygen/html/_reader_8txt.html new file mode 100644 index 00000000..1e24fd25 --- /dev/null +++ b/Doc/Doxygen/html/_reader_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: Reader.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
Reader.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_settings_8h.html b/Doc/Doxygen/html/_settings_8h.html new file mode 100644 index 00000000..f6918a34 --- /dev/null +++ b/Doc/Doxygen/html/_settings_8h.html @@ -0,0 +1,115 @@ + + + + + + +Chameleon-Mini: Settings.h File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
Settings.h File Reference
+
+
+
#include "Button.h"
+#include "Configuration.h"
+#include "Log.h"
+#include "LED.h"
+#include "Memory.h"
+
+

Go to the source code of this file.

+ + + + +

+Classes

struct  SettingsEntryType
 
+
+ + + + diff --git a/Doc/Doxygen/html/_settings_8h_source.html b/Doc/Doxygen/html/_settings_8h_source.html new file mode 100644 index 00000000..d292ed7d --- /dev/null +++ b/Doc/Doxygen/html/_settings_8h_source.html @@ -0,0 +1,108 @@ + + + + + + +Chameleon-Mini: Settings.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Settings.h
+
+
+Go to the documentation of this file.
1 /*
2  * Settings.h
3  *
4  * Created on: 21.12.2013
5  * Author: skuser
6  */
8 #ifndef SETTINGS_H_
9 #define SETTINGS_H_
10 
11 #include "Button.h"
12 #include "Configuration.h"
13 #include "Log.h"
14 #include "LED.h"
15 #include "Memory.h"
16 
17 #define SETTINGS_COUNT (MEMORY_SIZE / MEMORY_SIZE_PER_SETTING)
18 #define SETTINGS_FIRST 1
19 #define SETTINGS_LAST (SETTINGS_FIRST + SETTINGS_COUNT - 1)
20 
25 typedef struct {
26  ButtonActionEnum ButtonActions[BUTTON_TYPE_COUNT];
27  LogModeEnum LogMode;
28  ConfigurationEnum Configuration;
29  LEDHookEnum LEDRedFunction;
30  LEDHookEnum LEDGreenFunction;
31  uint16_t PendingTaskTimeout;
33 
34 typedef struct {
35  uint8_t ActiveSettingIdx;
36  SettingsEntryType* ActiveSettingPtr;
37  SettingsEntryType Settings[SETTINGS_COUNT];
38 } SettingsType;
39 
40 extern SettingsType GlobalSettings;
41 
42 void SettingsLoad(void);
43 void SettingsSave(void);
44 
45 void SettingsCycle(void);
46 bool SettingsSetActiveById(uint8_t Setting);
47 uint8_t SettingsGetActiveById(void);
48 void SettingsGetActiveByName(char* SettingOut, uint16_t BufferSize);
49 bool SettingsSetActiveByName(const char* Setting);
50 
51 #endif /* SETTINGS_H_ */
LogModeEnum LogMode
Button actions for this setting.
Definition: Settings.h:27
+ +
Definition: Settings.h:25
+
LEDHookEnum LEDGreenFunction
Red LED function for this setting.
Definition: Settings.h:30
+
uint16_t PendingTaskTimeout
Green LED function for this setting.
Definition: Settings.h:31
+
ConfigurationEnum Configuration
Log mode for this setting.
Definition: Settings.h:28
+
LEDHookEnum LEDRedFunction
Active configuration for this setting.
Definition: Settings.h:29
+ +
+ + + + diff --git a/Doc/Doxygen/html/_settings_8txt.html b/Doc/Doxygen/html/_settings_8txt.html new file mode 100644 index 00000000..1172c17a --- /dev/null +++ b/Doc/Doxygen/html/_settings_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: Settings.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
Settings.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_system_8h_source.html b/Doc/Doxygen/html/_system_8h_source.html new file mode 100644 index 00000000..7cfa735d --- /dev/null +++ b/Doc/Doxygen/html/_system_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: System.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
System.h
+
+
+
1 /*
2  * System.h
3  *
4  * Created on: 10.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef SYSTEM_H
9 #define SYSTEM_H
10 
11 #include <avr/io.h>
12 #include <avr/pgmspace.h>
13 #include <avr/interrupt.h>
14 #include <stddef.h>
15 #include <stdbool.h>
16 #include "Common.h"
17 
18 #define F_RTC 1000
19 #define SYSTEM_MILLISECONDS_TO_RTC_CYCLES(x) \
20  ( (uint16_t) ( (double) F_RTC * x / 1E3 + 0.5) )
21 
22 #define SYSTEM_TICK_WIDTH 7 /* Bits */
23 #define SYSTEM_TICK_PERIOD (1<<7)
24 #define SYSTEM_TICK_MS (SYSTEM_TICK_PERIOD)
25 #define SYSTEM_TICK_FREQ (1000 / SYSTEM_TICK_PERIOD)
26 
27 #define SYSTEM_SMODE_PSAVE SLEEP_SMODE_PSAVE_gc
28 #define SYSTEM_SMODE_IDLE SLEEP_SMODE_IDLE_gc
29 
30 /* Use GPIORE and GPIORF as global tick register */
31 #define SYSTEM_TICK_REGISTER (*((volatile uint16_t*) &GPIORE))
32 
33 void SystemInit(void);
34 void SystemReset(void);
35 void SystemEnterBootloader(void);
36 void SystemStartUSBClock(void);
37 void SystemStopUSBClock(void);
38 void SystemInterruptInit(void);
39 INLINE bool SystemTick100ms(void);
40 
41 INLINE bool SystemTick100ms(void)
42 {
43  if (RTC.INTFLAGS & RTC_COMPIF_bm) {
44  while(RTC.STATUS & RTC_SYNCBUSY_bm)
45  ;
46 
47  RTC.INTFLAGS = RTC_COMPIF_bm;
48  return true;
49  }
50 
51  return false;
52 }
53 
54 INLINE uint16_t SystemGetSysTick(void) {
55  return SYSTEM_TICK_REGISTER | RTC.CNT;
56 }
57 
58 #endif /* SYSTEM_H */
+ + + + diff --git a/Doc/Doxygen/html/_terminal_8h_source.html b/Doc/Doxygen/html/_terminal_8h_source.html new file mode 100644 index 00000000..d0eac08e --- /dev/null +++ b/Doc/Doxygen/html/_terminal_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Terminal.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Terminal.h
+
+
+
1 /*
2  * CommandLine.h
3  *
4  * Created on: 10.02.2013
5  * Author: skuser
6  */
7 
8 #ifndef TERMINAL_H_
9 #define TERMINAL_H_
10 
11 #include "../Common.h"
12 #include "../LUFA/Drivers/USB/USB.h"
13 #include "XModem.h"
14 #include "CommandLine.h"
15 
16 #define TERMINAL_VBUS_PORT PORTD
17 #define TERMINAL_VBUS_MASK PIN5_bm
18 
19 #define TERMINAL_BUFFER_SIZE 512
20 
21 typedef enum {
22  TERMINAL_UNINITIALIZED,
23  TERMINAL_INITIALIZING,
24  TERMINAL_INITIALIZED,
25  TERMINAL_UNITIALIZING
26 } TerminalStateEnum;
27 
28 extern uint8_t TerminalBuffer[TERMINAL_BUFFER_SIZE];
29 extern USB_ClassInfo_CDC_Device_t TerminalHandle;
30 extern TerminalStateEnum TerminalState;
31 
32 void TerminalInit(void);
33 void TerminalTask(void);
34 void TerminalTick(void);
35 
36 /*void TerminalSendHex(void* Buffer, uint16_t ByteCount);*/
37 INLINE void TerminalSendByte(uint8_t Byte);
38 void TerminalSendBlock(const void* Buffer, uint16_t ByteCount);
39 
40 INLINE void TerminalSendChar(char c);
41 void TerminalSendString(const char* s);
42 void TerminalSendStringP(const char* s);
43 
44 void EVENT_USB_Device_Connect(void);
45 void EVENT_USB_Device_Disconnect(void);
46 void EVENT_USB_Device_ConfigurationChanged(void);
47 void EVENT_USB_Device_ControlRequest(void);
48 
49 INLINE void TerminalSendChar(char c) { CDC_Device_SendByte(&TerminalHandle, c); }
50 INLINE void TerminalSendByte(uint8_t Byte) { CDC_Device_SendByte(&TerminalHandle, Byte); }
51 
52 #endif /* TERMINAL_H_ */
+ + + + diff --git a/Doc/Doxygen/html/_uploading_downloading_8txt.html b/Doc/Doxygen/html/_uploading_downloading_8txt.html new file mode 100644 index 00000000..caa1ad0d --- /dev/null +++ b/Doc/Doxygen/html/_uploading_downloading_8txt.html @@ -0,0 +1,96 @@ + + + + + + +Chameleon-Mini: UploadingDownloading.txt File Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
UploadingDownloading.txt File Reference
+
+
+
+ + + + diff --git a/Doc/Doxygen/html/_x_modem_8h_source.html b/Doc/Doxygen/html/_x_modem_8h_source.html new file mode 100644 index 00000000..9d50af09 --- /dev/null +++ b/Doc/Doxygen/html/_x_modem_8h_source.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: XModem.h Source File + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
XModem.h
+
+
+
1 /*
2  * TerminalXModem.h
3  *
4  * Created on: 22.03.2013
5  * Author: skuser
6  */
7 
8 #ifndef XMODEM_H_
9 #define XMODEM_H_
10 
11 #include "../Common.h"
12 
13 typedef bool (*XModemCallbackType) (void* ByteBuffer, uint32_t BlockAddress, uint16_t ByteCount);
14 
15 void XModemReceive(XModemCallbackType CallbackFunc);
16 void XModemSend(XModemCallbackType CallbackFunc);
17 
18 bool XModemProcessByte(uint8_t Byte);
19 void XModemTick(void);
20 
21 #endif /* TERMINALXMODEM_H_ */
+ + + + diff --git a/Doc/Doxygen/html/annotated.html b/Doc/Doxygen/html/annotated.html new file mode 100644 index 00000000..f8e32532 --- /dev/null +++ b/Doc/Doxygen/html/annotated.html @@ -0,0 +1,104 @@ + + + + + + +Chameleon-Mini: Class List + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class List
+
+
+
Here are the classes, structs, unions and interfaces with brief descriptions:
+
+ + + + diff --git a/Doc/Doxygen/html/arrowdown.png b/Doc/Doxygen/html/arrowdown.png new file mode 100644 index 00000000..0b63f6d3 Binary files /dev/null and b/Doc/Doxygen/html/arrowdown.png differ diff --git a/Doc/Doxygen/html/arrowright.png b/Doc/Doxygen/html/arrowright.png new file mode 100644 index 00000000..c6ee22f9 Binary files /dev/null and b/Doc/Doxygen/html/arrowright.png differ diff --git a/Doc/Doxygen/html/bc_s.png b/Doc/Doxygen/html/bc_s.png new file mode 100644 index 00000000..224b29aa Binary files /dev/null and b/Doc/Doxygen/html/bc_s.png differ diff --git a/Doc/Doxygen/html/bdwn.png b/Doc/Doxygen/html/bdwn.png new file mode 100644 index 00000000..940a0b95 Binary files /dev/null and b/Doc/Doxygen/html/bdwn.png differ diff --git a/Doc/Doxygen/html/classes.html b/Doc/Doxygen/html/classes.html new file mode 100644 index 00000000..fe40ff4b --- /dev/null +++ b/Doc/Doxygen/html/classes.html @@ -0,0 +1,108 @@ + + + + + + +Chameleon-Mini: Class Index + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class Index
+
+
+
C | S | U
+ + + + + +
  C  
+
  S  
+
  U  
+
ConfigurationType   SettingsEntryType   USB_Descriptor_Configuration_t   
+
C | S | U
+
+ + + + diff --git a/Doc/Doxygen/html/closed.png b/Doc/Doxygen/html/closed.png new file mode 100644 index 00000000..98cc2c90 Binary files /dev/null and b/Doc/Doxygen/html/closed.png differ diff --git a/Doc/Doxygen/html/dir_5de29d499bb29a41092979d00d22c134.html b/Doc/Doxygen/html/dir_5de29d499bb29a41092979d00d22c134.html new file mode 100644 index 00000000..d4b3384f --- /dev/null +++ b/Doc/Doxygen/html/dir_5de29d499bb29a41092979d00d22c134.html @@ -0,0 +1,104 @@ + + + + + + +Chameleon-Mini: Application Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Application Directory Reference
+
+
+ + +

+Files

+
+ + + + diff --git a/Doc/Doxygen/html/dir_74b6a3b63f61c160c0f14b7a283a4c9b.html b/Doc/Doxygen/html/dir_74b6a3b63f61c160c0f14b7a283a4c9b.html new file mode 100644 index 00000000..e34bf7c9 --- /dev/null +++ b/Doc/Doxygen/html/dir_74b6a3b63f61c160c0f14b7a283a4c9b.html @@ -0,0 +1,104 @@ + + + + + + +Chameleon-Mini: Firmware Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Firmware Directory Reference
+
+
+ + +

+Directories

+
+ + + + diff --git a/Doc/Doxygen/html/dir_8465ec698d237f801ae9966d4551fcfa.html b/Doc/Doxygen/html/dir_8465ec698d237f801ae9966d4551fcfa.html new file mode 100644 index 00000000..06f8f177 --- /dev/null +++ b/Doc/Doxygen/html/dir_8465ec698d237f801ae9966d4551fcfa.html @@ -0,0 +1,120 @@ + + + + + + +Chameleon-Mini: Chameleon-Mini Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Chameleon-Mini Directory Reference
+
+
+ + +

+Directories

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

+Files

file  Configuration.h [code]
 
file  Log.h [code]
 
file  LUFAConfig.h [code]
 LUFA Library Configuration Header File.
 
file  LUFADescriptors.c
 
file  LUFADescriptors.h [code]
 
file  Settings.h [code]
 
+
+ + + + diff --git a/Doc/Doxygen/html/dir_ddeffaa734f77525428b0dd4068da9cb.html b/Doc/Doxygen/html/dir_ddeffaa734f77525428b0dd4068da9cb.html new file mode 100644 index 00000000..6ac2d34b --- /dev/null +++ b/Doc/Doxygen/html/dir_ddeffaa734f77525428b0dd4068da9cb.html @@ -0,0 +1,104 @@ + + + + + + +Chameleon-Mini: Terminal Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Terminal Directory Reference
+
+
+ + +

+Files

+
+ + + + diff --git a/Doc/Doxygen/html/dir_f5aab302412c0352d69464400cc5ee44.html b/Doc/Doxygen/html/dir_f5aab302412c0352d69464400cc5ee44.html new file mode 100644 index 00000000..84faa446 --- /dev/null +++ b/Doc/Doxygen/html/dir_f5aab302412c0352d69464400cc5ee44.html @@ -0,0 +1,104 @@ + + + + + + +Chameleon-Mini: Codec Directory Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Codec Directory Reference
+
+
+ + +

+Files

+
+ + + + diff --git a/Doc/Doxygen/html/doc.png b/Doc/Doxygen/html/doc.png new file mode 100644 index 00000000..17edabff Binary files /dev/null and b/Doc/Doxygen/html/doc.png differ diff --git a/Doc/Doxygen/html/doxygen.css b/Doc/Doxygen/html/doxygen.css new file mode 100644 index 00000000..1425ec53 --- /dev/null +++ b/Doc/Doxygen/html/doxygen.css @@ -0,0 +1,1475 @@ +/* The standard CSS for doxygen 1.8.11 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 4px 6px; + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: bold; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #ffffff; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #ffffff; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + diff --git a/Doc/Doxygen/html/doxygen.png b/Doc/Doxygen/html/doxygen.png new file mode 100644 index 00000000..3ff17d80 Binary files /dev/null and b/Doc/Doxygen/html/doxygen.png differ diff --git a/Doc/Doxygen/html/dynsections.js b/Doc/Doxygen/html/dynsections.js new file mode 100644 index 00000000..85e18369 --- /dev/null +++ b/Doc/Doxygen/html/dynsections.js @@ -0,0 +1,97 @@ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + +Chameleon-Mini: File List + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 AntennaLevel.h
 Application.h
 Battery.h
 Button.h
 Chameleon-Mini.h
 Codec.h
 CommandLine.h
 Commands.h
 Common.h
 Configuration.h
 Crypto1.h
 ISO14443-2A.h
 ISO14443-3A.h
 LED.h
 LEDHook.h
 Log.h
 LUFAConfig.hLUFA Library Configuration Header File
 LUFADescriptors.c
 LUFADescriptors.h
 Map.h
 Memory.h
 MifareClassic.h
 MifareUltralight.h
 Random.h
 Reader14443-2A.h
 Reader14443A.h
 Settings.h
 System.h
 Terminal.h
 XModem.h
+
+
+ + + + diff --git a/Doc/Doxygen/html/folderclosed.png b/Doc/Doxygen/html/folderclosed.png new file mode 100644 index 00000000..bb8ab35e Binary files /dev/null and b/Doc/Doxygen/html/folderclosed.png differ diff --git a/Doc/Doxygen/html/folderopen.png b/Doc/Doxygen/html/folderopen.png new file mode 100644 index 00000000..d6c7f676 Binary files /dev/null and b/Doc/Doxygen/html/folderopen.png differ diff --git a/Doc/Doxygen/html/functions.html b/Doc/Doxygen/html/functions.html new file mode 100644 index 00000000..ce418ee3 --- /dev/null +++ b/Doc/Doxygen/html/functions.html @@ -0,0 +1,155 @@ + + + + + + +Chameleon-Mini: Class Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+
+ + + + diff --git a/Doc/Doxygen/html/functions_vars.html b/Doc/Doxygen/html/functions_vars.html new file mode 100644 index 00000000..912eab57 --- /dev/null +++ b/Doc/Doxygen/html/functions_vars.html @@ -0,0 +1,155 @@ + + + + + + +Chameleon-Mini: Class Members - Variables + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
+
+ + + + diff --git a/Doc/Doxygen/html/globals.html b/Doc/Doxygen/html/globals.html new file mode 100644 index 00000000..05f30833 --- /dev/null +++ b/Doc/Doxygen/html/globals.html @@ -0,0 +1,234 @@ + + + + + + +Chameleon-Mini: File Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented file members with links to the documentation:
+ +

- c -

+ + +

- d -

+ + +

- l -

    +
  • LanguageString +: LUFADescriptors.c +
  • +
  • LOG_EMPTY +: Log.h +
  • +
  • LOG_ERR_APP_AUTH_FAIL +: Log.h +
  • +
  • LOG_ERR_APP_CHECKSUM_FAIL +: Log.h +
  • +
  • LOG_ERR_APP_NOT_AUTHED +: Log.h +
  • +
  • LOG_INFO_APP_AUTHED +: Log.h +
  • +
  • LOG_INFO_APP_AUTHING +: Log.h +
  • +
  • LOG_INFO_APP_CMD_AUTH +: Log.h +
  • +
  • LOG_INFO_APP_CMD_DEC +: Log.h +
  • +
  • LOG_INFO_APP_CMD_HALT +: Log.h +
  • +
  • LOG_INFO_APP_CMD_INC +: Log.h +
  • +
  • LOG_INFO_APP_CMD_READ +: Log.h +
  • +
  • LOG_INFO_APP_CMD_RESTORE +: Log.h +
  • +
  • LOG_INFO_APP_CMD_TRANSFER +: Log.h +
  • +
  • LOG_INFO_APP_CMD_UNKNOWN +: Log.h +
  • +
  • LOG_INFO_APP_CMD_WRITE +: Log.h +
  • +
  • LOG_INFO_CODEC_RX_DATA +: Log.h +
  • +
  • LOG_INFO_CODEC_TX_DATA +: Log.h +
  • +
  • LOG_INFO_CONFIG_SET +: Log.h +
  • +
  • LOG_INFO_GENERIC +: Log.h +
  • +
  • LOG_INFO_RESET_APP +: Log.h +
  • +
  • LOG_INFO_SETTING_SET +: Log.h +
  • +
  • LOG_INFO_UID_SET +: Log.h +
  • +
  • LogEntryEnum +: Log.h +
  • +
+ + +

- m -

+ + +

- p -

+
+ + + + diff --git a/Doc/Doxygen/html/globals_defs.html b/Doc/Doxygen/html/globals_defs.html new file mode 100644 index 00000000..dfc81943 --- /dev/null +++ b/Doc/Doxygen/html/globals_defs.html @@ -0,0 +1,119 @@ + + + + + + +Chameleon-Mini: File Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
+
+ + + + diff --git a/Doc/Doxygen/html/globals_enum.html b/Doc/Doxygen/html/globals_enum.html new file mode 100644 index 00000000..d6557fc9 --- /dev/null +++ b/Doc/Doxygen/html/globals_enum.html @@ -0,0 +1,107 @@ + + + + + + +Chameleon-Mini: File Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
    +
  • LogEntryEnum +: Log.h +
  • +
+
+ + + + diff --git a/Doc/Doxygen/html/globals_eval.html b/Doc/Doxygen/html/globals_eval.html new file mode 100644 index 00000000..974f1c83 --- /dev/null +++ b/Doc/Doxygen/html/globals_eval.html @@ -0,0 +1,170 @@ + + + + + + +Chameleon-Mini: File Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
    +
  • LOG_EMPTY +: Log.h +
  • +
  • LOG_ERR_APP_AUTH_FAIL +: Log.h +
  • +
  • LOG_ERR_APP_CHECKSUM_FAIL +: Log.h +
  • +
  • LOG_ERR_APP_NOT_AUTHED +: Log.h +
  • +
  • LOG_INFO_APP_AUTHED +: Log.h +
  • +
  • LOG_INFO_APP_AUTHING +: Log.h +
  • +
  • LOG_INFO_APP_CMD_AUTH +: Log.h +
  • +
  • LOG_INFO_APP_CMD_DEC +: Log.h +
  • +
  • LOG_INFO_APP_CMD_HALT +: Log.h +
  • +
  • LOG_INFO_APP_CMD_INC +: Log.h +
  • +
  • LOG_INFO_APP_CMD_READ +: Log.h +
  • +
  • LOG_INFO_APP_CMD_RESTORE +: Log.h +
  • +
  • LOG_INFO_APP_CMD_TRANSFER +: Log.h +
  • +
  • LOG_INFO_APP_CMD_UNKNOWN +: Log.h +
  • +
  • LOG_INFO_APP_CMD_WRITE +: Log.h +
  • +
  • LOG_INFO_CODEC_RX_DATA +: Log.h +
  • +
  • LOG_INFO_CODEC_TX_DATA +: Log.h +
  • +
  • LOG_INFO_CONFIG_SET +: Log.h +
  • +
  • LOG_INFO_GENERIC +: Log.h +
  • +
  • LOG_INFO_RESET_APP +: Log.h +
  • +
  • LOG_INFO_SETTING_SET +: Log.h +
  • +
  • LOG_INFO_UID_SET +: Log.h +
  • +
+
+ + + + diff --git a/Doc/Doxygen/html/globals_func.html b/Doc/Doxygen/html/globals_func.html new file mode 100644 index 00000000..59c2c5fe --- /dev/null +++ b/Doc/Doxygen/html/globals_func.html @@ -0,0 +1,108 @@ + + + + + + +Chameleon-Mini: File Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
+
+ + + + diff --git a/Doc/Doxygen/html/globals_vars.html b/Doc/Doxygen/html/globals_vars.html new file mode 100644 index 00000000..421f19a4 --- /dev/null +++ b/Doc/Doxygen/html/globals_vars.html @@ -0,0 +1,119 @@ + + + + + + +Chameleon-Mini: File Members + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+ +
+
+ + +
+ +
+ +
+
+ + + + diff --git a/Doc/Doxygen/html/index.html b/Doc/Doxygen/html/index.html new file mode 100644 index 00000000..bfff61f0 --- /dev/null +++ b/Doc/Doxygen/html/index.html @@ -0,0 +1,105 @@ + + + + + + +Chameleon-Mini: Main Page + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + +
+ +
+
+ + +
+ +
+ +
+
+
Chameleon-Mini Documentation
+
+
+

ChameleonMini, created by Kasper & Oswald, is a freely programmable, portable tool for ISO14443 / ISO15693 / NFC security analysis that can for example read out compatible transponders, emulate or clone contactless cards, and sniff/log the RFID communication. The versatile, battery operated device is designed to assess security aspects in RFID environments and can be used in different scenarios like relay or replay attacks, including state restoration, and for virtualizing up to eight smartcards that behave as perfect clones of the original, given card.

+

The Chameleon Project has been started by the Chair for Embedded Security at the Ruhr-University Bochum, Germany, and has been licensed as open source to let everyone benefit from the work. Meanwhile the inventors of ChameleonMini have founded the security consulting company Kasper & Oswald and now continue the hardware and firmware development.

+

We appreciate all types of contributions (for example hardware mods, firmware upgrades, bug fixes, new supported card types, videos, pictures, example applications, reviews, instructions, documentation, translations, new findings, ANYTHING...) and are happy to upload the stuff for you into the github project. Please send your contribution to chame.nosp@m.leon.nosp@m.@kasp.nosp@m.er-o.nosp@m.swald.nosp@m..de and we will (if desired) give you credit in the github log of the upload. Likewise, we are looking forward to your feedback about bugs, problems, and desired future upgrades. Please use the issues button accordingly.

+

Pages:

+ +
+ + + + diff --git a/Doc/Doxygen/html/jquery.js b/Doc/Doxygen/html/jquery.js new file mode 100644 index 00000000..d52a1c77 --- /dev/null +++ b/Doc/Doxygen/html/jquery.js @@ -0,0 +1,68 @@ +/* + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ +(function(bb,L){var av=bb.document,bu=bb.navigator,bl=bb.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bb.jQuery,bH=bb.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b40){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bb.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bb.attachEvent("onload",bF.ready);var b0=false;try{b0=bb.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0&&typeof b0==="object"&&"setInterval" in b0},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bb.JSON&&bb.JSON.parse){return bb.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){var b0,b1;try{if(bb.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bb.execScript||function(b1){bb["eval"].call(bb,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b40&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b21?aJ.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aJ.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv
a";bI=bv.getElementsByTagName("*");bF=bv.getElementsByTagName("a")[0];if(!bI||!bI.length||!bF){return{}}bG=av.createElement("select");bx=bG.appendChild(av.createElement("option"));bE=bv.getElementsByTagName("input")[0];bJ={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bF.getAttribute("style")),hrefNormalized:(bF.getAttribute("href")==="/a"),opacity:/^0.55/.test(bF.style.opacity),cssFloat:!!bF.style.cssFloat,checkOn:(bE.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true};bE.checked=true;bJ.noCloneChecked=bE.cloneNode(true).checked;bG.disabled=true;bJ.optDisabled=!bx.disabled;try{delete bv.test}catch(bC){bJ.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bJ.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bE=av.createElement("input");bE.value="t";bE.setAttribute("type","radio");bJ.radioValue=bE.value==="t";bE.setAttribute("checked","checked");bv.appendChild(bE);bD=av.createDocumentFragment();bD.appendChild(bv.lastChild);bJ.checkClone=bD.cloneNode(true).cloneNode(true).lastChild.checked;bJ.appendChecked=bE.checked;bD.removeChild(bE);bD.appendChild(bv);bv.innerHTML="";if(bb.getComputedStyle){bA=av.createElement("div");bA.style.width="0";bA.style.marginRight="0";bv.style.width="2px";bv.appendChild(bA);bJ.reliableMarginRight=(parseInt((bb.getComputedStyle(bA,null)||{marginRight:0}).marginRight,10)||0)===0}if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bB="on"+by;bw=(bB in bv);if(!bw){bv.setAttribute(bB,"return;");bw=(typeof bv[bB]==="function")}bJ[by+"Bubbles"]=bw}}bD.removeChild(bv);bD=bG=bx=bA=bv=bE=null;b(function(){var bM,bU,bV,bT,bN,bO,bL,bS,bR,e,bP,bQ=av.getElementsByTagName("body")[0];if(!bQ){return}bL=1;bS="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";bR="visibility:hidden;border:0;";e="style='"+bS+"border:5px solid #000;padding:0;'";bP="
";bM=av.createElement("div");bM.style.cssText=bR+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bQ.insertBefore(bM,bQ.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="
t
";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bJ.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);bv.innerHTML="";bv.style.width=bv.style.paddingLeft="1px";b.boxModel=bJ.boxModel=bv.offsetWidth===2;if(typeof bv.style.zoom!=="undefined"){bv.style.display="inline";bv.style.zoom=1;bJ.inlineBlockNeedsLayout=(bv.offsetWidth===2);bv.style.display="";bv.innerHTML="
";bJ.shrinkWrapBlocks=(bv.offsetWidth!==2)}bv.style.cssText=bS+bR;bv.innerHTML=bP;bU=bv.firstChild;bV=bU.firstChild;bN=bU.nextSibling.firstChild.firstChild;bO={doesNotAddBorder:(bV.offsetTop!==5),doesAddBorderForTableAndCells:(bN.offsetTop===5)};bV.style.position="fixed";bV.style.top="20px";bO.fixedPosition=(bV.offsetTop===20||bV.offsetTop===15);bV.style.position=bV.style.top="";bU.style.overflow="hidden";bU.style.position="relative";bO.subtractsBorderForOverflowNotVisible=(bV.offsetTop===-5);bO.doesNotIncludeMarginInBodyOffset=(bQ.offsetTop!==bL);bQ.removeChild(bM);bv=bM=null;b.extend(bJ,bO)});return bJ})();var aS=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.nodeName.toLowerCase()]||b.valHooks[bw.type];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aU,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.nodeName.toLowerCase()]||b.valHooks[this.type];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType;if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aY:be)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(bx,bz){var by,bA,bv,e,bw=0;if(bz&&bx.nodeType===1){bA=bz.toLowerCase().split(af);e=bA.length;for(;bw=0)}}})});var bd=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/\bhover(\.\S+)?\b/,aO=/^key/,bf=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bb,bI])}}for(bC=0;bCbA){bH.push({elem:this,matches:bz.slice(bA)})}for(bC=0;bC0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aO.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bf.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}}); +/* + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1},lt:function(bS,bR,e){return bRe[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="

";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="
";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT0){for(bB=bA;bB=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(C(bx[0])||C(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function C(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling(e.parentNode.firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||a9.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aG(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aR.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aR="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ag=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,w=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},ac=a(av);ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div
","
"]}b.fn.extend({text:function(e){if(b.isFunction(e)){return this.each(function(bw){var bv=b(this);bv.text(e.call(this,bw,bv.text()))})}if(typeof e!=="object"&&e!==L){return this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(e))}return b.text(this)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(bx){if(bx===L){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ag,""):null}else{if(typeof bx==="string"&&!ae.test(bx)&&(b.support.leadingWhitespace||!ar.test(bx))&&!ax[(d.exec(bx)||["",""])[1].toLowerCase()]){bx=bx.replace(R,"<$1>");try{for(var bw=0,bv=this.length;bw1&&bw0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bg(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function E(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function al(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||!ah.test("<"+by.nodeName)?by.cloneNode(true):al(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){ai(by,bz);e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){if(bv[bx]){ai(e[bx],bv[bx])}}}if(bA){t(by,bz);if(bw){e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){t(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bw,by,bH,bA){var bF;by=by||av;if(typeof by.createElement==="undefined"){by=by.ownerDocument||by[0]&&by[0].ownerDocument||av}var bI=[],bB;for(var bE=0,bz;(bz=bw[bE])!=null;bE++){if(typeof bz==="number"){bz+=""}if(!bz){continue}if(typeof bz==="string"){if(!W.test(bz)){bz=by.createTextNode(bz)}else{bz=bz.replace(R,"<$1>");var bK=(d.exec(bz)||["",""])[1].toLowerCase(),bx=ax[bK]||ax._default,bD=bx[0],bv=by.createElement("div");if(by===av){ac.appendChild(bv)}else{a(by).appendChild(bv)}bv.innerHTML=bx[1]+bz+bx[2];while(bD--){bv=bv.lastChild}if(!b.support.tbody){var e=w.test(bz),bC=bK==="table"&&!e?bv.firstChild&&bv.firstChild.childNodes:bx[1]===""&&!e?bv.childNodes:[];for(bB=bC.length-1;bB>=0;--bB){if(b.nodeName(bC[bB],"tbody")&&!bC[bB].childNodes.length){bC[bB].parentNode.removeChild(bC[bB])}}}if(!b.support.leadingWhitespace&&ar.test(bz)){bv.insertBefore(by.createTextNode(ar.exec(bz)[0]),bv.firstChild)}bz=bv.childNodes}}var bG;if(!b.support.appendChecked){if(bz[0]&&typeof(bG=bz.length)==="number"){for(bB=0;bB=0){return bx+"px"}}else{return bx}}}});if(!b.support.opacity){b.cssHooks.opacity={get:function(bv,e){return au.test((e&&bv.currentStyle?bv.currentStyle.filter:bv.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(by,bz){var bx=by.style,bv=by.currentStyle,e=b.isNumeric(bz)?"alpha(opacity="+bz*100+")":"",bw=bv&&bv.filter||bx.filter||"";bx.zoom=1;if(bz>=1&&b.trim(bw.replace(ak,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=ak.test(bw)?bw.replace(ak,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bw,bv){var e;b.swap(bw,{display:"inline-block"},function(){if(bv){e=Z(bw,"margin-right","marginRight")}else{e=bw.style.marginRight}});return e}}}});if(av.defaultView&&av.defaultView.getComputedStyle){aI=function(by,bw){var bv,bx,e;bw=bw.replace(z,"-$1").toLowerCase();if((bx=by.ownerDocument.defaultView)&&(e=bx.getComputedStyle(by,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(by.ownerDocument.documentElement,by)){bv=b.style(by,bw)}}return bv}}if(av.documentElement.currentStyle){aX=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv===null&&bx&&(by=bx[bw])){bv=by}if(!bc.test(bv)&&bn.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":(bv||0);bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aI||aX;function p(by,bw,bv){var bA=bw==="width"?by.offsetWidth:by.offsetHeight,bz=bw==="width"?an:a1,bx=0,e=bz.length;if(bA>0){if(bv!=="border"){for(;bx)<[^<]*)*<\/script>/gi,q=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,A=b.fn.load,aa={},r={},aE,s,aV=["*/"]+["*"];try{aE=bl.href}catch(aw){aE=av.createElement("a");aE.href="";aE=aE.href}s=K.exec(aE.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("
").append(bD.replace(a6,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||q.test(this.nodeName)||aZ.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){am(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}am(bv,e);return bv},ajaxSettings:{url:aE,isLocal:aM.test(s[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aV},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bb.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(r),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bj(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=G(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,s[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=s[1]||bI[2]!=s[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(s[3]||(s[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aW(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aQ.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aV+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aW(r,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){v(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function v(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{v(bw+"["+(typeof bz==="object"||b.isArray(bz)?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&by!=null&&typeof by==="object"){for(var e in by){v(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bj(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function G(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!a8){a8=av.createElement("iframe");a8.frameBorder=a8.width=a8.height=0}e.appendChild(a8);if(!m||!a8.createElement){m=(a8.contentWindow||a8.contentDocument).document;m.write((av.compatMode==="CSS1Compat"?"":"")+"");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(a8)}Q[bx]=bw}return Q[bx]}var V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){b.fn.offset=function(bI){var by=this[0],bB;if(bI){return this.each(function(e){b.offset.setOffset(this,bI,e)})}if(!by||!by.ownerDocument){return null}if(by===by.ownerDocument.body){return b.offset.bodyOffset(by)}try{bB=by.getBoundingClientRect()}catch(bF){}var bH=by.ownerDocument,bw=bH.documentElement;if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aK(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{b.fn.offset=function(bF){var bz=this[0];if(bF){return this.each(function(bG){b.offset.setOffset(this,bF,bG)})}if(!bz||!bz.ownerDocument){return null}if(bz===bz.ownerDocument.body){return b.offset.bodyOffset(bz)}var bC,bw=bz.offsetParent,bv=bz,bE=bz.ownerDocument,bx=bE.documentElement,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each(["Left","Top"],function(bv,e){var bw="scroll"+e;b.fn[bw]=function(bz){var bx,by;if(bz===L){bx=this[0];if(!bx){return null}by=aK(bx);return by?("pageXOffset" in by)?by[bv?"pageYOffset":"pageXOffset"]:b.support.boxModel&&by.document.documentElement[bw]||by.document.body[bw]:bx[bw]}return this.each(function(){by=aK(this);if(by){by.scrollTo(!bv?bz:b(by).scrollLeft(),bv?bz:b(by).scrollTop())}else{this[bw]=bz}})}});function aK(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each(["Height","Width"],function(bv,e){var bw=e.toLowerCase();b.fn["inner"+e]=function(){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,"padding")):this[bw]():null};b.fn["outer"+e]=function(by){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,by?"margin":"border")):this[bw]():null};b.fn[bw]=function(bz){var bA=this[0];if(!bA){return bz==null?null:this}if(b.isFunction(bz)){return this.each(function(bE){var bD=b(this);bD[bw](bz.call(this,bE,bD[bw]()))})}if(b.isWindow(bA)){var bB=bA.document.documentElement["client"+e],bx=bA.document.body;return bA.document.compatMode==="CSS1Compat"&&bB||bx&&bx["client"+e]||bB}else{if(bA.nodeType===9){return Math.max(bA.documentElement["client"+e],bA.body["scroll"+e],bA.documentElement["scroll"+e],bA.body["offset"+e],bA.documentElement["offset"+e])}else{if(bz===L){var bC=b.css(bA,bw),by=parseFloat(bC);return b.isNumeric(by)?by:bC}else{return this.css(bw,typeof bz==="string"?bz:bz+"px")}}}}});bb.jQuery=bb.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b})}})(window);/* + * jQuery UI 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/* + * jQuery UI Widget 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/* + * jQuery UI Mouse 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Mouse + * + * Depends: + * jquery.ui.widget.js + */ +(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('
').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g
');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null;p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/* + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$(' + + +
+
+
Related Pages
+
+
+
Here is a list of all related documentation pages:
+
+ +
 LED functionality
+ + + + + + diff --git a/Doc/Doxygen/html/search/all_0.html b/Doc/Doxygen/html/search/all_0.html new file mode 100644 index 00000000..d54e0bd8 --- /dev/null +++ b/Doc/Doxygen/html/search/all_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_0.js b/Doc/Doxygen/html/search/all_0.js new file mode 100644 index 00000000..fa97c116 --- /dev/null +++ b/Doc/Doxygen/html/search/all_0.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['applicationgetuidfunc',['ApplicationGetUidFunc',['../struct_configuration_type.html#a9d31886f03ebf75d59611b7dbe81aeca',1,'ConfigurationType']]], + ['applicationinitfunc',['ApplicationInitFunc',['../struct_configuration_type.html#a835db40b131727b32d732585e8984d4a',1,'ConfigurationType']]], + ['applicationprocessfunc',['ApplicationProcessFunc',['../struct_configuration_type.html#a12036017f3f9e7a0c6a168539e262571',1,'ConfigurationType']]], + ['applicationresetfunc',['ApplicationResetFunc',['../struct_configuration_type.html#abcb24589b62d04a8aa3e7d129e87e239',1,'ConfigurationType']]], + ['applicationsetuidfunc',['ApplicationSetUidFunc',['../struct_configuration_type.html#afd1eeffbd4b0aeab57449e57f67cd400',1,'ConfigurationType']]], + ['applicationtaskfunc',['ApplicationTaskFunc',['../struct_configuration_type.html#a9e695aaf0fd0bb6e5165b23c654e9346',1,'ConfigurationType']]], + ['applicationtickfunc',['ApplicationTickFunc',['../struct_configuration_type.html#a902e157e8657cd7bb2ef5211c1a6bc58',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/search/all_1.html b/Doc/Doxygen/html/search/all_1.html new file mode 100644 index 00000000..8cc6a1de --- /dev/null +++ b/Doc/Doxygen/html/search/all_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_1.js b/Doc/Doxygen/html/search/all_1.js new file mode 100644 index 00000000..c0bce830 --- /dev/null +++ b/Doc/Doxygen/html/search/all_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['buttons_2etxt',['Buttons.txt',['../_buttons_8txt.html',1,'']]], + ['buttons',['Buttons',['../Page_Buttons.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/all_2.html b/Doc/Doxygen/html/search/all_2.html new file mode 100644 index 00000000..d15ac65f --- /dev/null +++ b/Doc/Doxygen/html/search/all_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_2.js b/Doc/Doxygen/html/search/all_2.js new file mode 100644 index 00000000..6b815784 --- /dev/null +++ b/Doc/Doxygen/html/search/all_2.js @@ -0,0 +1,19 @@ +var searchData= +[ + ['callback_5fusb_5fgetdescriptor',['CALLBACK_USB_GetDescriptor',['../_l_u_f_a_descriptors_8c.html#a4d7def6e037bf75e86c24e3adb18d705',1,'CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress): LUFADescriptors.c'],['../_l_u_f_a_descriptors_8h.html#a205665735698917df77439b51d372e64',1,'CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress) ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3): LUFADescriptors.c']]], + ['cdc_5fnotification_5fepaddr',['CDC_NOTIFICATION_EPADDR',['../_l_u_f_a_descriptors_8h.html#a375d8befdd497fa6548ed0f72cb0d85d',1,'LUFADescriptors.h']]], + ['cdc_5fnotification_5fepsize',['CDC_NOTIFICATION_EPSIZE',['../_l_u_f_a_descriptors_8h.html#a1cfffa25431375dde9c6c880212f43b6',1,'LUFADescriptors.h']]], + ['cdc_5frx_5fepaddr',['CDC_RX_EPADDR',['../_l_u_f_a_descriptors_8h.html#a5051b28e57390b0072358e2dc602083e',1,'LUFADescriptors.h']]], + ['cdc_5ftx_5fepaddr',['CDC_TX_EPADDR',['../_l_u_f_a_descriptors_8h.html#a2114400269fd643e0e3b597df6a8930d',1,'LUFADescriptors.h']]], + ['cdc_5ftxrx_5fepsize',['CDC_TXRX_EPSIZE',['../_l_u_f_a_descriptors_8h.html#aef7fa1919196a302fd0f8b1079e008be',1,'LUFADescriptors.h']]], + ['codecdeinitfunc',['CodecDeInitFunc',['../struct_configuration_type.html#a2b3fe0c8c0643102a8f07157fa0265f7',1,'ConfigurationType']]], + ['codecinitfunc',['CodecInitFunc',['../struct_configuration_type.html#a2e62a9c3c9361a09c94505dff5820a9b',1,'ConfigurationType']]], + ['codectaskfunc',['CodecTaskFunc',['../struct_configuration_type.html#afcabcce06f07798a43b95d0cf4d05db2',1,'ConfigurationType']]], + ['commandline_2etxt',['CommandLine.txt',['../_command_line_8txt.html',1,'']]], + ['configuration',['Configuration',['../struct_settings_entry_type.html#a3356abc0d4b2c66663a998830ba810db',1,'SettingsEntryType']]], + ['configuration_2eh',['Configuration.h',['../_configuration_8h.html',1,'']]], + ['configurationdescriptor',['ConfigurationDescriptor',['../_l_u_f_a_descriptors_8c.html#a59d882a5961a04a054fab63be98c3b80',1,'LUFADescriptors.c']]], + ['configurations_2etxt',['Configurations.txt',['../_configurations_8txt.html',1,'']]], + ['configurationtype',['ConfigurationType',['../struct_configuration_type.html',1,'']]], + ['configurations',['Configurations',['../Page_Configurations.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/all_3.html b/Doc/Doxygen/html/search/all_3.html new file mode 100644 index 00000000..9f526c67 --- /dev/null +++ b/Doc/Doxygen/html/search/all_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_3.js b/Doc/Doxygen/html/search/all_3.js new file mode 100644 index 00000000..200675de --- /dev/null +++ b/Doc/Doxygen/html/search/all_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['devicedescriptor',['DeviceDescriptor',['../_l_u_f_a_descriptors_8c.html#addd196cc2b517282c4dc2a694313b6ac',1,'LUFADescriptors.c']]] +]; diff --git a/Doc/Doxygen/html/search/all_4.html b/Doc/Doxygen/html/search/all_4.html new file mode 100644 index 00000000..7b814aa9 --- /dev/null +++ b/Doc/Doxygen/html/search/all_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_4.js b/Doc/Doxygen/html/search/all_4.js new file mode 100644 index 00000000..3cf34410 --- /dev/null +++ b/Doc/Doxygen/html/search/all_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['gettingstarted_2etxt',['GettingStarted.txt',['../_getting_started_8txt.html',1,'']]], + ['getting_20started',['Getting Started',['../Page_GettingStarted.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/all_5.html b/Doc/Doxygen/html/search/all_5.html new file mode 100644 index 00000000..d8de5560 --- /dev/null +++ b/Doc/Doxygen/html/search/all_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_5.js b/Doc/Doxygen/html/search/all_5.js new file mode 100644 index 00000000..91d1b5f0 --- /dev/null +++ b/Doc/Doxygen/html/search/all_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['iso14443a_20reader_20functionality',['ISO14443A Reader Functionality',['../Page_14443AReader.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/all_6.html b/Doc/Doxygen/html/search/all_6.html new file mode 100644 index 00000000..9ba0cc2b --- /dev/null +++ b/Doc/Doxygen/html/search/all_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_6.js b/Doc/Doxygen/html/search/all_6.js new file mode 100644 index 00000000..02560001 --- /dev/null +++ b/Doc/Doxygen/html/search/all_6.js @@ -0,0 +1,40 @@ +var searchData= +[ + ['languagestring',['LanguageString',['../_l_u_f_a_descriptors_8c.html#a2706320165dd3831bf525233371d7af9',1,'LUFADescriptors.c']]], + ['led_2etxt',['LED.txt',['../_l_e_d_8txt.html',1,'']]], + ['ledgreenfunction',['LEDGreenFunction',['../struct_settings_entry_type.html#a178766edbb1fae270c733106c936ec5e',1,'SettingsEntryType']]], + ['ledredfunction',['LEDRedFunction',['../struct_settings_entry_type.html#abc547dcb36868b52ea63bad2905e8751',1,'SettingsEntryType']]], + ['leds_2etxt',['LEDs.txt',['../_l_e_ds_8txt.html',1,'']]], + ['log_2eh',['Log.h',['../_log_8h.html',1,'']]], + ['log_2etxt',['Log.txt',['../_log_8txt.html',1,'']]], + ['log_5fempty',['LOG_EMPTY',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0aeb7af2cca9f4eb0e7dfd62d761f23eb5',1,'Log.h']]], + ['log_5ferr_5fapp_5fauth_5ffail',['LOG_ERR_APP_AUTH_FAIL',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0af91b96f88c44348cff7d0cc69cd55bf7',1,'Log.h']]], + ['log_5ferr_5fapp_5fchecksum_5ffail',['LOG_ERR_APP_CHECKSUM_FAIL',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0af565feb6368681e1ed5f4a50fda9578a',1,'Log.h']]], + ['log_5ferr_5fapp_5fnot_5fauthed',['LOG_ERR_APP_NOT_AUTHED',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a7c307a46c2553ef6e2ae16fc85ef9295',1,'Log.h']]], + ['log_5finfo_5fapp_5fauthed',['LOG_INFO_APP_AUTHED',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a0a39a14c93925e98d015e71f8d1a2857',1,'Log.h']]], + ['log_5finfo_5fapp_5fauthing',['LOG_INFO_APP_AUTHING',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0ac7581254deab15ea99afbd19bc094e04',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fauth',['LOG_INFO_APP_CMD_AUTH',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0ae0eb650d8a75222cc52a238fa68ececa',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fdec',['LOG_INFO_APP_CMD_DEC',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a0ac7629c5bdd53c593dcefe74bad7601',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fhalt',['LOG_INFO_APP_CMD_HALT',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a3f1b700795995ca9308ca42a04bb67cb',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5finc',['LOG_INFO_APP_CMD_INC',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a1d26816467effc0eeda47234d4124c8a',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fread',['LOG_INFO_APP_CMD_READ',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a7951ddf501dad656bc39a71cff430565',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5frestore',['LOG_INFO_APP_CMD_RESTORE',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a8c9c625c4f49bee6e75c8f418046e09c',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5ftransfer',['LOG_INFO_APP_CMD_TRANSFER',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a3ff2f7a4ed2f210bb42e3d0a2ba45dc8',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5funknown',['LOG_INFO_APP_CMD_UNKNOWN',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a51365dd939423069d8fe2c09f51c805b',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fwrite',['LOG_INFO_APP_CMD_WRITE',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0abb646871507173fe4978b1342f238b7c',1,'Log.h']]], + ['log_5finfo_5fcodec_5frx_5fdata',['LOG_INFO_CODEC_RX_DATA',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a3b67fcd03ff3cc80231df3b7d9211380',1,'Log.h']]], + ['log_5finfo_5fcodec_5ftx_5fdata',['LOG_INFO_CODEC_TX_DATA',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a40884a5af2a5bfa73ab4824a3adc71af',1,'Log.h']]], + ['log_5finfo_5fconfig_5fset',['LOG_INFO_CONFIG_SET',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a837ae1da35dbdeb2cc1d8b7c22a0025d',1,'Log.h']]], + ['log_5finfo_5fgeneric',['LOG_INFO_GENERIC',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a0c156342f0056e472b5ac1ff48aa41fb',1,'Log.h']]], + ['log_5finfo_5freset_5fapp',['LOG_INFO_RESET_APP',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a27bb078ecb411f03d2a81fb68d2644c8',1,'Log.h']]], + ['log_5finfo_5fsetting_5fset',['LOG_INFO_SETTING_SET',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a1e360efb165c04ce7282511f80337483',1,'Log.h']]], + ['log_5finfo_5fuid_5fset',['LOG_INFO_UID_SET',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a54d679e676c487407959422049e43956',1,'Log.h']]], + ['logentryenum',['LogEntryEnum',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0',1,'Log.h']]], + ['logmode',['LogMode',['../struct_settings_entry_type.html#a2de0f2e5da183f58d0a46c69e530905f',1,'SettingsEntryType']]], + ['lufaconfig_2eh',['LUFAConfig.h',['../_l_u_f_a_config_8h.html',1,'']]], + ['lufadescriptors_2ec',['LUFADescriptors.c',['../_l_u_f_a_descriptors_8c.html',1,'']]], + ['lufadescriptors_2eh',['LUFADescriptors.h',['../_l_u_f_a_descriptors_8h.html',1,'']]], + ['led_20functionality',['LED functionality',['../Page_LED.html',1,'']]], + ['led_20functionality',['LED functionality',['../Page_LEDs.html',1,'index']]], + ['log_20functionality',['Log functionality',['../Page_Log.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/all_7.html b/Doc/Doxygen/html/search/all_7.html new file mode 100644 index 00000000..9384ec9b --- /dev/null +++ b/Doc/Doxygen/html/search/all_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_7.js b/Doc/Doxygen/html/search/all_7.js new file mode 100644 index 00000000..3acac7f3 --- /dev/null +++ b/Doc/Doxygen/html/search/all_7.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['mainpage_2etxt',['MainPage.txt',['../_main_page_8txt.html',1,'']]], + ['manufacturerstring',['ManufacturerString',['../_l_u_f_a_descriptors_8c.html#a84557c5ab5d188d8d7cfdbfe6de20f02',1,'LUFADescriptors.c']]], + ['memorysize',['MemorySize',['../struct_configuration_type.html#a53854068c955c57a0a564bc9f7b16dd7',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/search/all_8.html b/Doc/Doxygen/html/search/all_8.html new file mode 100644 index 00000000..37566c5d --- /dev/null +++ b/Doc/Doxygen/html/search/all_8.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_8.js b/Doc/Doxygen/html/search/all_8.js new file mode 100644 index 00000000..d35b0f4e --- /dev/null +++ b/Doc/Doxygen/html/search/all_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['pendingtasktimeout',['PendingTaskTimeout',['../struct_settings_entry_type.html#a8c13c87e174691cb0dbbbf555853829d',1,'SettingsEntryType']]], + ['productstring',['ProductString',['../_l_u_f_a_descriptors_8c.html#ad68575f70b5d6ab576068eec9d59fafb',1,'LUFADescriptors.c']]] +]; diff --git a/Doc/Doxygen/html/search/all_9.html b/Doc/Doxygen/html/search/all_9.html new file mode 100644 index 00000000..c8c51023 --- /dev/null +++ b/Doc/Doxygen/html/search/all_9.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_9.js b/Doc/Doxygen/html/search/all_9.js new file mode 100644 index 00000000..0686d5f8 --- /dev/null +++ b/Doc/Doxygen/html/search/all_9.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['reader_2etxt',['Reader.txt',['../_reader_8txt.html',1,'']]], + ['readonly',['ReadOnly',['../struct_configuration_type.html#af1ed4e624b9bd8cb65743b5cbc0be2bf',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/search/all_a.html b/Doc/Doxygen/html/search/all_a.html new file mode 100644 index 00000000..4cb31f0c --- /dev/null +++ b/Doc/Doxygen/html/search/all_a.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_a.js b/Doc/Doxygen/html/search/all_a.js new file mode 100644 index 00000000..a5bfd4f9 --- /dev/null +++ b/Doc/Doxygen/html/search/all_a.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['settings',['Settings',['../Page_Settings.html',1,'index']]], + ['settings_2eh',['Settings.h',['../_settings_8h.html',1,'']]], + ['settings_2etxt',['Settings.txt',['../_settings_8txt.html',1,'']]], + ['settingsentrytype',['SettingsEntryType',['../struct_settings_entry_type.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/all_b.html b/Doc/Doxygen/html/search/all_b.html new file mode 100644 index 00000000..d34a612e --- /dev/null +++ b/Doc/Doxygen/html/search/all_b.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_b.js b/Doc/Doxygen/html/search/all_b.js new file mode 100644 index 00000000..25634010 --- /dev/null +++ b/Doc/Doxygen/html/search/all_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['the_20chameleon_20command_20structure',['The Chameleon Command Structure',['../Page_CommandLine.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/all_c.html b/Doc/Doxygen/html/search/all_c.html new file mode 100644 index 00000000..c1ae2cae --- /dev/null +++ b/Doc/Doxygen/html/search/all_c.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/all_c.js b/Doc/Doxygen/html/search/all_c.js new file mode 100644 index 00000000..d53796e9 --- /dev/null +++ b/Doc/Doxygen/html/search/all_c.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['uploading_20and_20downloading_20memory_20dumps',['Uploading and Downloading Memory dumps',['../Page_UploadingDownloading.html',1,'index']]], + ['uidsize',['UidSize',['../struct_configuration_type.html#ac730d8b9dc9e728bb10069ea1917d99f',1,'ConfigurationType']]], + ['uploadingdownloading_2etxt',['UploadingDownloading.txt',['../_uploading_downloading_8txt.html',1,'']]], + ['usb_5fdescriptor_5fconfiguration_5ft',['USB_Descriptor_Configuration_t',['../struct_u_s_b___descriptor___configuration__t.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/classes_0.html b/Doc/Doxygen/html/search/classes_0.html new file mode 100644 index 00000000..025587a7 --- /dev/null +++ b/Doc/Doxygen/html/search/classes_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/classes_0.js b/Doc/Doxygen/html/search/classes_0.js new file mode 100644 index 00000000..745d2a02 --- /dev/null +++ b/Doc/Doxygen/html/search/classes_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['configurationtype',['ConfigurationType',['../struct_configuration_type.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/classes_1.html b/Doc/Doxygen/html/search/classes_1.html new file mode 100644 index 00000000..86dc4ffe --- /dev/null +++ b/Doc/Doxygen/html/search/classes_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/classes_1.js b/Doc/Doxygen/html/search/classes_1.js new file mode 100644 index 00000000..5d1d0017 --- /dev/null +++ b/Doc/Doxygen/html/search/classes_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['settingsentrytype',['SettingsEntryType',['../struct_settings_entry_type.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/classes_2.html b/Doc/Doxygen/html/search/classes_2.html new file mode 100644 index 00000000..014caf80 --- /dev/null +++ b/Doc/Doxygen/html/search/classes_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/classes_2.js b/Doc/Doxygen/html/search/classes_2.js new file mode 100644 index 00000000..1c133fc0 --- /dev/null +++ b/Doc/Doxygen/html/search/classes_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['usb_5fdescriptor_5fconfiguration_5ft',['USB_Descriptor_Configuration_t',['../struct_u_s_b___descriptor___configuration__t.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/close.png b/Doc/Doxygen/html/search/close.png new file mode 100644 index 00000000..9342d3df Binary files /dev/null and b/Doc/Doxygen/html/search/close.png differ diff --git a/Doc/Doxygen/html/search/defines_0.html b/Doc/Doxygen/html/search/defines_0.html new file mode 100644 index 00000000..17cfaa2c --- /dev/null +++ b/Doc/Doxygen/html/search/defines_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/defines_0.js b/Doc/Doxygen/html/search/defines_0.js new file mode 100644 index 00000000..df13009a --- /dev/null +++ b/Doc/Doxygen/html/search/defines_0.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['cdc_5fnotification_5fepaddr',['CDC_NOTIFICATION_EPADDR',['../_l_u_f_a_descriptors_8h.html#a375d8befdd497fa6548ed0f72cb0d85d',1,'LUFADescriptors.h']]], + ['cdc_5fnotification_5fepsize',['CDC_NOTIFICATION_EPSIZE',['../_l_u_f_a_descriptors_8h.html#a1cfffa25431375dde9c6c880212f43b6',1,'LUFADescriptors.h']]], + ['cdc_5frx_5fepaddr',['CDC_RX_EPADDR',['../_l_u_f_a_descriptors_8h.html#a5051b28e57390b0072358e2dc602083e',1,'LUFADescriptors.h']]], + ['cdc_5ftx_5fepaddr',['CDC_TX_EPADDR',['../_l_u_f_a_descriptors_8h.html#a2114400269fd643e0e3b597df6a8930d',1,'LUFADescriptors.h']]], + ['cdc_5ftxrx_5fepsize',['CDC_TXRX_EPSIZE',['../_l_u_f_a_descriptors_8h.html#aef7fa1919196a302fd0f8b1079e008be',1,'LUFADescriptors.h']]] +]; diff --git a/Doc/Doxygen/html/search/enums_0.html b/Doc/Doxygen/html/search/enums_0.html new file mode 100644 index 00000000..aba8d799 --- /dev/null +++ b/Doc/Doxygen/html/search/enums_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/enums_0.js b/Doc/Doxygen/html/search/enums_0.js new file mode 100644 index 00000000..57f76e4f --- /dev/null +++ b/Doc/Doxygen/html/search/enums_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['logentryenum',['LogEntryEnum',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0',1,'Log.h']]] +]; diff --git a/Doc/Doxygen/html/search/enumvalues_0.html b/Doc/Doxygen/html/search/enumvalues_0.html new file mode 100644 index 00000000..83192d35 --- /dev/null +++ b/Doc/Doxygen/html/search/enumvalues_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/enumvalues_0.js b/Doc/Doxygen/html/search/enumvalues_0.js new file mode 100644 index 00000000..ec09559c --- /dev/null +++ b/Doc/Doxygen/html/search/enumvalues_0.js @@ -0,0 +1,25 @@ +var searchData= +[ + ['log_5fempty',['LOG_EMPTY',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0aeb7af2cca9f4eb0e7dfd62d761f23eb5',1,'Log.h']]], + ['log_5ferr_5fapp_5fauth_5ffail',['LOG_ERR_APP_AUTH_FAIL',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0af91b96f88c44348cff7d0cc69cd55bf7',1,'Log.h']]], + ['log_5ferr_5fapp_5fchecksum_5ffail',['LOG_ERR_APP_CHECKSUM_FAIL',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0af565feb6368681e1ed5f4a50fda9578a',1,'Log.h']]], + ['log_5ferr_5fapp_5fnot_5fauthed',['LOG_ERR_APP_NOT_AUTHED',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a7c307a46c2553ef6e2ae16fc85ef9295',1,'Log.h']]], + ['log_5finfo_5fapp_5fauthed',['LOG_INFO_APP_AUTHED',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a0a39a14c93925e98d015e71f8d1a2857',1,'Log.h']]], + ['log_5finfo_5fapp_5fauthing',['LOG_INFO_APP_AUTHING',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0ac7581254deab15ea99afbd19bc094e04',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fauth',['LOG_INFO_APP_CMD_AUTH',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0ae0eb650d8a75222cc52a238fa68ececa',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fdec',['LOG_INFO_APP_CMD_DEC',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a0ac7629c5bdd53c593dcefe74bad7601',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fhalt',['LOG_INFO_APP_CMD_HALT',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a3f1b700795995ca9308ca42a04bb67cb',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5finc',['LOG_INFO_APP_CMD_INC',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a1d26816467effc0eeda47234d4124c8a',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fread',['LOG_INFO_APP_CMD_READ',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a7951ddf501dad656bc39a71cff430565',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5frestore',['LOG_INFO_APP_CMD_RESTORE',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a8c9c625c4f49bee6e75c8f418046e09c',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5ftransfer',['LOG_INFO_APP_CMD_TRANSFER',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a3ff2f7a4ed2f210bb42e3d0a2ba45dc8',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5funknown',['LOG_INFO_APP_CMD_UNKNOWN',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a51365dd939423069d8fe2c09f51c805b',1,'Log.h']]], + ['log_5finfo_5fapp_5fcmd_5fwrite',['LOG_INFO_APP_CMD_WRITE',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0abb646871507173fe4978b1342f238b7c',1,'Log.h']]], + ['log_5finfo_5fcodec_5frx_5fdata',['LOG_INFO_CODEC_RX_DATA',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a3b67fcd03ff3cc80231df3b7d9211380',1,'Log.h']]], + ['log_5finfo_5fcodec_5ftx_5fdata',['LOG_INFO_CODEC_TX_DATA',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a40884a5af2a5bfa73ab4824a3adc71af',1,'Log.h']]], + ['log_5finfo_5fconfig_5fset',['LOG_INFO_CONFIG_SET',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a837ae1da35dbdeb2cc1d8b7c22a0025d',1,'Log.h']]], + ['log_5finfo_5fgeneric',['LOG_INFO_GENERIC',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a0c156342f0056e472b5ac1ff48aa41fb',1,'Log.h']]], + ['log_5finfo_5freset_5fapp',['LOG_INFO_RESET_APP',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a27bb078ecb411f03d2a81fb68d2644c8',1,'Log.h']]], + ['log_5finfo_5fsetting_5fset',['LOG_INFO_SETTING_SET',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a1e360efb165c04ce7282511f80337483',1,'Log.h']]], + ['log_5finfo_5fuid_5fset',['LOG_INFO_UID_SET',['../_log_8h.html#a34112fbd78128ae58dc7801690dfa6e0a54d679e676c487407959422049e43956',1,'Log.h']]] +]; diff --git a/Doc/Doxygen/html/search/files_0.html b/Doc/Doxygen/html/search/files_0.html new file mode 100644 index 00000000..0b637cf9 --- /dev/null +++ b/Doc/Doxygen/html/search/files_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_0.js b/Doc/Doxygen/html/search/files_0.js new file mode 100644 index 00000000..7c6fcc54 --- /dev/null +++ b/Doc/Doxygen/html/search/files_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['buttons_2etxt',['Buttons.txt',['../_buttons_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_1.html b/Doc/Doxygen/html/search/files_1.html new file mode 100644 index 00000000..1094e74a --- /dev/null +++ b/Doc/Doxygen/html/search/files_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_1.js b/Doc/Doxygen/html/search/files_1.js new file mode 100644 index 00000000..519f57c7 --- /dev/null +++ b/Doc/Doxygen/html/search/files_1.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['commandline_2etxt',['CommandLine.txt',['../_command_line_8txt.html',1,'']]], + ['configuration_2eh',['Configuration.h',['../_configuration_8h.html',1,'']]], + ['configurations_2etxt',['Configurations.txt',['../_configurations_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_2.html b/Doc/Doxygen/html/search/files_2.html new file mode 100644 index 00000000..a08dbd36 --- /dev/null +++ b/Doc/Doxygen/html/search/files_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_2.js b/Doc/Doxygen/html/search/files_2.js new file mode 100644 index 00000000..0bc8ef6e --- /dev/null +++ b/Doc/Doxygen/html/search/files_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['gettingstarted_2etxt',['GettingStarted.txt',['../_getting_started_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_3.html b/Doc/Doxygen/html/search/files_3.html new file mode 100644 index 00000000..647fc8d0 --- /dev/null +++ b/Doc/Doxygen/html/search/files_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_3.js b/Doc/Doxygen/html/search/files_3.js new file mode 100644 index 00000000..9683f1ff --- /dev/null +++ b/Doc/Doxygen/html/search/files_3.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['led_2etxt',['LED.txt',['../_l_e_d_8txt.html',1,'']]], + ['leds_2etxt',['LEDs.txt',['../_l_e_ds_8txt.html',1,'']]], + ['log_2eh',['Log.h',['../_log_8h.html',1,'']]], + ['log_2etxt',['Log.txt',['../_log_8txt.html',1,'']]], + ['lufaconfig_2eh',['LUFAConfig.h',['../_l_u_f_a_config_8h.html',1,'']]], + ['lufadescriptors_2ec',['LUFADescriptors.c',['../_l_u_f_a_descriptors_8c.html',1,'']]], + ['lufadescriptors_2eh',['LUFADescriptors.h',['../_l_u_f_a_descriptors_8h.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_4.html b/Doc/Doxygen/html/search/files_4.html new file mode 100644 index 00000000..186557a6 --- /dev/null +++ b/Doc/Doxygen/html/search/files_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_4.js b/Doc/Doxygen/html/search/files_4.js new file mode 100644 index 00000000..6a6a345d --- /dev/null +++ b/Doc/Doxygen/html/search/files_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['mainpage_2etxt',['MainPage.txt',['../_main_page_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_5.html b/Doc/Doxygen/html/search/files_5.html new file mode 100644 index 00000000..671abd34 --- /dev/null +++ b/Doc/Doxygen/html/search/files_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_5.js b/Doc/Doxygen/html/search/files_5.js new file mode 100644 index 00000000..0dc55bb2 --- /dev/null +++ b/Doc/Doxygen/html/search/files_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['reader_2etxt',['Reader.txt',['../_reader_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_6.html b/Doc/Doxygen/html/search/files_6.html new file mode 100644 index 00000000..73aff188 --- /dev/null +++ b/Doc/Doxygen/html/search/files_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_6.js b/Doc/Doxygen/html/search/files_6.js new file mode 100644 index 00000000..91868bb6 --- /dev/null +++ b/Doc/Doxygen/html/search/files_6.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['settings_2eh',['Settings.h',['../_settings_8h.html',1,'']]], + ['settings_2etxt',['Settings.txt',['../_settings_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/files_7.html b/Doc/Doxygen/html/search/files_7.html new file mode 100644 index 00000000..364f4202 --- /dev/null +++ b/Doc/Doxygen/html/search/files_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/files_7.js b/Doc/Doxygen/html/search/files_7.js new file mode 100644 index 00000000..913fbf6d --- /dev/null +++ b/Doc/Doxygen/html/search/files_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['uploadingdownloading_2etxt',['UploadingDownloading.txt',['../_uploading_downloading_8txt.html',1,'']]] +]; diff --git a/Doc/Doxygen/html/search/functions_0.html b/Doc/Doxygen/html/search/functions_0.html new file mode 100644 index 00000000..6bc52b61 --- /dev/null +++ b/Doc/Doxygen/html/search/functions_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/functions_0.js b/Doc/Doxygen/html/search/functions_0.js new file mode 100644 index 00000000..eee90873 --- /dev/null +++ b/Doc/Doxygen/html/search/functions_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['callback_5fusb_5fgetdescriptor',['CALLBACK_USB_GetDescriptor',['../_l_u_f_a_descriptors_8c.html#a4d7def6e037bf75e86c24e3adb18d705',1,'CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress): LUFADescriptors.c'],['../_l_u_f_a_descriptors_8h.html#a205665735698917df77439b51d372e64',1,'CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, const void **const DescriptorAddress) ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3): LUFADescriptors.c']]] +]; diff --git a/Doc/Doxygen/html/search/mag_sel.png b/Doc/Doxygen/html/search/mag_sel.png new file mode 100644 index 00000000..81f6040a Binary files /dev/null and b/Doc/Doxygen/html/search/mag_sel.png differ diff --git a/Doc/Doxygen/html/search/nomatches.html b/Doc/Doxygen/html/search/nomatches.html new file mode 100644 index 00000000..b1ded27e --- /dev/null +++ b/Doc/Doxygen/html/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
+
No Matches
+
+ + diff --git a/Doc/Doxygen/html/search/pages_0.html b/Doc/Doxygen/html/search/pages_0.html new file mode 100644 index 00000000..0db7267b --- /dev/null +++ b/Doc/Doxygen/html/search/pages_0.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_0.js b/Doc/Doxygen/html/search/pages_0.js new file mode 100644 index 00000000..6d23ce10 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['buttons',['Buttons',['../Page_Buttons.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_1.html b/Doc/Doxygen/html/search/pages_1.html new file mode 100644 index 00000000..2c67a8ef --- /dev/null +++ b/Doc/Doxygen/html/search/pages_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_1.js b/Doc/Doxygen/html/search/pages_1.js new file mode 100644 index 00000000..a00dadfa --- /dev/null +++ b/Doc/Doxygen/html/search/pages_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['configurations',['Configurations',['../Page_Configurations.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_2.html b/Doc/Doxygen/html/search/pages_2.html new file mode 100644 index 00000000..9cb4325f --- /dev/null +++ b/Doc/Doxygen/html/search/pages_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_2.js b/Doc/Doxygen/html/search/pages_2.js new file mode 100644 index 00000000..b43e1fb8 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['getting_20started',['Getting Started',['../Page_GettingStarted.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_3.html b/Doc/Doxygen/html/search/pages_3.html new file mode 100644 index 00000000..118095e2 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_3.js b/Doc/Doxygen/html/search/pages_3.js new file mode 100644 index 00000000..91d1b5f0 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['iso14443a_20reader_20functionality',['ISO14443A Reader Functionality',['../Page_14443AReader.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_4.html b/Doc/Doxygen/html/search/pages_4.html new file mode 100644 index 00000000..e8623b10 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_4.js b/Doc/Doxygen/html/search/pages_4.js new file mode 100644 index 00000000..b181b066 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_4.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['led_20functionality',['LED functionality',['../Page_LED.html',1,'']]], + ['led_20functionality',['LED functionality',['../Page_LEDs.html',1,'index']]], + ['log_20functionality',['Log functionality',['../Page_Log.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_5.html b/Doc/Doxygen/html/search/pages_5.html new file mode 100644 index 00000000..20607d68 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_5.js b/Doc/Doxygen/html/search/pages_5.js new file mode 100644 index 00000000..dd72d0cb --- /dev/null +++ b/Doc/Doxygen/html/search/pages_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['settings',['Settings',['../Page_Settings.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_6.html b/Doc/Doxygen/html/search/pages_6.html new file mode 100644 index 00000000..8effcfe1 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_6.js b/Doc/Doxygen/html/search/pages_6.js new file mode 100644 index 00000000..25634010 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['the_20chameleon_20command_20structure',['The Chameleon Command Structure',['../Page_CommandLine.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/pages_7.html b/Doc/Doxygen/html/search/pages_7.html new file mode 100644 index 00000000..f363cca5 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/pages_7.js b/Doc/Doxygen/html/search/pages_7.js new file mode 100644 index 00000000..0017d888 --- /dev/null +++ b/Doc/Doxygen/html/search/pages_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['uploading_20and_20downloading_20memory_20dumps',['Uploading and Downloading Memory dumps',['../Page_UploadingDownloading.html',1,'index']]] +]; diff --git a/Doc/Doxygen/html/search/search.css b/Doc/Doxygen/html/search/search.css new file mode 100644 index 00000000..4d7612ff --- /dev/null +++ b/Doc/Doxygen/html/search/search.css @@ -0,0 +1,271 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + position: absolute; + float: none; + display: inline; + margin-top: 8px; + right: 0px; + width: 170px; + z-index: 102; + background-color: white; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:111px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:0px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 1; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/Doc/Doxygen/html/search/search.js b/Doc/Doxygen/html/search/search.js new file mode 100644 index 00000000..dedce3bf --- /dev/null +++ b/Doc/Doxygen/html/search/search.js @@ -0,0 +1,791 @@ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; e + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_0.js b/Doc/Doxygen/html/search/variables_0.js new file mode 100644 index 00000000..fa97c116 --- /dev/null +++ b/Doc/Doxygen/html/search/variables_0.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['applicationgetuidfunc',['ApplicationGetUidFunc',['../struct_configuration_type.html#a9d31886f03ebf75d59611b7dbe81aeca',1,'ConfigurationType']]], + ['applicationinitfunc',['ApplicationInitFunc',['../struct_configuration_type.html#a835db40b131727b32d732585e8984d4a',1,'ConfigurationType']]], + ['applicationprocessfunc',['ApplicationProcessFunc',['../struct_configuration_type.html#a12036017f3f9e7a0c6a168539e262571',1,'ConfigurationType']]], + ['applicationresetfunc',['ApplicationResetFunc',['../struct_configuration_type.html#abcb24589b62d04a8aa3e7d129e87e239',1,'ConfigurationType']]], + ['applicationsetuidfunc',['ApplicationSetUidFunc',['../struct_configuration_type.html#afd1eeffbd4b0aeab57449e57f67cd400',1,'ConfigurationType']]], + ['applicationtaskfunc',['ApplicationTaskFunc',['../struct_configuration_type.html#a9e695aaf0fd0bb6e5165b23c654e9346',1,'ConfigurationType']]], + ['applicationtickfunc',['ApplicationTickFunc',['../struct_configuration_type.html#a902e157e8657cd7bb2ef5211c1a6bc58',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/search/variables_1.html b/Doc/Doxygen/html/search/variables_1.html new file mode 100644 index 00000000..3c65cf26 --- /dev/null +++ b/Doc/Doxygen/html/search/variables_1.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_1.js b/Doc/Doxygen/html/search/variables_1.js new file mode 100644 index 00000000..b5866110 --- /dev/null +++ b/Doc/Doxygen/html/search/variables_1.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['codecdeinitfunc',['CodecDeInitFunc',['../struct_configuration_type.html#a2b3fe0c8c0643102a8f07157fa0265f7',1,'ConfigurationType']]], + ['codecinitfunc',['CodecInitFunc',['../struct_configuration_type.html#a2e62a9c3c9361a09c94505dff5820a9b',1,'ConfigurationType']]], + ['codectaskfunc',['CodecTaskFunc',['../struct_configuration_type.html#afcabcce06f07798a43b95d0cf4d05db2',1,'ConfigurationType']]], + ['configuration',['Configuration',['../struct_settings_entry_type.html#a3356abc0d4b2c66663a998830ba810db',1,'SettingsEntryType']]], + ['configurationdescriptor',['ConfigurationDescriptor',['../_l_u_f_a_descriptors_8c.html#a59d882a5961a04a054fab63be98c3b80',1,'LUFADescriptors.c']]] +]; diff --git a/Doc/Doxygen/html/search/variables_2.html b/Doc/Doxygen/html/search/variables_2.html new file mode 100644 index 00000000..7b43e0ac --- /dev/null +++ b/Doc/Doxygen/html/search/variables_2.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_2.js b/Doc/Doxygen/html/search/variables_2.js new file mode 100644 index 00000000..200675de --- /dev/null +++ b/Doc/Doxygen/html/search/variables_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['devicedescriptor',['DeviceDescriptor',['../_l_u_f_a_descriptors_8c.html#addd196cc2b517282c4dc2a694313b6ac',1,'LUFADescriptors.c']]] +]; diff --git a/Doc/Doxygen/html/search/variables_3.html b/Doc/Doxygen/html/search/variables_3.html new file mode 100644 index 00000000..ea0392df --- /dev/null +++ b/Doc/Doxygen/html/search/variables_3.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_3.js b/Doc/Doxygen/html/search/variables_3.js new file mode 100644 index 00000000..91340c8f --- /dev/null +++ b/Doc/Doxygen/html/search/variables_3.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['languagestring',['LanguageString',['../_l_u_f_a_descriptors_8c.html#a2706320165dd3831bf525233371d7af9',1,'LUFADescriptors.c']]], + ['ledgreenfunction',['LEDGreenFunction',['../struct_settings_entry_type.html#a178766edbb1fae270c733106c936ec5e',1,'SettingsEntryType']]], + ['ledredfunction',['LEDRedFunction',['../struct_settings_entry_type.html#abc547dcb36868b52ea63bad2905e8751',1,'SettingsEntryType']]], + ['logmode',['LogMode',['../struct_settings_entry_type.html#a2de0f2e5da183f58d0a46c69e530905f',1,'SettingsEntryType']]] +]; diff --git a/Doc/Doxygen/html/search/variables_4.html b/Doc/Doxygen/html/search/variables_4.html new file mode 100644 index 00000000..1ed95cb6 --- /dev/null +++ b/Doc/Doxygen/html/search/variables_4.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_4.js b/Doc/Doxygen/html/search/variables_4.js new file mode 100644 index 00000000..b9ee98fe --- /dev/null +++ b/Doc/Doxygen/html/search/variables_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['manufacturerstring',['ManufacturerString',['../_l_u_f_a_descriptors_8c.html#a84557c5ab5d188d8d7cfdbfe6de20f02',1,'LUFADescriptors.c']]], + ['memorysize',['MemorySize',['../struct_configuration_type.html#a53854068c955c57a0a564bc9f7b16dd7',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/search/variables_5.html b/Doc/Doxygen/html/search/variables_5.html new file mode 100644 index 00000000..ecc883b5 --- /dev/null +++ b/Doc/Doxygen/html/search/variables_5.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_5.js b/Doc/Doxygen/html/search/variables_5.js new file mode 100644 index 00000000..d35b0f4e --- /dev/null +++ b/Doc/Doxygen/html/search/variables_5.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['pendingtasktimeout',['PendingTaskTimeout',['../struct_settings_entry_type.html#a8c13c87e174691cb0dbbbf555853829d',1,'SettingsEntryType']]], + ['productstring',['ProductString',['../_l_u_f_a_descriptors_8c.html#ad68575f70b5d6ab576068eec9d59fafb',1,'LUFADescriptors.c']]] +]; diff --git a/Doc/Doxygen/html/search/variables_6.html b/Doc/Doxygen/html/search/variables_6.html new file mode 100644 index 00000000..0c1a66ba --- /dev/null +++ b/Doc/Doxygen/html/search/variables_6.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_6.js b/Doc/Doxygen/html/search/variables_6.js new file mode 100644 index 00000000..cf8f8deb --- /dev/null +++ b/Doc/Doxygen/html/search/variables_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['readonly',['ReadOnly',['../struct_configuration_type.html#af1ed4e624b9bd8cb65743b5cbc0be2bf',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/search/variables_7.html b/Doc/Doxygen/html/search/variables_7.html new file mode 100644 index 00000000..e0da2ef5 --- /dev/null +++ b/Doc/Doxygen/html/search/variables_7.html @@ -0,0 +1,26 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/Doc/Doxygen/html/search/variables_7.js b/Doc/Doxygen/html/search/variables_7.js new file mode 100644 index 00000000..8983436d --- /dev/null +++ b/Doc/Doxygen/html/search/variables_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['uidsize',['UidSize',['../struct_configuration_type.html#ac730d8b9dc9e728bb10069ea1917d99f',1,'ConfigurationType']]] +]; diff --git a/Doc/Doxygen/html/splitbar.png b/Doc/Doxygen/html/splitbar.png new file mode 100644 index 00000000..fe895f2c Binary files /dev/null and b/Doc/Doxygen/html/splitbar.png differ diff --git a/Doc/Doxygen/html/struct_configuration_type-members.html b/Doc/Doxygen/html/struct_configuration_type-members.html new file mode 100644 index 00000000..e552eed3 --- /dev/null +++ b/Doc/Doxygen/html/struct_configuration_type-members.html @@ -0,0 +1,113 @@ + + + + + + +Chameleon-Mini: Member List + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
ConfigurationType Member List
+
+ + + + + diff --git a/Doc/Doxygen/html/struct_configuration_type.html b/Doc/Doxygen/html/struct_configuration_type.html new file mode 100644 index 00000000..010cacd1 --- /dev/null +++ b/Doc/Doxygen/html/struct_configuration_type.html @@ -0,0 +1,330 @@ + + + + + + +Chameleon-Mini: ConfigurationType Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
ConfigurationType Struct Reference
+
+
+ +

#include <Configuration.h>

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

+Public Attributes

uint16_t MemorySize
 
uint8_t UidSize
 
bool ReadOnly
 
Codec

Codec related methods.

+
void(* CodecInitFunc )(void)
 
void(* CodecDeInitFunc )(void)
 
void(* CodecTaskFunc )(void)
 
Application

Application related functions.

+
void(* ApplicationInitFunc )(void)
 
void(* ApplicationResetFunc )(void)
 
void(* ApplicationTaskFunc )(void)
 
void(* ApplicationTickFunc )(void)
 
uint16_t(* ApplicationProcessFunc )(uint8_t *ByteBuffer, uint16_t BitCount)
 
void(* ApplicationGetUidFunc )(ConfigurationUidType Uid)
 
void(* ApplicationSetUidFunc )(ConfigurationUidType Uid)
 
+

Detailed Description

+

With this struct the behavior of a configuration is defined.

+

Member Data Documentation

+ +
+
+ + + + +
void(* ConfigurationType::CodecInitFunc) (void)
+
+

Function that initializes the codec.

+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::CodecDeInitFunc) (void)
+
+

Function that deinitializes the codec.

+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::CodecTaskFunc) (void)
+
+

Function that is called on every iteration of the main loop. Within this function the essential codec work is done.

+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::ApplicationInitFunc) (void)
+
+

Function that initializes the application.

+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::ApplicationResetFunc) (void)
+
+

Function that resets the application.

+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::ApplicationTaskFunc) (void)
+
+

Function that is called on every iteration of the main loop. Application work that is independent from the codec layer can be done here.

+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::ApplicationTickFunc) (void)
+
+

Function that is called roughly every 100ms. This can be used for parallel tasks of the application, that is independent of the codec module.

+ +
+
+ +
+
+ + + + +
uint16_t(* ConfigurationType::ApplicationProcessFunc) (uint8_t *ByteBuffer, uint16_t BitCount)
+
+

This function does two important things. It gets called by the codec. The first task is to deliver data that have been received by the codec module to the application module. The application then can decide how to answer to these data and return the response to the codec module, which will process it according to the configured codec.

+
Parameters
+ + + +
ByteBufferPointer to the start of the buffer, where the received data are and where the application can put the response data.
BitCountNumber of bits that have been received.
+
+
+
Returns
Number of bits of the response.
+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::ApplicationGetUidFunc) (ConfigurationUidType Uid)
+
+

Writes the UID for the current configuration to the given buffer.

Parameters
+ + +
UidThe target buffer.
+
+
+ +
+
+ +
+
+ + + + +
void(* ConfigurationType::ApplicationSetUidFunc) (ConfigurationUidType Uid)
+
+

Writes a given UID to the current configuration.

Parameters
+ + +
UidThe source buffer.
+
+
+ +
+
+ +
+
+ + + + +
uint16_t ConfigurationType::MemorySize
+
+

Defines how many space the configuration needs. For emulating configurations this is the memory space of the emulated card.

+
Note
For reader or sniff configurations this is set to zero.
+ +
+
+ +
+
+ + + + +
uint8_t ConfigurationType::UidSize
+
+

Defines the size of the UID for emulating configurations.

+
Note
For reader or sniff configurations this is set to zero.
+ +
+
+ +
+
+ + + + +
bool ConfigurationType::ReadOnly
+
+

Implies whether the Memory can be changed.

+ +
+
+
+ + + + diff --git a/Doc/Doxygen/html/struct_settings_entry_type-members.html b/Doc/Doxygen/html/struct_settings_entry_type-members.html new file mode 100644 index 00000000..a70241e6 --- /dev/null +++ b/Doc/Doxygen/html/struct_settings_entry_type-members.html @@ -0,0 +1,105 @@ + + + + + + +Chameleon-Mini: Member List + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
SettingsEntryType Member List
+
+ + + + + diff --git a/Doc/Doxygen/html/struct_settings_entry_type.html b/Doc/Doxygen/html/struct_settings_entry_type.html new file mode 100644 index 00000000..b42ba8fa --- /dev/null +++ b/Doc/Doxygen/html/struct_settings_entry_type.html @@ -0,0 +1,129 @@ + + + + + + +Chameleon-Mini: SettingsEntryType Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
SettingsEntryType Struct Reference
+
+
+ +

#include <Settings.h>

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

+Public Attributes

+LogModeEnum LogMode
 Button actions for this setting.
 
+ConfigurationEnum Configuration
 Log mode for this setting.
 
+LEDHookEnum LEDRedFunction
 Active configuration for this setting.
 
+LEDHookEnum LEDGreenFunction
 Red LED function for this setting.
 
+uint16_t PendingTaskTimeout
 Green LED function for this setting.
 
+

Detailed Description

+

Defines one setting.

+
Note
Some properties may change globally if this is defined in the Makefile.
+
+ + + + diff --git a/Doc/Doxygen/html/struct_u_s_b___descriptor___configuration__t-members.html b/Doc/Doxygen/html/struct_u_s_b___descriptor___configuration__t-members.html new file mode 100644 index 00000000..d48697c5 --- /dev/null +++ b/Doc/Doxygen/html/struct_u_s_b___descriptor___configuration__t-members.html @@ -0,0 +1,100 @@ + + + + + + +Chameleon-Mini: Member List + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+
+
USB_Descriptor_Configuration_t Member List
+
+
+ +

This is the complete list of members for USB_Descriptor_Configuration_t, including all inherited members.

+ +
+ + + + diff --git a/Doc/Doxygen/html/struct_u_s_b___descriptor___configuration__t.html b/Doc/Doxygen/html/struct_u_s_b___descriptor___configuration__t.html new file mode 100644 index 00000000..2404b02a --- /dev/null +++ b/Doc/Doxygen/html/struct_u_s_b___descriptor___configuration__t.html @@ -0,0 +1,103 @@ + + + + + + +Chameleon-Mini: USB_Descriptor_Configuration_t Struct Reference + + + + + + + + + + +
+
+ + + + + + +
+
Chameleon-Mini +
+
+
+ + + + + + +
+
+ + +
+ +
+ +
+
+ +
+
USB_Descriptor_Configuration_t Struct Reference
+
+
+ +

#include <LUFADescriptors.h>

+

Detailed Description

+

Type define for the device configuration descriptor structure. This must be defined in the application code, as the configuration descriptor contains several sub-descriptors which vary between devices, and which describe the device's usage to the host.

+
+ + + + diff --git a/Doc/Doxygen/html/sync_off.png b/Doc/Doxygen/html/sync_off.png new file mode 100644 index 00000000..3b443fc6 Binary files /dev/null and b/Doc/Doxygen/html/sync_off.png differ diff --git a/Doc/Doxygen/html/sync_on.png b/Doc/Doxygen/html/sync_on.png new file mode 100644 index 00000000..e08320fb Binary files /dev/null and b/Doc/Doxygen/html/sync_on.png differ diff --git a/Doc/Doxygen/html/tab_a.png b/Doc/Doxygen/html/tab_a.png new file mode 100644 index 00000000..3b725c41 Binary files /dev/null and b/Doc/Doxygen/html/tab_a.png differ diff --git a/Doc/Doxygen/html/tab_b.png b/Doc/Doxygen/html/tab_b.png new file mode 100644 index 00000000..e2b4a863 Binary files /dev/null and b/Doc/Doxygen/html/tab_b.png differ diff --git a/Doc/Doxygen/html/tab_h.png b/Doc/Doxygen/html/tab_h.png new file mode 100644 index 00000000..fd5cb705 Binary files /dev/null and b/Doc/Doxygen/html/tab_h.png differ diff --git a/Doc/Doxygen/html/tab_s.png b/Doc/Doxygen/html/tab_s.png new file mode 100644 index 00000000..ab478c95 Binary files /dev/null and b/Doc/Doxygen/html/tab_s.png differ diff --git a/Doc/Doxygen/html/tabs.css b/Doc/Doxygen/html/tabs.css new file mode 100644 index 00000000..9cf578f2 --- /dev/null +++ b/Doc/Doxygen/html/tabs.css @@ -0,0 +1,60 @@ +.tabs, .tabs2, .tabs3 { + background-image: url('tab_b.png'); + width: 100%; + z-index: 101; + font-size: 13px; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; +} + +.tabs2 { + font-size: 10px; +} +.tabs3 { + font-size: 9px; +} + +.tablist { + margin: 0; + padding: 0; + display: table; +} + +.tablist li { + float: left; + display: table-cell; + background-image: url('tab_b.png'); + line-height: 36px; + list-style: none; +} + +.tablist a { + display: block; + padding: 0 20px; + font-weight: bold; + background-image:url('tab_s.png'); + background-repeat:no-repeat; + background-position:right; + color: #283A5D; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; + outline: none; +} + +.tabs3 .tablist a { + padding: 0 10px; +} + +.tablist a:hover { + background-image: url('tab_h.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); + text-decoration: none; +} + +.tablist li.current a { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} diff --git a/Doc/DoxygenPages/.Configurations.txt.kate-swp b/Doc/DoxygenPages/.Configurations.txt.kate-swp new file mode 100644 index 00000000..62e49097 Binary files /dev/null and b/Doc/DoxygenPages/.Configurations.txt.kate-swp differ diff --git a/Doc/DoxygenPages/Buttons.txt b/Doc/DoxygenPages/Buttons.txt new file mode 100644 index 00000000..70b75d25 --- /dev/null +++ b/Doc/DoxygenPages/Buttons.txt @@ -0,0 +1,34 @@ +/** @file */ +/** @page Page_Buttons Buttons + * For user interaction, ChameleonMini provides two configurable push buttons, i.e., LBUTTON on the left side and RBUTTON on the right side of Chameleon. Chameleon distinguishes between + * -# a short (< ~1.28 s) press of the button and + * -# a long (≥ ~1.28 s) press of the button. + * + * Thus, there are four different commands for configuring the buttons: + * -# `LBUTTON` + * -# `RBUTTON` + * -# `LBUTTON_LONG` + * -# `RBUTTON_LONG` + * + * Each of these commands can be used in the getting ("?"), setting ("=") and suggesting ("=?") version. + * + * Supported Configurations + * ======================== + * + * The following table describes all currently implemented options for the button configuration. + * Configuration name | Description + * ------------------ | ----------- + * `NONE` | No function, the button is disabled + * `UID_RANDOM` | Sets a random UID for the current card slot. + * `UID_LEFT_INCREMENT` | Increments the UID for the current card slot. The UID is interpreted as little-endian. + * `UID_RIGHT_INCREMENT`| Increments the UID for the current card slot. The UID is interpreted as big-endian. + * `UID_LEFT_DECREMENT` | Decrements the UID for the current card slot. The UID is interpreted as little-endian. + * `UID_RIGHT_DECREMENT`| Decrements the UID for the current card slot. The UID is interpreted as big-endian. + * `CYCLE_SETTINGS` | Cycles through the slots/settings. If the configuration of a slot is set to `NONE`, this slot is skipped. When the last slot is reached, the next button press selects the first slot, again. + * `STORE_MEM` | Stores the current setting into the permanent Flash memory. Equivalent to the `STORE` command. + * `RECALL_MEM` | Recalls a setting from the permanent Flash memory. Equivalent to the `RECALL` command. + * `TOGGLE_FIELD` | Activates the reader field if it was deactivated, deactivates the reader field if it was activated. + * `STORE_LOG` | Writes the current log from SRAM to FRAM and clears the SRAM log. Equivalent to the `STORE_LOG` command. + * + * Note the UID commands have no effect when the slot is configured as reader. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/CommandLine.txt b/Doc/DoxygenPages/CommandLine.txt new file mode 100644 index 00000000..df816f0b --- /dev/null +++ b/Doc/DoxygenPages/CommandLine.txt @@ -0,0 +1,168 @@ +/** @file */ + +/** @page Page_CommandLine The Chameleon Command Structure + * After plugging in a USB cable, the ChameleonMini enumerates as a virtual serial interface. + * The settings of the serial interface, e.g. baudrate, stop and parity bits, are ignored by the Chameleon. + * For a high level of compatibility towards both humans and computers, Chameleon can be set up and controlled by means of a + * text-based command line interface, which can be accessed by using + * simple terminal software like hyper-terminal or teraterm. The command line is optimized to cooperate with script languages such as Python or TCL. + * + * + * Chameleon Command Structure + * =========================== + * For communicating with the Chameleon via USB, there exist four different syntax types: + * - `=` sets a parameter of the Chameleon ('set') + * - `=?` lists all possible values for the parameter ('suggest') + * - `?` returns the current value of a parameter ('get') + * - `` Executes a function with an optional response ('execute') + * + * For example, `CONFIG=?` lists the available types of virtualized cards and other options to configure a slot, while `CONFIG=MF_CLASSIC_1K` sets the current slot to Mifare Classic 1k emulation. In consequence, `CONFIG?` will return MF_CLASSIC_1K. Examples for commands executing a function are CLEAR, RESET or UPLOAD. + * + * The responses of Chameleon indicate whether an action was successful or whether (and why) an error occurred. Examples: In case of an invalid command, the Chameleon replies with `200:UNKNOWN COMMAND`. In case of a known command, but a wrong syntax, the Chameleon replies with `201:INVALID COMMAND USAGE`. + * + * Note: Each command has to be followed by a carriage return (CR, 0D hexadecimal). The backspace (08 hexadecimal) and escape (1B hexadecimal) keys are supported. All other control characters of the ASCII character set are ignored. The Chameleon commands are not case-sensitive. There is no echo of entered characters by the Chameleon, thus remember to switch on the 'local echo' in your terminal program. + * + * Responses + * --------- + * Subsequent to any command sent, the Chameleon responds with a status number and a corresponding status message, separated by a colon and terminated with a carriage return and line feed (CR+LF, 0D+0A hexadecimal). Status numbers are of a three-digit decimal format with the first digit showing the severity of the answer. Status numbers beginning with a '1' denote an informational item and those beginning with a '2' denote an error. + * Response | Description + * ---------------------------- | ----------- + * `100:OK` | The command has been successfully executed + * `101:OK WITH TEXT` | The command has been successfully executed and this response is appended with an additional line of information, terminated with CR+LF + * `110:WAITING FOR XMODEM` | The Chameleon is waiting for an XMODEM connection to be established + * `120:FALSE` | The request is answered with false + * `121:TRUE` | The request is answered with true + * `200:UNKNOWN COMMAND` | This command is unknown to the Chameleon + * `201:INVALID COMMAND USAGE` | This action is not supported by this command + * `202:INVALID PARAMETER` | The format or value of the given parameter value is invalid + * `203:TIMEOUT` | The timeout of the currently active command has expired + * + * + * Chameleon Command Set + * ===================== + * The current firmware supports the following global commands. + * Command | Description + * --------------------- | ----------- + * `CHARGING?` | Returns if the battery is currently being charged (TRUE) or not (FALSE) + * `HELP` | Returns a comma-separated list of all commands supported by the current firmware + * `RESET` | Reboots the Chameleon, i.e., power down and subsequent power-up. Note: A reset usually requires a new Terminal session. + * `RSSI?` | Returns the voltage measured at the antenna of the Chameleon, e.g., to detect the presence of an RF field or compare the field strength of different RFID readers. + * `SYSTICK?` | Returns the system tick value in ms. Note: An overflow occurs every 65,536 ms. + * `UPGRADE` | Sets the Chameleon into firmware upgrade mode (DFU). This command can be used instead of holding the RBUTTON while power-on to trigger the bootloader. + * `VERSION?` | Requests version information of the current firmware + * Button Commands| See also @ref Page_Buttons + * `RBUTTON=?` | Returns a comma-separated list of supported actions for pressing the right button shortly. + * `RBUTTON?` | Returns the currently set action for pressing the right button shortly. DEFAULT: `SETTING_CHANGE` + * `RBUTTON=` | Sets the action for pressing the right button shortly. + * `LBUTTON=?` | Returns a comma-separated list of supported actions for pressing the left button shortly. + * `LBUTTON?` | Returns the currently set action for pressing the left button shortly. DEFAULT: `RECALL_MEM` + * `LBUTTON=` | Sets the action for pressing the left button shortly. + * `RBUTTON_LONG=?` | Returns a comma-separated list of supported actions for pressing the right button a long time. + * `RBUTTON_LONG?` | Returns the currently set action for pressing the right button a long time. DEFAULT: `SETTING_CHANGE` + * `RBUTTON_LONG=` | Sets the action for pressing the right button a long time. + * `LBUTTON_LONG=?` | Returns a comma-separated list of supported actions for pressing the left button a long time. + * `LBUTTON_LONG?` | Returns the currently set action for pressing the left button a long time. DEFAULT: `RECALL_MEM` + * `LBUTTON_LONG=` | Sets the action for pressing the left button a long time. + * LED Commands | See also @ref Page_LED + * `LEDGREEN=?` | Returns a comma-separated list of supported events for illuminating the green LED + * `LEDGREEN?` | Returns the currently set event for lighting the green LED + * `LEDGREEN=` | Sets the event for which the green LED is lit. DEFAULT: `POWERED` + * `LEDRED=? ` | Returns a comma-separated list of supported events for illuminating the red LED + * `LEDRED?` | Returns the currently set event for lighting the red LED + * `LEDRED=` | Sets the event for which the green LED is lit. DEFAULT: `SETTING_CHANGE` + * Log Commands | See also @ref Page_Log \anchor Anchor_LogFunctions + * `LOGMODE=?` | Returns a comma-separated list of supported log modes + * `LOGMODE?` | Returns the current state of the log mode + * `LOGMODE=` | Sets the current log mode. DEFAULT = `OFF` + * `LOGMEM?` | Returns the remaining free space for logging data to the SRAM (max. 2048 byte) + * `LOGDOWNLOAD` | Waits for an XModem connection and then downloads the binary log - including any log data in FRAM. + * `LOGCLEAR` | Clears the log memory (SRAM and FRAM) + * `LOGSTORE` | Writes the current log from SRAM to FRAM and clears the SRAM log. \warning If the FRAM is full, currently no error message is shown. If calling `LOGMEM?` after executing this command returns any other value than the maximum SRAM log size, there was not sufficient space in the FRAM and nothing has been done. + * + * ChameleonMini provides eight 'slots' that can be configured to store different virtualized cards, or as active NFC reader, or as completely passive device for sniffing purposes. Each slot stores its configuration and, if applicable, card content. To select a particular slot, use the following command (or configure a button accordingly): + * Command | Description + * --------------------- | ----------- + * `SETTING?` | Returns the currently activated slot + * `SETTING=` | Sets the active slot, where is a number between 1 and 8 (see \ref Page_Settings) + * + * The following commands have an effect on the currently selected slot only: + * Command | Description + * --------------------- | ----------- + * `CONFIG=?` | Returns a comma-separated list of all supported configurations + * `CONFIG?` | Returns the configuration of the current slot + * `CONFIG=` | Sets the configuration of the surrent slot to `` (See @ref Page_Configurations) + * `UIDSIZE?` | Returns the UID size of the currently selected card type in Byte + * `UID?` | Returns the UID of a card in the current slot + * `UID=` | Sets a new UID, passed in hexadecimal notation. + * `READONLY?` | Returns the current state of the read-only mode + * `READONLY=[0;1]` | Activates (1) or deactivates (0) the read-only mode (Any writing to the memory is silently ignored) + * `MEMSIZE?` | Returns the memory size occupied by the current configuration in Byte + * `UPLOAD` | Waits for an XModem connection in order to upload a new virtualized card into the currently selected slot, with a size up to the current memory size + * `DOWNLOAD` | Waits for an XModem connection in order to download a virtualized card with the current memory size + * `CLEAR` | Clears the content of the current slot + * `STORE` | Stores the content of the current slot from FRAM into the Flash memory + * `RECALL` | Recalls/restores the content of the current slot from the Flash memory into the FRAM + * `TIMEOUT=?` | Returns the possible number range for timeouts. See also \ref Anchor_TimeoutCommands "Timeout commands". + * `TIMEOUT=` | Sets the timeout for the current slot in multiples of 128 ms. If set to zero, there is no timeout. See also \ref Anchor_TimeoutCommands "Timeout commands". + * `TIMEOUT?` | Returns the timeout for the current slot. See also \ref Anchor_TimeoutCommands "Timeout commands". + * Reader Commands| Using these commands only makes sense, if the slot is configured as reader. See also @ref Page_14443AReader + * `SEND ` | Adds parity bits, sends the given byte string , and returns the cards answer + * `SEND_RAW `| Does NOT add parity bits, sends the given byte string and returns the cards answer + * `GETUID` | Obtains the UID of a card that is in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command". + * `DUMP_MFU` | Reads the whole content of a Mifare Ultralight card that is in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command". + * `IDENTIFY` | Identifies the type of a card in the range of the antenna and returns it. + * `THRESHOLD=?` | Returns the possible number range for the reader threshold. + * `THRESHOLD=` | Globally sets the reader threshold. The influences the reader function and range. Setting a wrong value may result in malfunctioning of the reader. DEFAULT: 400 + * `THRESHOLD?` | Returns the current reader threshold. + * `FIELD?` | Returns whether (1) or not (0) the reader field is active. + * `FIELD=[0;1]` | Enables/disables the reader field. + * + * + * Timeout Commands \anchor Anchor_TimeoutCommands + * ---------------- + * Some commands start a process with an unpredictable termination time. In these cases, + * ChameleonMini waits with its response, until the result of this process is obtained. In order to prevent an infinite + * waiting time, an individual timeout value can be set for each slot, in multiples of roughly 100 ms up to 60,000 ms. + * When a timeout occurs or if a respective command is aborted by means of a setting change, the return code `203:TIMEOUT` is sent and a command-specific shutdown function is called, which terminates the timeout process gracefully. + * + * \warning Any terminal input is completely ignored during the waiting period. + * + * \warning When setting the timeout to zero, there is no timeout and thus a process may continue forever. + * Such a process can only be terminated by changing the setting, if a button is configured accordingly, + * or by restarting the ChameleonMini (power off, power on). + * + * + * + * Accessing the command-line using a terminal software + * ==================================================== + * In order to have quick access to the Chameleon's command-line without using any complicated software, + * we suggest using the [TeraTerm](https://ttssh2.osdn.jp/index.html.en) terminal emulation software available for windows based operating systems. + * + * Connecting and setting up + * ------------------------- + * For establishing a connection to the Chameleon's command line, select File -> New Connection, choose + * the virtual serial port of the Chameleon and hit the "OK" button. TeraTerm now tries to open the serial port + * and should succeed without any error. + * + * For easier use of the command-line using a terminal software the local-echo functionality should be activated, + * to be able to see what is typed into the chameleon. When using TeraTerm, this can be achieved by selecting + * Setup -> Terminal and check "Local Echo". + * + * Uploading and Downloading dump files + * ------------------------------------ + * In some configurations of the Chameleon, it is necessary to upload a card dump before it can be accessed by a reader. + * For doing so, the relatively simple and widely known XMODEM protocol is used. + * + * To upload a dump file using TeraTerm, follow these steps. + * 1. Enter `UPLOAD` and wait for the `110:WAITING FOR XMODEM` response + * 2. Select File -> Transfer -> XMODEM -> Send + * 3. In the dialog choose the binary dumpfile to be uploaded and make sure the option "Checksum" is checked in the lower left corner + * 4. Hitting the "Open" button will start the transfer. If no error is given to the user, the file has been uploaded sucessfully. + * + * To download the Chameleon's memory again, follow the instructions above except for using `DOWNLOAD` instead of `UPLOAD` + * and the Receive function of TeraTerm + * + * Note that there is a 10 second timeout after entering `UPLOAD` respectively `DOWNLOAD` + * after which the standard command-line is activated again. So try again if the timeout is already + * over when the XMODEM transfer is about to start. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/Configurations.txt b/Doc/DoxygenPages/Configurations.txt new file mode 100644 index 00000000..7f4a6dc4 --- /dev/null +++ b/Doc/DoxygenPages/Configurations.txt @@ -0,0 +1,34 @@ +/** @file */ + +/** @page Page_Configurations Configurations + * Each setting of the Chameleon-Mini has an active configuration, which defines the behavior of the Chameleon-Mini. A detailed description of what defines a configuration can be found at \ref ConfigurationType. + * + * Supported Codecs + * ================ + * A Configuration basically is defined by the codec it uses and by the application functions that use this codec. Currently there are two different codecs implemented: + * -# The ISO14443A codec for emulation. + * -# The ISO14443A codec for the reader function. + * + * Supported Configurations + * ======================== + * The following table shows which configurations are available currently. + * Configuration name | Codec | Description + * ------------------ | ----- | ----------- + * `NONE` | None | No functionality, Chameleon-Mini does nothing, the current setting is skipped when cycling through the settings + * `MF_ULTRALIGHT` | ISO14443A emulation | Emulates a MiFare Ultralight card + * `MF_CLASSIC_1K` | ISO14443A emulation | Emulates a MiFare Classic 1k card + * `MF_CLASSIC_4K` | ISO14443A emulation | Emulates a MiFare Classic 4k card + * `MF_CLASSIC_1K_7B` | ISO14443A emulation | Emulates a MiFare Classic 1k card with 7-byte UID. + * `MF_CLASSIC_4K_7B` | ISO14443A emulation | Emulates a MiFare Classic 4k card with 7-byte UID. + * `ISO14443A_SNIFF` | ISO14443A emulation | Currently incomplete. Sniffs ISO14443A communication between a reader and a card. + * `ISO14443A_READER` | ISO14443A reader | The Chameleon-Mini works as a reader and can process different procedures in order to obtain a cards UID etc. + * + * Configuration Changing procedure \anchor Anchor_ConfigurationChange + * ================================ + * When the configuration is changed, no matter whether by command line or during a setting change, the following steps are done: + * -# The codec deinitialization function of the currently active configuration is called. + * -# Possibly pending timeout commands are aborted. + * -# The configuration struct (\ref ConfigurationType) for the currently active configuration is overwritten with the new configuration struct. + * -# The codec initialization function of the new configuration is called. + * -# The application initialization function of the new configuration is called. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/GettingStarted.txt b/Doc/DoxygenPages/GettingStarted.txt new file mode 100644 index 00000000..8ae1511a --- /dev/null +++ b/Doc/DoxygenPages/GettingStarted.txt @@ -0,0 +1,41 @@ +/** @file */ + +/** @page Page_GettingStarted Getting Started + * + * Finally, you hold your brand-new ChameleonMini RevG in your hands! What to do now?! + * In the factory, a test firmware including a USB bootloader has been programmed into the microcontroller of the Chameleon. This page describes the next steps in order to upload the current firmware, as developed in this project, via the USB bootloader. + * + * Step 1: Trigger the USB Bootloader + * ================================= + * The bootloader can be executed in two different ways: + * -# Make sure the Chameleon is switched off (power switch on the side is in the position `OFF`). Now, hold down the right button (RBUTTON) and keep it pressed while connecting the Chameleon to a PC via a USB cable. + * -# OR: Plug your Chameleon via USB to a PC and use your favorite terminal application to connect with the test firmware of the ChameleonMini. Type `upgrade` and hit Enter. + * + * + * In either way, the ChameleonMini now jumps to the bootloader and waits patiently for a firmware upgrade. + * + * + * Step 2: Upgrade the Firmware + * =========================== + * Once the ChameleonMini is in the bootloader, you can flash a new firmware, i.e., the files [Chameleon-Mini.hex](https://raw.githubusercontent.com/emsec/ChameleonMini/master/Firmware/Chameleon-Mini/Chameleon-Mini.hex) and the [Chameleon-Mini.hex](https://raw.githubusercontent.com/emsec/ChameleonMini/master/Firmware/Chameleon-Mini/Chameleon-Mini.eep), into the microcontroller. The source code directory contains these files precompiled but you can of course also compile the code yourself. Create a new folder and copy the two files into it. The following depends on your operating system: + * + * ## Upgrade Procedure for Linux Users ## + * In order to upgrade the firmware under Linux you first have to install `avrdude`, e.g. under Ubuntu with the command `sudo apt-get install avra avrdude`. Then change to the directory where you have saved the hex and eep files and run `sudo avrdude -c flip2 -p ATXMega128A4U -B 60 -P usb -U application:w:Chameleon-Mini.hex:i -U eeprom:w:Chameleon-Mini.eep:i`. + * + * You also can use `sudo make program` in the source code directory, which basically does the same. + * + * After running this command you need to restart your Chameleon, e.g. by reattaching the Chameleon to the PC. + * + * ## Upgrade Procedure for Windows Users ## + * For upgrading the firmware under Windows please + * -# download https://sourceforge.net/projects/dfu-programmer/files/dfu-programmer/0.7.2/dfu-programmer-win-0.7.2.zip/download and extract to an arbitrary directory. Make sure to use the DFU programmer Version 0.7.2! + * -# Go to the extraction directory and then open the folder `dfu-prog-usb-1.2.2`. Install the `atmel_usb_dfu.inf` driver (right click -> install). + * -# Copy `dfu-programmer.exe` from the extraction directory to the directory where you have saved the hex and eep files. + * -# Save the [ChameleonFirmwareUpgrade.bat](https://raw.githubusercontent.com/emsec/ChameleonMini/master/Firmware/Chameleon-Mini/ChameleonFirmwareUpgrade.bat) in the same directory as the hex and eep files. + * -# Run the `ChameleonFirmwareUpgrade.bat` as Administrator (right click -> run as Administrator) and wait for the firmware upgrade to terminate. Upon success, the green LED of the ChameleonMini should light up. + * + * Finally, install the driver for Chameleon: + * Download both [ChameleonDriver.inf](https://raw.githubusercontent.com/emsec/ChameleonMini/master/Driver/ChameleonDriver.inf) and [ChameleonDriver.cat](https://raw.githubusercontent.com/emsec/ChameleonMini/master/Driver/ChameleonDriver.cat) from the Drivers directory and install the INF file (right click -> install). + * + * Now, Chameleon should appear in the Windows device manager and you should be able to open a terminal program such as TeraTerm and connect to the Chameleon-Mini via the COM port shown in the device manager. Further information about how to "talk" to the Chameleon can be found here: \ref Page_CommandLine. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/LED.txt b/Doc/DoxygenPages/LED.txt new file mode 100644 index 00000000..71878d80 --- /dev/null +++ b/Doc/DoxygenPages/LED.txt @@ -0,0 +1,19 @@ +/** @file */ +/** @page Page_LED LED functionality + * The Chameleon-Mini has two fully configurable LEDs: one red LED and one green LED. The configuration is done with the commands `LEDRED` and `LEDGREEN`, which both can be called as the getting ("?"), setting ("=") and suggesting ("=?") version. + * + * The following table shows which LED functions are currently available. + * Function name | Description + * ------------- | ----------- + * `NONE` | No function, the LED is deactivated. + * `POWERED` | The LED lights up if the Chameleon-Mini is powered, regardless whether powered by USB or by battery. + * `TERMINAL_CONN` | The LED is turned on when the Chameleon-Mini is connected via USB and is turned off when no USB connection is established. + * `TERMINAL_RXTX` | The according LED blinks shortly when sending or receiving data via the USB interface. + * `SETTING_CHANGE` | The LED blinks one time if the new setting is setting 1, two times for setting 2, ..., eight times for setting 8. + * `MEMORY_STORED` | The LED flashes everytime when a setting is stored to the permanent flash. This is currently the case when calling the command `STORE`, the button event `STORE_MEM` occurs or the setting is changed. + * `MEMORY_CHANGED` | The LED turns on when the FRAM is changed and is turned off when the currently active setting is written to the permanent flash. Thus, this function indicates when the current setting is changed. + * `CODEC_RX` | The LED flashes when the currently active codec (e.g. ISO14443A emulation) receives data. Note that this is implemented on codec layer and the flashing is triggered before the received data are interpreted by the application. + * `CODEC_TX` | The LED flashes when the currently active codec sends data. This function also is implemented on codec layer. + * `FIELD_DETECTED` | The LED is turned on if and only if a reader field is detected, which is recognized by the RSSI module (when the RSSI value hits a hardcoded threshold, it is assumed that there is a reader field). It is irrelevant whether the field comes from another reader or from the Chameleon-Mini itself. + * `LOGMEM_FULL` | Lights up the LED, if the SRAM log memory is full. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/LEDs.txt b/Doc/DoxygenPages/LEDs.txt new file mode 100644 index 00000000..bae6c9a9 --- /dev/null +++ b/Doc/DoxygenPages/LEDs.txt @@ -0,0 +1,19 @@ +/** @file */ +/** @page Page_LEDs LED functionality + * For giving user feedback, ChameleonMini provides two LEDs that can be configured to indicate various conditions, events, or internal state changes of ChameleonMini: a red LED and a green LED. Their individual configuration is controlled with the commands `LEDRED` and `LEDGREEN`, which can be called in the getting ("?"), setting ("=") and suggesting ("=?") variants. + * + * The following table shows the currently supported LED functions. + * Condition/Event | Description + * ------------- | ----------- + * `NONE` | Nothing happens, the LED remains dark. + * `POWERED` | The LED lights up, if the ChameleonMini is powered by USB or by battery. + * `TERMINAL_CONN` | The LED is turned on when the ChameleonMini is connected via USB and is turned off when no USB connection is established. + * `TERMINAL_RXTX` | The LED blinks shortly when sending or receiving data via the USB interface. + * `SETTING_CHANGE` | The LED blinks one time if the new setting is setting 1, two times for setting 2, ..., eight times for setting 8. + * `MEMORY_STORED` | The LED flashes everytime when a setting is stored to the permanent flash. This is currently the case when calling the command `STORE`, the button event `STORE_MEM` occurs or the setting is changed. + * `MEMORY_CHANGED` | The LED turns on when the content of the FRAM has been modified and is turned off when the currently active setting is written to the permanent Flash memory. Thus, this function indicates when the current content has been changed. + * `CODEC_RX` | The LED flashes when the currently active codec (e.g. ISO14443A emulation) receives data via the RFID interface. Note that this is implemented on the codec layer and the flashing is triggered before the received data is interpreted by the application. + * `CODEC_TX` | The LED flashes when the currently active codec sends data via the RFID interface. This function is also implemented on the codec layer. + * `FIELD_DETECTED` | The LED is turned on, if a reader field is detected via the RSSI module (when the RSSI value hits a hardcoded threshold, it is assumed that there is a reader field). It is irrelevant whether the field comes from another reader or from the ChameleonMini itself. + * `LOGMEM_FULL` | Lights up the LED, if the SRAM log memory is full. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/Log.txt b/Doc/DoxygenPages/Log.txt new file mode 100644 index 00000000..3b1bdb88 --- /dev/null +++ b/Doc/DoxygenPages/Log.txt @@ -0,0 +1,35 @@ +/** @file */ +/** @page Page_Log Log functionality + * + * The ChameleonMini provides a configurable log functionality. This page describes how to use it. + * + * Log Entry Format + * ================ + * The log entries use a TLV (Type Length Value)-like format: + * Name | Size | Description + * ---- | ---- | ----------- + * Entry type | 1 byte | See \ref LogEntryEnum + * Data length | 1 byte | This is the length of the appended data. + * Timestamp | 2 bytes | This is the current systick value. + * Data |Data length bytes | It is also possible that no data is appended, then the `Data length` field is zero. + * + * Entry Types + * =========== + * See \ref LogEntryEnum. + * + * Log Modes + * ========= + * Currently there exist three log modes: + * - `OFF`, which means that nothing is logged. + * - `LIVE`, which means that log events are written directly to the terminal (untested). + * - `MEMORY`, where the log events are written to SRAM. + * + * \note If there is not enough log memory, the log mode is automatically set to `OFF`. + * + * \warning Since the `MEMORY` log mode writes to SRAM, the log memory is cleared by power off or restarting the Chameleon. + * + * Related Commands, Button event and LED functions + * ================================================ + * There are various commands to configure the log functionality. See \ref Anchor_LogFunctions "Page Command Line". Equivalently to the `LOGSTORE` command, the buttons are configurable to `STORE_LOG`, which does the same. Also, there exists a `LOGMEM_FULL` function for the LEDs, which lights up the LED if the SRAM log memory is full. See also the Pages \ref Page_Buttons and \ref Page_LED. + * The 'chamlog' Python script in the project (Software folder) automatizes the process of downloading the binary log data, e.g., sending the following command under Windows with a ChameleonMini connected on port COM6 results in downloading the binary log file, clearing the log memory, and setting the log mode to `MEMORY`: `chamlog -p COM6 -c -m MEMORY -v`. Repeatedly executing this command always outputs the recently logged commands in user-readable form. Make sure that no other program, e.g., terminal software, is blocking the serial port. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/MainPage.txt b/Doc/DoxygenPages/MainPage.txt new file mode 100644 index 00000000..2b59905c --- /dev/null +++ b/Doc/DoxygenPages/MainPage.txt @@ -0,0 +1,21 @@ +/** @file */ + +/** @mainpage + * ChameleonMini, created by Kasper & Oswald, is a freely programmable, portable tool for ISO14443 / ISO15693 / NFC security analysis that can for example read out compatible transponders, emulate or clone contactless cards, and sniff/log the RFID communication. The versatile, battery operated device is designed to assess security aspects in RFID environments and can be used in different scenarios like relay or replay attacks, including state restoration, and for virtualizing up to eight smartcards that behave as perfect clones of the original, given card. + * + * The Chameleon Project has been started by the Chair for Embedded Security at the Ruhr-University Bochum, Germany, and has been licensed as open source to let everyone benefit from the work. Meanwhile the inventors of ChameleonMini have founded the security consulting company Kasper & Oswald and now continue the hardware and firmware development. + * + * We appreciate all types of contributions (for example hardware mods, firmware upgrades, bug fixes, new supported card types, videos, pictures, example applications, reviews, instructions, documentation, translations, new findings, ANYTHING...) and are happy to upload the stuff for you into the github project. Please send your contribution to chameleon@kasper-oswald.de and we will (if desired) give you credit in the github log of the upload. Likewise, we are looking forward to your feedback about bugs, problems, and desired future upgrades. Please use the issues button accordingly. + * + * *Pages:* + * + * - @subpage Page_GettingStarted + * - @subpage Page_CommandLine + * - @subpage Page_UploadingDownloading + * - @subpage Page_LEDs + * - @subpage Page_Buttons + * - @subpage Page_Configurations + * - @subpage Page_Settings + * - @subpage Page_Log + * - @subpage Page_14443AReader + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/Reader.txt b/Doc/DoxygenPages/Reader.txt new file mode 100644 index 00000000..5f53c1dc --- /dev/null +++ b/Doc/DoxygenPages/Reader.txt @@ -0,0 +1,99 @@ +/** \file */ +/** + * \page Page_14443AReader ISO14443A Reader Functionality + * + * The ChameleonMini is able to act as an ISO 14443A reader. This page describes how to use this configuration (See \ref Page_Configurations) correctly. + * + * Supported Commands + * ================== + * Using the ISO 14443A reader configuration enables the usage of some commands that are only available within this configuration. + * + * \note Technically, the `SEND` and `SEND_RAW` commands are also \ref Anchor_TimeoutCommands "timeout commands", but they end successfully (either with `NO DATA` or the response) nearly immediately on every call. + * + * \note Each of the following commands returns `INVALID COMMAND USAGE` on a non-reader \ref Page_Configurations "configuration". + * + * \warning The reader field is only turned on if this is necessary. Some commands deactivate the reader field after they are done, some do not deactivate the reader field after finishing. Please be aware, that the reader field takes a massive amount of energy and thus the voltage of the battery can drop to a critical level fastly. If not mentioned differently, all of the commands below deactivate the reader field after work. + * + * `SEND ` + * ------------------ + * There are two cases what is done, depending on the parameter: + * -# If the parameter is one byte, no parity bits are added, since this must be a short frame command. In this case the seven least significant bits are sent. + * -# If the parameter consists of more than one byte, parity bits are added and afterwards the whole sequence is sent. + * + * After sending, the ChameleonMini waits for an answer and returns either + * - `NO DATA` if no answer could be detected or + * - the received data with removed parity bits, a 2-byte big-endian value indicating the bit count and either the string `PARITY OK` or `PARITY ERR` indicating whether the parity check failed or not. + * + * In each case, the ChameleonMini code `101:OK WITH TEXT` is returned. + * + * ### Examples ### + * - `SEND 52` sends the `WUPA` command + * - `SEND 9320` sends the `ANTICOLLISION` command + * - `SEND AB2` returns `INVALID PARAMETER` since the parameter is no byte sequence + * + * \warning This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card. + * + * `SEND <2-BYTEVALUE> ` + * -------------------------------- + * Does the same like the command with only one parameter, but the first parameter indicates the to-be-sent bit count. + * + * \warning If the bit count parameter is neither 7 or a multiple of 8, no parity bits will be appended, but the remaining functionality is the exact same! + * + * ### Examples ### + * - `SEND 0007 26` sends the `REQA` command + * - `SEND 0010 9320` sends the `ANTICOLLISION` command + * - `SEND 0012 13DE4A` sends (on bit-processing-layer) SOC - 1100 1000 0111 1011 01 - EOC. The remaining bits are discarded. Note that the byte sequence is interpreted as little-endian and the bits are sent in reverse-order, just like defined in the ISO. Note also, that no parity bits are added, since `0x12` is neither 7 nor a multiple of 8. + * - `SEND 0300 52` returns `INVALID PARAMETER` since the second parameter does not contain 768 bits. + * + * \warning This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card. + * + * `SEND_RAW ` + * ---------------------- + * Sends the given byte sequence. The ChameleonMini assumes that the parameter has the parity bits already appended and thus calculates the bit count itself: + * - If the parameter is one byte, the bit count is set to 7, since this seems to be a short frame. + * - If the parameter is *n* bytes long, the ChameleonMini sends `floor(n * 16 / 9)` bits. + * + * After sending, the ChameleonMini waits for an answer and returns either + * - `NO DATA` if no answer could be detected or + * - the raw received data (including parity bits) and a 2-byte big-endian value indicating the bit count + * + * ### Examples ### + * - `SEND_RAW 52` sends the `WUPA` command. + * - `SEND_RAW 934100` sends the `ANTICOLLISION` command as the bit sequence SOC - 1100 1001 1 0000 0100 0 - EOC is sent, which is the same as `0x9320` with parity bits. + * - `SEND_RAW AB2` returns `INVALID PARAMETER` since the parameter is no byte sequence + * + * \warning This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card. + * + * `SEND <2-BYTEVALUE> ` + * -------------------------------- + * Does the same like the command with only one parameter, but the first parameter indicates the to-be-sent bit count. + * + * ### Examples ### + * - `SEND_RAW 0007 26` sends the `REQA` command + * - `SEND_RAW 0012 934100` sends the `ANTICOLLISION` command + * - `SEND_RAW 0012 934100AB` also sends the `ANTICOLLISION` command, since remaining bits are discarded + * - `SEND_RAW 0300 52` returns `INVALID PARAMETER` since the second parameter does not contain 768 bits. + * + * \warning This command does not deactivate the reader field after finishing in order to make it possible to keep up the conversation with the card. + * + * `GETUID` + * -------- + * This is a \ref Anchor_TimeoutCommands "timeout command". It tries to obtain the UID from a card that is in reader range and returns it. + * + * If this command is called within the reader configuration, it either ends up returning `101:OK WITH TEXT` and the UID or with a timeout (no matter if on setting/configuration change or on real timeout). + * + * `DUMP_MFU` + * ---------- + * This is a \ref Anchor_TimeoutCommands "timeout command". It tries to read the whole content of a MiFare Ultralight card that is in reader range and returns the content. + * + * If this command is called within the reader configuration, it either ends up returning `101:OK WITH TEXT` and the card content in 4 lines (each line contains 16 bytes) or with a timeout (no matter if on setting/configuration change or on real timeout). + * + * `IDENTIFY` + * ---------- + * This is a \ref Anchor_TimeoutCommands "timeout command". Tries to identify the type of a card in reader range and returns the type. + * + * If this command is called within the reader configuration, it ends in one of three ways: + * -# Return code `101:OK WITH TEXT`, the card type and ATQA value, UID value and SAK value of the highest cascade level. + * -# Return code `101:OK WITH TEXT`, the information that this card type is unknown to the ChameleonMini ("Unknown card.") and ATQA value, UID value and SAK value of the highest cascade level. + * -# Timeout (no matter if on setting/configuration change or on real timeout). + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/Settings.txt b/Doc/DoxygenPages/Settings.txt new file mode 100644 index 00000000..c0aa40f9 --- /dev/null +++ b/Doc/DoxygenPages/Settings.txt @@ -0,0 +1,22 @@ +/** \file */ +/** + * \page Page_Settings Settings + * + * The ChameleonMini can act in different ways, the behavior is defined by \ref Page_Configurations "configurations". But also, the ChameleonMini has slots, which are a layer above the configurations. With the slots, it is possible to switch between different configurations and respective content, e.g., a card dump together with the configuration as Mifare Classic 1k card. + * + * Properties + * ========== + * A slot is defined by settings: \ref SettingsEntryType. + * + * Slot Changing Procedure + * ======================= + * When the current slot is changed, the following procedure is applied: + * -# Break potentially pending timeout commands. + * -# Store the memory of the setting to the Flash. + * -# Set the slot number of the currently active slot to the number of the new slot. + * -# Set the slot pointer of the currently active slot to the pointer of the new slot. + * -# Since the slot also contains the configuration, apply the \ref Anchor_ConfigurationChange "configuration changing procedure" with the new configuration for the new slot. + * -# Log the slot change. + * -# Recall the new content of the slot from the permanent Flash. + * -# Signalize the slot change with an \ref Page_LED "LED", if an LED is configured to `SETTING_CHANGE`. + */ \ No newline at end of file diff --git a/Doc/DoxygenPages/UploadingDownloading.txt b/Doc/DoxygenPages/UploadingDownloading.txt new file mode 100644 index 00000000..cd7721ed --- /dev/null +++ b/Doc/DoxygenPages/UploadingDownloading.txt @@ -0,0 +1,28 @@ +/** @file */ + +/** @page Page_UploadingDownloading Uploading and Downloading Memory dumps + * In order to be able to emulate different cards, one can upload or download + * the content used for the emulation. + * + * The layout of the memory dump depends on the chosen configuration and is usually + * the same as the memory layout of the currently chosen card emulation. + * The size of the memory dump also depends on the currently chosen configuration + * and can be requested with a specific command on the command-line. + * + * In order to upload or download a memory dump, the user has to send the + * corresponding command on the command-line first and the Chameleon responds + * with a status message indicating that it is waiting for an X-MODEM connection. + * Depending on whether upload or download is chosen, the Chameleon then waits + * for 10 seconds to initiate an X-MODEM receive or send connection. + * + * When waiting for a receiving X-MODEM connection, the X-MODEM NAK byte is sent + * upto 20 times with a delay of 500ms in order to establish + * a standard 128 byte frame-size X-MODEM connection with the simple checksum scheme. + * Within this time, the user has to get his X-MODEM client ready and choose the + * binary file to be uploaded into the memory. + * + * In case of waiting for an X-MODEM send connection to establish, a wait time + * of 10 seconds is performed to receive the X-MODEM NAK byte. Within this time, + * the user has to start the X-MODEM receiver and set it to the standard 128 byte + * frame using the simple checksum scheme in order to receive the binary memory dump. + */ \ No newline at end of file diff --git a/Driver/ChameleonDriver.cat b/Driver/ChameleonDriver.cat new file mode 100644 index 00000000..4226c422 Binary files /dev/null and b/Driver/ChameleonDriver.cat differ diff --git a/Driver/ChameleonDriver.inf b/Driver/ChameleonDriver.inf new file mode 100644 index 00000000..934a8a1f --- /dev/null +++ b/Driver/ChameleonDriver.inf @@ -0,0 +1,64 @@ +;************************************************************ +; Windows USB CDC ACM Setup File +; Copyright (c) 2000 Microsoft Corporation +;************************************************************ + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%MFGNAME% +DriverVer=09/30/2016,1.0.0.4 +CatalogFile="ChameleonDriver.cat" + +[Manufacturer] +%MFGNAME%=DeviceList, NTx86, NTamd64, NTia64 + +[SourceDisksNames] + +[SourceDisksFiles] + +[DestinationDirs] +DefaultDestDir=12 + +[DriverInstall] +Include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=DriverInstall.AddReg + +[DriverInstall.Services] +Include=mdmcpq.inf +AddService=usbser, 0x00000002, LowerFilter_Service_Inst + +[DriverInstall.AddReg] +HKR,,EnumPropPages32,,"msports.dll,SerialPortPropPageProvider" + +;------------------------------------------------------------------------------ +; Vendor and Product ID Definitions +;------------------------------------------------------------------------------ +; When developing your USB device, the VID and PID used in the PC side +; application program and the firmware on the microcontroller must match. +; Modify the below line to use your VID and PID. Use the format as shown below. +; Note: One INF file can be used for multiple devices with different VID and PIDs. +; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the end of the line. +;------------------------------------------------------------------------------ +[DeviceList] +%DESCRIPTION%=DriverInstall, USB\VID_16D0&PID_04B2 + +[DeviceList.NTx86] +%DESCRIPTION%=DriverInstall, USB\VID_16D0&PID_04B2 + +[DeviceList.NTamd64] +%DESCRIPTION%=DriverInstall, USB\VID_16D0&PID_04B2 + +[DeviceList.NTia64] +%DESCRIPTION%=DriverInstall, USB\VID_16D0&PID_04B2 + +;------------------------------------------------------------------------------ +; String Definitions +;------------------------------------------------------------------------------ +;Modify these strings to customize your device +;------------------------------------------------------------------------------ +[Strings] +MFGNAME="https://github.com/emsec/ChameleonMini/" +DESCRIPTION="ChameleonMini Virtual Serial Port" diff --git a/Dumps/MFC1k_randomContent_fixedKeys.mfd b/Dumps/MFC1k_randomContent_fixedKeys.mfd new file mode 100644 index 00000000..49ac4e07 Binary files /dev/null and b/Dumps/MFC1k_randomContent_fixedKeys.mfd differ diff --git a/Dumps/MFC4k_randomContent_fixedKeys.mfd b/Dumps/MFC4k_randomContent_fixedKeys.mfd new file mode 100644 index 00000000..6704d3b1 Binary files /dev/null and b/Dumps/MFC4k_randomContent_fixedKeys.mfd differ diff --git a/Dumps/MifareClassic1K.mfd b/Dumps/MifareClassic1K.mfd new file mode 100644 index 00000000..4e8cd3fe Binary files /dev/null and b/Dumps/MifareClassic1K.mfd differ diff --git a/Dumps/MifareUltralight.mfd b/Dumps/MifareUltralight.mfd new file mode 100644 index 00000000..c2e3483c Binary files /dev/null and b/Dumps/MifareUltralight.mfd differ diff --git a/Firmware/Atmel DFU Bootloader/ASF-License.txt b/Firmware/Atmel DFU Bootloader/ASF-License.txt new file mode 100644 index 00000000..171141be --- /dev/null +++ b/Firmware/Atmel DFU Bootloader/ASF-License.txt @@ -0,0 +1,27 @@ + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Firmware/Atmel DFU Bootloader/GenerateBootloader.bat b/Firmware/Atmel DFU Bootloader/GenerateBootloader.bat new file mode 100644 index 00000000..46cff984 --- /dev/null +++ b/Firmware/Atmel DFU Bootloader/GenerateBootloader.bat @@ -0,0 +1,30 @@ +@ECHO OFF + +REM This script generates the bootloader for the actual device by combining the modified Atmel +REM bootloader located in BOOTDIR with the SPM helper that is being generated by make in BUILDDIR +REM Uses srec_cat to append the hex files + +SET MCU=atxmega128a4u +SET PIN=PA6 +SET VER=104 +SET BUILDDIR=Chameleon-Mini +SET BUILDHEX=Chameleon-Mini.hex +SET BOOTDIR=Atmel-DFU-Bootloader +SET BOOTHEX=%MCU%_%VER%_%PIN%.hex +SET OUTHEX=bootloader-%MCU%-%VER%-%PIN%-SPM.hex +SET WORKDIR=%CD% + +REM Enter build directory and build SPM helper +cd %BUILDDIR% +make clean +make spmhelper MCU='%MCU%' + +REM Return to working directory and combine generated HEX files into one +cd %WORKDIR% + +ECHO Generating bootloader by combining %BOOTHEX% and %BUILDHEX% into %OUTHEX% +ECHO. + +srec_cat %BOOTDIR%\%BOOTHEX% -intel %BUILDDIR%\%BUILDHEX% -intel -o %OUTHEX% -intel -line-length 44 + +ECHO Done \ No newline at end of file diff --git a/Firmware/Atmel DFU Bootloader/bootloader-atxmega128a4u-104-PA6-SPM.hex b/Firmware/Atmel DFU Bootloader/bootloader-atxmega128a4u-104-PA6-SPM.hex new file mode 100644 index 00000000..5f2ef19a --- /dev/null +++ b/Firmware/Atmel DFU Bootloader/bootloader-atxmega128a4u-104-PA6-SPM.hex @@ -0,0 +1,356 @@ +:020000040002F8 +:1000000000C00091780005FD42C0F092000608E1B2 +:10001000009316060FEF0A950023E9F700910806F2 +:1000200006FFECC0E0E0F0E0079116910F3F19F4F5 +:100030001F3F09F4E3C02BC03091CF0137FDFCCF47 +:100040003BB72BBFF8012091CA0113E21093CA01FC +:100050000A01E8952093CA013BBF08953BB72BBF27 +:10006000F8012091CA014093CA013DE93093340060 +:10007000E8952093CA013BBF089501E70DBF00E258 +:100080000EBFC2E9DAE20F94B6000F94720AF09242 +:10009000160600910020109101200A3A154511F032 +:1000A0000C940000F0920020F092012000E20093F6 +:1000B0007800F6CFEE84DD84CC84BB84AA84998456 +:1000C00088847F806E805D804C80BB81AA8199810D +:1000D0008881F0E0EC0FFD1FEF010895EA92DA92BB +:1000E000CA92BA92AA929A928A927A926A925A92F0 +:1000F0004A92BA93AA939A938A930895AF93BF931F +:10010000D80101900D9241505040D9F7BF91AF9165 +:1001100008954091CA01E22FF32F0093CA01049180 +:100120004093CA01089540E04BBFF80158ED54BF19 +:10013000208308954A951AF016950795FBCF0895E8 +:100140004A951AF0000F111FFBCF089520E008D048 +:10015000E9F708953BBF27913BB702D0D9F708953F +:100160002D9301501040202F212B08950EEF402E8B +:1001700004E1502E02E0602EF201362D6BBE079195 +:100180001691F201EE5FFF4F3F4F3BBFA791B69133 +:10019000F201362DEC5FFF4F3F4F3BBF4791579128 +:1001A0006691242F252B262B21F0FA01362FD2DF42 +:1001B00001C0CCDF07E0400E00E0501E601EA2012F +:1001C000662D4C3055416240B8F20895BD01D8010A +:1001D000F90104C021912D9341505040242F252B2B +:0601E000C9F7DB010895E0 +:1001F4000D947D010D94B2013ECF0FBF08952AE105 +:1002040007D00093FA042BE103D00093FB04089574 +:1002140030E002E00F9489000F3F09F40FE10895E4 +:100224000F947A0000E00093600000E30F94FA0951 +:1002340030D10064008301E000936000AFB7F8940C +:1002440051D028E0029FF001EC54F64D158303953C +:100254000230C0F3D4DF0091C0040093C00419D16C +:100264000068008300810061008384EB99E20496B6 +:10027400E6EC80839183E0EC46D10FEF0583E8EC54 +:100284000081016000830A2FB8DFE3E00D9466006B +:100294008991089500E008950FB7F89410E410933D +:1002A400CA0410E21093CA04E1ECF4E01081116076 +:1002B4001083E9EC108112601083E8EC1081106463 +:1002C4001083E9EC108111601083E8EC1081106850 +:1002D400108393CF008308950093C304089500917D +:1002E400C304089500E010E008950AD1068F178F23 +:1002F40020A331A3089566D00091CB0407FF05C065 +:1003040000E814D20F94250429C0F9D1002331F553 +:10031400EBECC0D004FF18C000E108D20F94110424 +:1003240000E00093C30420E430E010E062D020E455 +:1003340030E010E000E85DD002EE19E20093BC2941 +:100344001093BD2929D10AC0008106FF02C000E430 +:1003540004C0008105FF02C000E2E8D11ED0189558 +:1003640031D09ED101FD02C085D1B1F402E00093E9 +:10037400CC040091C5043BD0F801008105FF06C000 +:1003840036D020E2F801269308D106C000E830D028 +:1003940020E2F8012693C0D0E1CFACBF9BBF8FBF52 +:1003A40009911991299139914991599169917991B9 +:1003B4000990199029903990E991F991899199912D +:1003C400A9910895AA939A938A93FA93EA933A92F5 +:1003D4002A921A920A927A936A935A934A933A9374 +:1003E4002A931A930A938FB79BB7ACB7089500E08A +:1003F4001AC08A932051304041F02051304039F0E6 +:100404002052304031F080E005C081E003C082E03A +:1004140001C083E0EDDF20E0F801218326E02083A2 +:100424008064818335CF68EB79E2202F2F70220F0F +:10043400402F440F57DF001F020F43E00F94A0002A +:10044400060F171F08959D01E8EC24D00F7D00834B +:1004540000810F7D00833BD102E00593A2ECB9E259 +:1004640041DF0D930C93539600E2069300E4069348 +:1004740038D1069300E406931D931D931C931196A3 +:100484001D931D931C9317971D931C9310A7D901BB +:100494000895E0ECF4E000810895FFD0002331F0EA +:1004A400033011F0043009F41FD176D029D006812D +:1004B4001781083050E0104009F548E022EE39E297 +:1004C4000AEC19E20F94E600E8ECF4E01CD01BD02F +:1004D4000F94DB05002309F4E6C012D0068907FF58 +:1004E40004C014D002E004A717C0048D158D012B9D +:1004F40009F405C00BD001E004A7EFD00895DFC0D4 +:10050400E4EBF9E2089500810062E4CE00E000A784 +:1005140001A702A703A70895BCD0033011F43BD070 +:1005240037C083D080A191A1801B910B282F292B48 +:10053400A9F47FD0048D158D0217130719F005A5B2 +:10054400002311F0C7D024C080D081F07BD071F09B +:1005540000E0FD0102A703A780A191A1803400E07F +:10056400900720F080E490E005A703C001E0009329 +:10057400E129FD0186879787068D178D22A533A56E +:10058400020F131F008B118B89014AD0A0D0A6D073 +:10059400E4E00D946500A8D056CF7BD0043011F46C +:1005A400FADF3DC0FD018681978162A573A520A174 +:1005B40031A18B01080F191F2017310718F4C90145 +:1005C400861B970BAC0122EE39E2068D178D060FC0 +:1005D400171F0F94E60029D023D08034904031F4C3 +:1005E4002CD0448D558D2417350740F000A311A35A +:0C05F4002CD011F027D059F062D011C0BB +:1006000020A131A12017310759F421D011F01CD0BD +:1006100011F44BD006C00BD00ED000E002A703A708 +:100620005ED0B8CF080F191F02A713A70895FD01C8 +:1006300002A513A5089503D020A731A7089520A5EA +:1006400031A5200F311F089559D00023089545A1E9 +:1006500056A167A100E0403050076007089522D0FE +:1006600001FD09C009D039F41AD0013009F449CF8D +:10067000043009F41DD008955ED0E7CF13D001FDFA +:1006800009C0FADF39F40BD0023009F425C0033079 +:1006900009F40ED008950F947900A4EBB9E200910B +:1006A000E02908950091CC04089505E00093E02925 +:1006B000E1ECF9E204E00593E9EBF9E204E00593EB +:1006C000089520DF03E004A700E00687078701D034 +:1006D00007C0E0ECF9E2089504E00093E02903D0BC +:1006E00002E006930895E8EBF9E208950BDF42A1DA +:1006F00053A164A1AFDF09F001D00895FA016CBFE6 +:100700001994EBECC9DE02FF08C0F093CA04009113 +:10071000C02906FF0BC0A3DF09C0008101FF07C08D +:1007200002E006D00091B82906FDA8DF16C0B4CDBE +:100730000093CA040895B6DF00FFAECD01E0009338 +:10074000CC04D1DF00E80693C4DF00E8069301E0A3 +:10075000EFDFC9DF00E10693A2DE01E00895BD01ED +:100760004DD12681222371F1A281B3812D913C913B +:10077000D90114964C91041728F524833583D901A7 +:1007800012964D915C91240F351F06C04C9150E09C +:10079000A40FB51FA483B583A481B581A217B307A5 +:1007A00088F411964C911197443081F712964C9130 +:1007B0001297041759F713964C911397141731F7A2 +:1007C00001E001C000E0DB0108953DD0802F10E082 +:1007D000E8D111F400E006C015D003811481258111 +:1007E000D5D101E04DC02FD0802FDBD149F00AD008 +:1007F000008111812281CAD1002311F001E001C0E2 +:1008000000E03EC0AEE4B1E2ED91FC91A281B38183 +:1008100002E0809FA00DB11DED91FC9108950D9413 +:10082000120111D00DD139F080E003C0082FCDDFC7 +:10083000839509D1D8F300E00093522101E010E044 +:100840000D931C931DC00D947900A3D1C9F080E0D5 +:100850000EC0FD0118D044855585668500E0403006 +:100860005007600719F0FA016CBF19958395C6D03F +:10087000A281B381ED91FC9111970481801748F317 +:10088000E4E00D9465000281138177D10081F1814C +:10089000E02F08950091CC290F770D946E010091FF +:1008A000CC29002329F00A9541F00A9511F125C0C1 +:1008B00024E030E006E011E21AC025E00EEE10E27E +:1008C00040E050E032E0F801E40FF51F6081439F03 +:1008D000F001E653FF4D628353834395421798F32B +:1008E000220F2E5F2093CA2030E00AEC10E2A6D03F +:1008F00005C021E104EF10E2E3CF7CC101E00895DF +:1009000074D0FD014281238104E411E22A9529F08B +:100910002A95A1F02A9551F12CC02DD0208130E0EC +:10092000F801008111818AD065D0228533850217B4 +:10093000130710F40287138701E054C01CD02189EB +:100940004217B8F4F801F9D024E0429F000D111DC0 +:10095000F80100811181F801228133816FD022E0FA +:10096000FD010085F185E02F2183DECF98DF002394 +:10097000D9F600E0E2CFF8012081F181E22F08955D +:1009800034D038D0012B59F50F947101002339F17F +:10099000E4E4F1E27BDF2189FD0102812017F8F018 +:1009A00040DFFD0102810093522120915221222338 +:1009B000C1F0E4E4F1E2C1D034E0239F000D111D49 +:1009C000045010401BD002831383A0E001C0A39504 +:1009D000EAD0A01730F410E04ED00023C1F700E0B9 +:1009E00001C001E0A991B9910895BA93AA93AAEC24 +:1009F000B9E20895FD01068117810895ECE4F1E262 +:100A0000089521DF93D0068117810130104039F419 +:100A100017D029F0848117D010F4C1D011F400E070 +:100A20000CC0FD01A7D02FDFAED00093532121E0F1 +:100A300030E017968D0102D001E022CF0D947701AE +:100A4000ACE4B1E2A8C0FD01B0D080170895AA932C +:100A50008A936CD06ED041F49ED031F0A481828113 +:100A60000A2FB3DE002311F400E002C0182F03D0D8 +:100A70008991A99108950A2FB6CE58D0008107FF19 +:100A80002DC026813781022F032B09F447C0008136 +:100A90000F71F1F41181112329F0165069F01250F1 +:100AA00061F016C0223000E0304009F0089522E0E5 +:100AB00030E00CE411E20AC023CF213000E03040E6 +:100AC00009F0089521E030E002E511E2B7DF16CF2A +:100AD000013021F501810A3009F593CF0F7101F53D +:100AE00011811A9581F01250C9F0125019F014506A +:100AF000B1F016C01ED091F40AE414E021E004879E +:100B000015872687E4CF15D049F417D0013010405F +:100B100029F474DF00810D7F0083D9CF6BC030CF03 +:100B20000130E1F701810B30C9F791CFEAECF9E22E +:100B3000089506811781012B08950281138108957C +:100B400028D091F08091CE292ED0801768F427D03C +:100B500059F054DF0FD0F1DF10D0A081B181FD0139 +:100B600012D0102F1DD011F400E003C043DF208508 +:100B70000DD086CE0281F3818BCE22E0829F000DC4 +:100B8000111DF8010895018512852385F8012CBFF8 +:100B900019940F947900009152210023089510E0D8 +:100BA000082FDDDDFACFECE4F1E2E4DF0081F18132 +:100BB000E02F04810895BADF00E0028703870487ED +:100BC000058706870787008B018B008107FF02C01E +:100BD000B0DF81F00091CA29007619F44EDF0023BE +:100BE00041F40091CA290F71013021F4A9DF0023DB +:100BF00009F084CE00E0089500E000936F2152D008 +:100C00000F943C0A0F944B0AD2C00895BA93AA934A +:100C1000AAECB9E20091CA2900760032F9F51091E8 +:100C2000CB290C9107FF17C0125041F01A9599F586 +:100C300026E030E00EE511E25ED12BC0F8D0408D09 +:100C4000518D628D00E040305007600721F1FA01BC +:100C50006CBF199524C01A9521F01350E1F422D0ED +:100C600018C000916F21002341F000E00F94710A39 +:100C700002E61AE021E01C9609C020E430E002E719 +:100C800011E239D101E616E021E01F960D931D9384 +:100C90002C9301E004C0CBD00FE064D000E0A99118 +:100CA000B991089502C000E0089500E0E1D0EAECB7 +:100CB000F9E200E00787008B018B04870587068730 +:100CC0000895F0DF00E0B3D0008F018F028F01E0C4 +:100CD0000F94710AE2E7F1E230812181203001E0D6 +:100CE000300709F420C0203003E0300709F43DC08C +:100CF0002130300709F453C0203004E0300739F4C4 +:100D00000F94530A002300E009F4089550C02330E3 +:100D1000300721F401E000936F210895233036401D +:100D200009F452C0C0CF83D0048D158D012309F082 +:100D30009CC047815085618540305040604011F42F +:100D400010D002C027D009F4AECF20E038E0D1D0D7 +:100D500002EF17E021E0EAECF9E20787108B218B24 +:100D600028C003E002870AE0AACF14D019F023D0EC +:100D700011F4F7DF98CF048D158D012321F005E3E1 +:100D800017E021E003C00EE617E021E0008F118F8D +:100D9000228F0FC004E711E271D000230895FADF1B +:100DA00019F009D011F4DDDF7ECFA7D002C0009387 +:100DB000702101E00895E4E5F1E244815581668106 +:100DC00040305040604008952497E2E7F1E203810B +:100DD0001281112319F01A9559F026C00131F0F44F +:100DE00029D000E024D0008B018B028B038B1CC028 +:100DF00040E0488349834A834B830B8304810A8301 +:100E000016D0088119812A813B81408151816281FC +:100E10007381041715072607370728F008D008E064 +:100E2000A1DF00E002C0CFD001E024960895E4E500 +:100E3000F1E20895033041F0023031F0043021F046 +:100E4000053011F011E001C010E01093712112E0A3 +:100E5000019FF001E955FF4D6081F18104E511E248 +:100E6000E62F4AE050E00D947E0003E001D01BCF56 +:100E700000935E2102E00093622108950F947800B0 +:100E8000A4E5B1E2FD0122893389F8015081418056 +:100E9000FD01408A518BF801128103810D901D9054 +:100EA0002D903C901397001511052205330540F055 +:100EB00008E000935E210AE00093622100E00BC08D +:100EC0000419150B220B330B66D0FD01048B158B17 +:100ED000268B378B01E0E5E00D946400A8DF2488C1 +:100EE000358964D0222D6CD0A2DF2489358901D0C8 +:100EF00060CF02EB11E20D9477010F947900A4E525 +:100F0000B1E24ED0012B022B032B49F400E018EF85 +:100F1000048B158B068B078B80E098E01BC040D0BC +:100F2000402F412B422B432B99F1003048E014070E +:100F300080E02040304010F4C80101C098E0A801D2 +:100F400066897789481B590B60407040448B558BEC +:100F5000668B778B392F2AD0282F32D042EB51E283 +:100F600004C0FD0158D017D02ED08C010197012B61 +:100F7000B1F2FA010191AF010F3F99F305E000933F +:100F80005E2108EE17E021E0FD01008F118F228F16 +:100F9000E4E00D9465000F5F1F4F2F4F3F4F089502 +:100FA000FD01048915892689378908954089518969 +:100FB00062897389048115812681F8012CBF089507 +:100FC00002EB11E21994008B118B228B338B089565 +:100FD0002EDF008941894093B2210093B32122E0A2 +:100FE00030E085CF24DF17D064897589402F4F7397 +:100FF000042E112442EB51E2400D511D0780108454 +:101000002184F0012CBE199500E0EAECF9E2078793 +:10101000008B018BCECE00891189228933890895F6 +:10102000B901B2D0208127FDFDCFECEC20812860F2 +:101030002083105F98018B010F94E600ECECF1E047 +:101040000081077F008308950F947900C801A22FC3 +:10105000B091CA013AD098D0008107FDFDCF82D06F +:101060009093C1018093C001A093C40105E337D0E0 +:10107000B093CA01E4E00D9465000F947700C801B5 +:10108000D9012A010DC08D0134D045E08C010F94A7 +:101090009A004AD08096909600EE400E0FEF501EB8 +:1010A000042D052979F0082F0F7129F400E240166C +:1010B00000E0500640F72D918C01C6DF01960FEF3E +:1010C000400EEDCFE6E00D9463005ED0008107FD99 +:1010D000FDCF008101FF02C006E301D00895009317 +:1010E000CA0121E00BEC11E00D9493003093CA018A +:1010F00008953091CA012091CF0127FDFCCF0BD07C +:101100002093C001F80141918F014093C4012395C0 +:101110002032B0F3EBCF23E32093CA0120E02093E9 +:10112000C2012093C10108952ED0108117FDFDCF7B +:10113000D0D005E321C09A938A93802F9091CA0161 +:10114000C4DF46D007FDFDCF0DD00093C10111D003 +:101150008093C40103950032D0F39093CA01899122 +:101160009991089503E30093CA0100E00093C2013E +:1011700008950093C00108950093CA01B2DF8093DF +:10118000CA01899108958A93EFECF1E00895FBDF9D +:10119000008107FDFDCFA6D000E3EECF01D0F7CF51 +:1011A0000FEFC9CF0F947900DA01CB01A801622FAC +:1011B0000FD007FDFDCF082F092B49F0FA016BBFB7 +:1011C00006910D934F5F5F4F6F4F0197F4CF52CF52 +:1011D0000091CF0108950F946E0022974A015B01A0 +:1011E00028013901912FD90180E0C98807C0F0DFBB +:1011F00007FDFDCF45E2002D0F942E000A2D0B298F +:1012000009F450C0EE24E4DF07FDFDCF00E8D02E46 +:10121000CC2071F0FC01ABBF0791169108831983B4 +:101220002881312F2F3F3F4F31F0EE24E39403C04C +:101230000FEF088309830A2D0B29C9F048165906B8 +:101240006A067B0631F437D0088330D00A2D0B298B +:1012500071F08C019D010F5F1F4F2F4F3F4F4016C4 +:1012600051066206730619F426D009831FD04881FF +:1012700059818C019D010F941C008E5F9F4FAF4FD1 +:10128000BF4FDA9429F68C019D0100501140204097 +:101290003040EE20002E09F0AACF9ADF07FDFDCFE7 +:1012A00044E2A9CF2296E0E10D945A0001E0800EBD +:1012B00000E0901E08950FEFA00EB01E05D0601E36 +:1012C000701EF4010081089501E0400E00E0501E00 +:1012D000089510E2019F00E00093C2011092C10145 +:1012E0000092C0018091CA0108950FBF089508308F +:1012F00049F01FB7F894E0E5F0E02081202B20832F +:10130000012F72D008958A938FB7F8940A9519F037 +:101310000A9559F023C0183019F424D0016002C096 +:1013200023D00E7F0083E8E616C01ED0097F00831D +:10133000183019F417D002600CC0143011F4008179 +:1013400008C01F3F39F400E807870BEB008B0081D2 +:1013500004600083E0E6008101600083082F44D030 +:101360008991089504E0C3DFE6E5F0E00081089587 +:101370002497E0E7F0E007E01FEF11930A95E9F703 +:1013800024E001E44AD02CE124D009832DE121D0CE +:10139000088319810F3F1F4F21F400E413E20883F3 +:1013A0001983088119810A831B830A8100936200D3 +:1013B0000B810093630034D021E000E42ED00FB7FE +:1013C000F894E0E5F0E010811E7F10830DD02496A4 +:1013D000089530E002E00D9489004FB7F89410951D +:1013E00004D001230083042F80CFF0E0E02FE059E8 +:1013F000FF4FBCCF8A93063011F488E101C080E032 +:101400000091510001FB0EF00BD08360282F04E403 +:1014100004D010E400E0E1DFA3CF10E00D949300CE +:1014200002E065DF0091510001FBE6F71FEF02E0EB +:101430006ACF0A011B01B901A801800191010D9435 +:10144000D208E1E0EA930D94EB080A01A9019801A2 +:1014500080010D9410089A01AB010D943D080A011A +:10146000A90122E730E2200D311D0D94E6000A01AA +:10147000A90128E431E2F7CFE8E4F1E2009190001D +:1014800000830091910001830091920002830091FA +:10149000930003830895E0EDF1E0008101FB00E09B +:1014A00000F90F2708950091CF0107FDFCCF40E21E +:1014B00000E010E020E030E00F942E000F94CE0802 +:1014C00001E00895F8940AEA15E5E0E0F0E200830F +:1014D000118320917900216009E710E00F949300B7 +:1014E000FFCF089527E402EA10E00F9493000F94D1 +:1014F000B80978940F940F040F944E01FFCFDA08C7 +:101500004821000000D60072200C150204000000E3 +:10151000000200190A01210A0100080000250A0141 +:101520002B0A01030000002F0A0100000004000044 +:1015300000370A0100000000000000000000000069 +:101540000075207F209D209D20892093209D209D37 +:10155000209D209D209D209D209D209D209D209DA3 +:10156000209D20000003000000000000000000009B +:10157000000000000000000000000000000000006B +:10158000000000000000000041544D454C0044465E +:1015900055204154584D454741313238413455006A +:1015A00004030904FC0501050601060601530601B2 +:1015B000000000001201000200000040EB03DE2FDB +:1015C00004000102000109021200010100C03209F9 +:1015D00004000000FF0000000A212C213E211A21F6 +:0215E0004021A8 +:101FE000FC014093CA012DE920933400E8951124A7 +:041FF0003BBF089556 +:0400000500020000F5 +:00000001FF diff --git a/Firmware/Chameleon-Mini/.cproject b/Firmware/Chameleon-Mini/.cproject new file mode 100644 index 00000000..20859635 --- /dev/null +++ b/Firmware/Chameleon-Mini/.cproject @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firmware/Chameleon-Mini/.project b/Firmware/Chameleon-Mini/.project new file mode 100644 index 00000000..bcb4b7c5 --- /dev/null +++ b/Firmware/Chameleon-Mini/.project @@ -0,0 +1,26 @@ + + + ChamGH + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/Firmware/Chameleon-Mini/AntennaLevel.c b/Firmware/Chameleon-Mini/AntennaLevel.c new file mode 100644 index 00000000..cdc6ea1c --- /dev/null +++ b/Firmware/Chameleon-Mini/AntennaLevel.c @@ -0,0 +1,14 @@ +#include "AntennaLevel.h" +#include "LEDHook.h" + +#define FIELD_MIN_RSSI 500 + +void AntennaLevelTick(void) +{ + uint16_t rssi = AntennaLevelGet(); + + if (rssi < FIELD_MIN_RSSI) + LEDHook(LED_FIELD_DETECTED, LED_OFF); + else + LEDHook(LED_FIELD_DETECTED, LED_ON); +} diff --git a/Firmware/Chameleon-Mini/AntennaLevel.h b/Firmware/Chameleon-Mini/AntennaLevel.h new file mode 100644 index 00000000..5af73688 --- /dev/null +++ b/Firmware/Chameleon-Mini/AntennaLevel.h @@ -0,0 +1,54 @@ +/* + * AntennaLevel.h + * + * Created on: 24.11.2013 + * Author: skuser + */ + +#ifndef ANTENNALEVEL_H_ +#define ANTENNALEVEL_H_ + +#include "Common.h" + +#define ANTENNA_LEVEL_R1 47E3 +#define ANTENNA_LEVEL_R2 1E3 +#define ANTENNA_LEVEL_VREF 1.0 +#define ANTENNA_LEVEL_RES 4096 +#define ANTENNA_LEVEL_OFFSET 190 /* LSB */ + +#define ANTENNA_LEVEL_MILLIVOLT 1E3 +#define ANTENNA_LEVEL_FACTOR (ANTENNA_LEVEL_VREF * (ANTENNA_LEVEL_R1 + ANTENNA_LEVEL_R2) / (ANTENNA_LEVEL_RES * ANTENNA_LEVEL_R2) ) +#define ANTENNA_LEVEL_SCALE ((uint32_t) 1<<16) +#define ANTENNA_LEVEL_NUMERATOR ((uint32_t) (ANTENNA_LEVEL_MILLIVOLT * ANTENNA_LEVEL_FACTOR * ANTENNA_LEVEL_SCALE + .5)) +#define ANTENNA_LEVEL_DENOMINATOR (ANTENNA_LEVEL_SCALE) + +static inline +void AntennaLevelInit(void) +{ + ADCA.CTRLA = ADC_ENABLE_bm; + ADCA.CTRLB = ADC_RESOLUTION_12BIT_gc; + ADCA.REFCTRL = ADC_REFSEL_INT1V_gc | ADC_BANDGAP_bm; + ADCA.PRESCALER = ADC_PRESCALER_DIV32_gc; + ADCA.CH0.CTRL = ADC_CH_INPUTMODE_SINGLEENDED_gc; + ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN1_gc; + +} + +static inline +uint16_t AntennaLevelGet(void) +{ + ADCA.CH0.CTRL |= ADC_CH_START_bm; + while( !(ADCA.CH0.INTFLAGS & ADC_CH_CHIF_bm) ); + + ADCA.CH0.INTFLAGS = ADC_CH_CHIF_bm; + + int16_t Result = ADCA.CH0RES - ANTENNA_LEVEL_OFFSET; + if (Result < 0) Result = 0; + + return (uint16_t) (((uint32_t) Result * ANTENNA_LEVEL_NUMERATOR) / ANTENNA_LEVEL_DENOMINATOR); +} + +void AntennaLevelTick(void); +void AntennaLevelResetMaxRssi(void); + +#endif /* ANTENNALEVEL_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h new file mode 100644 index 00000000..6667477f --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -0,0 +1,51 @@ +/* + * Application.h + * + * Created on: 18.02.2013 + * Author: skuser + */ + +#ifndef APPLICATION_H_ +#define APPLICATION_H_ + +#include "../Common.h" +#include "../Configuration.h" +#include "../Log.h" + +/* Applications */ +#include "MifareUltralight.h" +#include "MifareClassic.h" +#include "Reader14443A.h" + +/* Function wrappers */ +INLINE void ApplicationInit(void) { + ActiveConfiguration.ApplicationInitFunc(); +} + +INLINE void ApplicationTask(void) { + ActiveConfiguration.ApplicationTaskFunc(); +} + +INLINE void ApplicationTick(void) { + ActiveConfiguration.ApplicationTickFunc(); +} + +INLINE uint16_t ApplicationProcess(uint8_t* ByteBuffer, uint16_t ByteCount) { + return ActiveConfiguration.ApplicationProcessFunc(ByteBuffer, ByteCount); +} + +INLINE void ApplicationReset(void) { + ActiveConfiguration.ApplicationResetFunc(); + //LogEntry(LOG_INFO_RESET_APP, NULL, 0); +} + +INLINE void ApplicationGetUid(ConfigurationUidType Uid) { + ActiveConfiguration.ApplicationGetUidFunc(Uid); +} + +INLINE void ApplicationSetUid(ConfigurationUidType Uid) { + ActiveConfiguration.ApplicationSetUidFunc(Uid); + LogEntry(LOG_INFO_UID_SET, Uid, ActiveConfiguration.UidSize); +} + +#endif /* APPLICATION_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Crypto1.c b/Firmware/Chameleon-Mini/Application/Crypto1.c new file mode 100644 index 00000000..e172381c --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Crypto1.c @@ -0,0 +1,415 @@ +#include "Crypto1.h" + +#define PRNG_MASK 0x002D0000UL +/* x^16 + x^14 + x^13 + x^11 + 1 */ + +#define PRNG_SIZE 4 /* Bytes */ + +#define LFSR_MASK_EVEN 0x2010E1UL +#define LFSR_MASK_ODD 0x3A7394UL +/* x^48 + x^43 + x^39 + x^38 + x^36 + x^34 + x^33 + x^31 + x^29 + + * x^24 + x^23 + x^21 + x^19 + x^13 + x^9 + x^7 + x^6 + x^5 + 1 */ + +#define LFSR_SIZE 6 /* Bytes */ + +/* Functions fa, fb and fc in filter output network. Definitions taken + * from Timo Kasper's thesis */ +#define FA(x3, x2, x1, x0) ( \ + ( (x0 | x1) ^ (x0 & x3) ) ^ ( x2 & ( (x0 ^ x1) | x3 ) ) \ +) + +#define FB(x3, x2, x1, x0) ( \ + ( (x0 & x1) | x2 ) ^ ( (x0 ^ x1) & (x2 | x3) ) \ +) + +#define FC(x4, x3, x2, x1, x0) ( \ + ( x0 | ( (x1 | x4) & (x3 ^ x4) ) ) ^ ( ( x0 ^ (x1 & x3) ) & ( (x2 ^ x3) | (x1 & x4) ) ) \ +) + +#define SWAPENDIAN(x)\ + (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) + +/* Create tables from function fa, fb and fc for faster access */ +static const uint8_t TableAB[5][16] = { + { /* fa with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 0 */ + FA(0,0,0,0) << 0, FA(0,0,0,1) << 0, FA(0,0,1,0) << 0, FA(0,0,1,1) << 0, + FA(0,1,0,0) << 0, FA(0,1,0,1) << 0, FA(0,1,1,0) << 0, FA(0,1,1,1) << 0, + FA(1,0,0,0) << 0, FA(1,0,0,1) << 0, FA(1,0,1,0) << 0, FA(1,0,1,1) << 0, + FA(1,1,0,0) << 0, FA(1,1,0,1) << 0, FA(1,1,1,0) << 0, FA(1,1,1,1) << 0, + }, + { /* fb with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 1 */ + FB(0,0,0,0) << 1, FB(0,0,0,1) << 1, FB(0,0,1,0) << 1, FB(0,0,1,1) << 1, + FB(0,1,0,0) << 1, FB(0,1,0,1) << 1, FB(0,1,1,0) << 1, FB(0,1,1,1) << 1, + FB(1,0,0,0) << 1, FB(1,0,0,1) << 1, FB(1,0,1,0) << 1, FB(1,0,1,1) << 1, + FB(1,1,0,0) << 1, FB(1,1,0,1) << 1, FB(1,1,1,0) << 1, FB(1,1,1,1) << 1, + }, + { /* fb with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 2 */ + FB(0,0,0,0) << 2, FB(0,0,0,1) << 2, FB(0,0,1,0) << 2, FB(0,0,1,1) << 2, + FB(0,1,0,0) << 2, FB(0,1,0,1) << 2, FB(0,1,1,0) << 2, FB(0,1,1,1) << 2, + FB(1,0,0,0) << 2, FB(1,0,0,1) << 2, FB(1,0,1,0) << 2, FB(1,0,1,1) << 2, + FB(1,1,0,0) << 2, FB(1,1,0,1) << 2, FB(1,1,1,0) << 2, FB(1,1,1,1) << 2, + }, + { /* fa with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 3 */ + FA(0,0,0,0) << 3, FA(0,0,0,1) << 3, FA(0,0,1,0) << 3, FA(0,0,1,1) << 3, + FA(0,1,0,0) << 3, FA(0,1,0,1) << 3, FA(0,1,1,0) << 3, FA(0,1,1,1) << 3, + FA(1,0,0,0) << 3, FA(1,0,0,1) << 3, FA(1,0,1,0) << 3, FA(1,0,1,1) << 3, + FA(1,1,0,0) << 3, FA(1,1,0,1) << 3, FA(1,1,1,0) << 3, FA(1,1,1,1) << 3, + }, + { /* fb with Input {3,2,1,0} = (0,0,0,0) to (1,1,1,1) shifted by 4 */ + FB(0,0,0,0) << 4, FB(0,0,0,1) << 4, FB(0,0,1,0) << 4, FB(0,0,1,1) << 4, + FB(0,1,0,0) << 4, FB(0,1,0,1) << 4, FB(0,1,1,0) << 4, FB(0,1,1,1) << 4, + FB(1,0,0,0) << 4, FB(1,0,0,1) << 4, FB(1,0,1,0) << 4, FB(1,0,1,1) << 4, + FB(1,1,0,0) << 4, FB(1,1,0,1) << 4, FB(1,1,1,0) << 4, FB(1,1,1,1) << 4, + } +}; + +static const uint8_t TableC[32] = { + /* fc with Input {4,3,2,1,0} = (0,0,0,0,0) to (1,1,1,1,1) */ + FC(0,0,0,0,0), FC(0,0,0,0,1), FC(0,0,0,1,0), FC(0,0,0,1,1), + FC(0,0,1,0,0), FC(0,0,1,0,1), FC(0,0,1,1,0), FC(0,0,1,1,1), + FC(0,1,0,0,0), FC(0,1,0,0,1), FC(0,1,0,1,0), FC(0,1,0,1,1), + FC(0,1,1,0,0), FC(0,1,1,0,1), FC(0,1,1,1,0), FC(0,1,1,1,1), + FC(1,0,0,0,0), FC(1,0,0,0,1), FC(1,0,0,1,0), FC(1,0,0,1,1), + FC(1,0,1,0,0), FC(1,0,1,0,1), FC(1,0,1,1,0), FC(1,0,1,1,1), + FC(1,1,0,0,0), FC(1,1,0,0,1), FC(1,1,0,1,0), FC(1,1,0,1,1), + FC(1,1,1,0,0), FC(1,1,1,0,1), FC(1,1,1,1,0), FC(1,1,1,1,1), +}; + +/* Split Crypto1 state into even and odd bits to speed up the output filter network */ +static uint8_t StateEven[LFSR_SIZE/2] = {0}; +static uint8_t StateOdd[LFSR_SIZE/2] = {0}; + +/* Proceed LFSR by one clock cycle */ +static void Crypto1LFSR(uint8_t In) { + uint8_t Feedback = 0; + + /* Calculate feedback according to LFSR taps. XOR all 6 state bytes + * into a single bit. */ + Feedback ^= StateEven[0] & (uint8_t) (LFSR_MASK_EVEN >> 0); + Feedback ^= StateEven[1] & (uint8_t) (LFSR_MASK_EVEN >> 8); + Feedback ^= StateEven[2] & (uint8_t) (LFSR_MASK_EVEN >> 16); + + Feedback ^= StateOdd[0] & (uint8_t) (LFSR_MASK_ODD >> 0); + Feedback ^= StateOdd[1] & (uint8_t) (LFSR_MASK_ODD >> 8); + Feedback ^= StateOdd[2] & (uint8_t) (LFSR_MASK_ODD >> 16); + + Feedback ^= Feedback >> 4; + Feedback ^= Feedback >> 2; + Feedback ^= Feedback >> 1; + + /* Now the shifting of the Crypto1 state gets more complicated when + * split up into even/odd parts. After some hard thinking, one can + * see that after one LFSR clock cycle + * - the new even state becomes the old odd state + * - the new odd state becomes the old even state right-shifted by 1. + * For shifting the even state, we convert it into a 32 bit int first */ + uint32_t Temp = 0; + Temp |= ((uint32_t) StateEven[0] << 0); + Temp |= ((uint32_t) StateEven[1] << 8); + Temp |= ((uint32_t) StateEven[2] << 16); + + /* Proceed LFSR. Try to force compiler not to shift the unneded upper bits. */ + Temp = (Temp >> 1) & 0x00FFFFFF; + + /* Calculate MSBit of even state as input bit to LFSR */ + if ( (Feedback & 0x01) ^ In ) { + Temp |= (uint32_t) 1 << (8 * LFSR_SIZE/2 - 1); + } + + /* Convert even state back into byte array and swap odd/even state + * as explained above. */ + StateEven[0] = StateOdd[0]; + StateEven[1] = StateOdd[1]; + StateEven[2] = StateOdd[2]; + + StateOdd[0] = (uint8_t) (Temp >> 0); + StateOdd[1] = (uint8_t) (Temp >> 8); + StateOdd[2] = (uint8_t) (Temp >> 16); +} + +uint8_t Crypto1FilterOutput(void) { + /* Calculate the functions fa, fb. + * Note that only bits {4...23} of the odd state + * get fed into these function. + * The tables are designed to hold mask values, which + * can simply be ORed together to produce the resulting + * 5 bits that are used to lookup the output bit. + */ + uint8_t Sum = 0; + + Sum |= TableAB[0][(StateOdd[0] >> 4) & 0x0F]; + Sum |= TableAB[1][(StateOdd[1] >> 0) & 0x0F]; + Sum |= TableAB[2][(StateOdd[1] >> 4) & 0x0F]; + Sum |= TableAB[3][(StateOdd[2] >> 0) & 0x0F]; + Sum |= TableAB[4][(StateOdd[2] >> 4) & 0x0F]; + + return TableC[Sum]; +} + +void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4]) +{ + uint8_t i; + + /* Again, one trade off when splitting up the state into even/odd parts + * is that loading the key into the state becomes a little more difficult. + * The inner loop generates 8 even and 8 odd bits from 16 key bits and + * the outer loop stores them. */ + for (i=0; i<(LFSR_SIZE/2); i++) { + uint8_t EvenByte = 0; + uint8_t OddByte = 0; + uint16_t KeyWord = ((uint16_t) Key[2*i+1] << 8) | Key[2*i+0]; + uint8_t j; + + for (j=0; j<8; j++) { + EvenByte >>= 1; + OddByte >>= 1; + + if (KeyWord & (1<<0)) { + EvenByte |= 0x80; + } + + if (KeyWord & (1<<1)) { + OddByte |= 0x80; + } + + KeyWord >>= 2; + } + + StateEven[i] = EvenByte; + StateOdd[i] = OddByte; + } + + /* Use Uid XOR CardNonce as feed-in and do 32 clocks on the + * Crypto1 LFSR.*/ + uint32_t Temp = 0; + + Temp |= (uint32_t) (Uid[0] ^ CardNonce[0]) << 0; + Temp |= (uint32_t) (Uid[1] ^ CardNonce[1]) << 8; + Temp |= (uint32_t) (Uid[2] ^ CardNonce[2]) << 16; + Temp |= (uint32_t) (Uid[3] ^ CardNonce[3]) << 24; + + for (i=0; i<32; i++) { + uint8_t Out = Crypto1FilterOutput(); + + Crypto1LFSR(Temp & 0x01); + Temp >>= 1; + + /* Store the keystream for later use */ + if (Out) { + Temp |= (uint32_t) 1 << 31; + } + } + + /* Crypto1 state register is now set up to be used for authentication. + * In case of nested authentication, we need to use the produced keystream + * to encrypt the CardNonce. For this case we do the encryption in-place. */ + CardNonce[0] ^= (uint8_t) (Temp >> 0); + CardNonce[1] ^= (uint8_t) (Temp >> 8); + CardNonce[2] ^= (uint8_t) (Temp >> 16); + CardNonce[3] ^= (uint8_t) (Temp >> 24); +} + +void Crypto1SetupReader(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], bool Nested) +{ + uint8_t i; + + /* Again, one trade off when splitting up the state into even/odd parts + * is that loading the key into the state becomes a little more difficult. + * The inner loop generates 8 even and 8 odd bits from 16 key bits and + * the outer loop stores them. */ + for (i=0; i<(LFSR_SIZE/2); i++) { + uint8_t EvenByte = 0; + uint8_t OddByte = 0; + uint16_t KeyWord = ((uint16_t) Key[2*i+1] << 8) | Key[2*i+0]; + uint8_t j; + + for (j=0; j<8; j++) { + EvenByte >>= 1; + OddByte >>= 1; + + if (KeyWord & (1<<0)) { + EvenByte |= 0x80; + } + + if (KeyWord & (1<<1)) { + OddByte |= 0x80; + } + + KeyWord >>= 2; + } + + StateEven[i] = EvenByte; + StateOdd[i] = OddByte; + } + + if (Nested) + { + /* Use Uid XOR DECRYPTED CardNonce as feed-in and do 32 clocks on the + * Crypto1 LFSR.*/ + for (i=0; i<32; i++) + { + CardNonce[i/8] ^= Crypto1FilterOutput() << (i % 8); // decrypt bit + + Crypto1LFSR(((Uid[i/8]^CardNonce[i/8]) >> (i % 8)) & 0x01); // feed back decrypted CardNonce bit XOR uid bit + } + } else { + /* Use Uid XOR CardNonce as feed-in and do 32 clocks on the + * Crypto1 LFSR.*/ + uint32_t Temp = 0; + + Temp |= (uint32_t) (Uid[0] ^ CardNonce[0]) << 0; + Temp |= (uint32_t) (Uid[1] ^ CardNonce[1]) << 8; + Temp |= (uint32_t) (Uid[2] ^ CardNonce[2]) << 16; + Temp |= (uint32_t) (Uid[3] ^ CardNonce[3]) << 24; + + for (i=0; i<32; i++) + { + Crypto1LFSR(Temp & 0x01); + Temp >>= 1; + } + } +} + +void Crypto1Auth(uint8_t EncryptedReaderNonce[4]) +{ + uint32_t Temp = 0; + + /* For ease of processing, we convert the encrypted reader nonce + * into a 32 bit integer */ + Temp |= (uint32_t) EncryptedReaderNonce[0] << 0; + Temp |= (uint32_t) EncryptedReaderNonce[1] << 8; + Temp |= (uint32_t) EncryptedReaderNonce[2] << 16; + Temp |= (uint32_t) EncryptedReaderNonce[3] << 24; + + uint8_t i; + + for (i=0; i<32; i++) { + /* Decrypt one output bit of the given encrypted nonce using the + * filter output as keystream. */ + uint8_t Out = Crypto1FilterOutput(); + uint8_t Bit = Out ^ (Temp & 0x01); + + /* Feed back the bit to load the LFSR with the (decrypted) nonce */ + Crypto1LFSR(Bit); + Temp >>= 1; + } +} + +uint8_t Crypto1Byte(void) +{ + uint8_t KeyStream = 0; + uint8_t i; + + /* Generate 8 keystream-bits */ + for (i=0; i<8; i++) { + + /* Calculate output of function-network and cycle LFSR with no + * additional input, thus linearly! */ + uint8_t Out = Crypto1FilterOutput(); + Crypto1LFSR(0); + + /* Store keystream bit */ + KeyStream >>= 1; + + if (Out) { + KeyStream |= (1<<7); + } + } + + return KeyStream; +} + +uint8_t Crypto1Nibble(void) +{ + uint8_t KeyStream = 0; + uint8_t i; + + /* Generate 4 keystream-bits */ + for (i=0; i<4; i++) { + + /* Calculate output of function-network and cycle LFSR with no + * additional input, thus linearly! */ + uint8_t Out = Crypto1FilterOutput(); + Crypto1LFSR(0); + + /* Store keystream bit */ + KeyStream >>= 1; + + if (Out) { + KeyStream |= (1<<3); + } + } + + return KeyStream; +} + +void Crypto1PRNG(uint8_t State[4], uint16_t ClockCount) +{ + while(ClockCount--) { + /* Actually, the PRNG is a 32 bit register with the upper 16 bit + * used as a LFSR. Furthermore only mask-byte 2 contains feedback at all. + * We rely on the compiler to optimize this for us here. + * XOR all tapped bits to a single feedback bit. */ + uint8_t Feedback = 0; + + Feedback ^= State[0] & (uint8_t) (PRNG_MASK >> 0); + Feedback ^= State[1] & (uint8_t) (PRNG_MASK >> 8); + Feedback ^= State[2] & (uint8_t) (PRNG_MASK >> 16); + Feedback ^= State[3] & (uint8_t) (PRNG_MASK >> 24); + + Feedback ^= Feedback >> 4; + Feedback ^= Feedback >> 2; + Feedback ^= Feedback >> 1; + + /* For ease of processing convert the state into a 32 bit integer first */ + uint32_t Temp = 0; + + Temp |= (uint32_t) State[0] << 0; + Temp |= (uint32_t) State[1] << 8; + Temp |= (uint32_t) State[2] << 16; + Temp |= (uint32_t) State[3] << 24; + + /* Cycle LFSR and feed back. */ + Temp >>= 1; + + if (Feedback & 0x01) { + Temp |= (uint32_t) 1 << (8 * PRNG_SIZE - 1); + } + + /* Store back state */ + State[0] = (uint8_t) (Temp >> 0); + State[1] = (uint8_t) (Temp >> 8); + State[2] = (uint8_t) (Temp >> 16); + State[3] = (uint8_t) (Temp >> 24); + } + + +} + +void Crypto1EncryptWithParity(uint8_t * Buffer, uint16_t BitCount) +{ + uint8_t i = 0; + while (i < BitCount) + { + Buffer[i/8] ^= Crypto1FilterOutput() << (i % 8); + if (++i % 9 != 0) // only shift, if this was no parity bit + Crypto1LFSR(0); + } +} + +void Crypto1ReaderAuthWithParity(uint8_t PlainReaderAnswerWithParityBits[9]) +{ + uint8_t i = 0, feedback; + while (i < 72) + { + feedback = PlainReaderAnswerWithParityBits[i/8] >> (i % 8); + PlainReaderAnswerWithParityBits[i/8] ^= Crypto1FilterOutput() << (i % 8); + if (++i % 9 != 0) // only shift, if this was no parity bit + { + if (i <= 36) + Crypto1LFSR(feedback & 1); + else + Crypto1LFSR(0); + } + } +} diff --git a/Firmware/Chameleon-Mini/Application/Crypto1.h b/Firmware/Chameleon-Mini/Application/Crypto1.h new file mode 100644 index 00000000..dd4dfbcc --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Crypto1.h @@ -0,0 +1,38 @@ +#ifndef CRYPTO1_H +#define CRYPTO1_H + +#include +#include + +/* Gets the current keystream-bit, without shifting the internal LFSR */ +uint8_t Crypto1FilterOutput(void); + +/* Set up Crypto1 cipher using the given Key, Uid and CardNonce. Also encrypts + * the CardNonce in-place while in non-linear mode. */ +void Crypto1Setup(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4]); + +/* Set up Crypto1 cipher using the given Key, Uid and CardNonce. Nested indicates + * whether the CardNonce is encrypted (true) or not (false). + * If the CardNonce is encrypted, it will we decrypted in-place. If not, it will + * be fed into the LFSR, but remains unchanged. */ +void Crypto1SetupReader(uint8_t Key[6], uint8_t Uid[4], uint8_t CardNonce[4], bool Nested); + +/* Load the decrypted ReaderNonce into the Crypto1 state LFSR */ +void Crypto1Auth(uint8_t EncryptedReaderNonce[4]); + +/* Generate 8 Bits of key stream */ +uint8_t Crypto1Byte(void); + +/* Generate 4 Bits of key stream */ +uint8_t Crypto1Nibble(void); + +/* Execute 'ClockCount' cycles on the PRNG state 'State' */ +void Crypto1PRNG(uint8_t State[4], uint16_t ClockCount); + +/* Encrypts buffer with consideration of parity bits */ +void Crypto1EncryptWithParity(uint8_t * Buffer, uint16_t BitCount); + +/* Encrypts buffer with LFSR feedback within reader nonce and considers parity bits */ +void Crypto1ReaderAuthWithParity(uint8_t PlainReaderAnswerWithParityBits[9]); + +#endif //CRYPTO1_H diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c new file mode 100644 index 00000000..4818be21 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -0,0 +1,156 @@ +/* + * ISO14443A.c + * + * Created on: 19.03.2013 + * Author: skuser + */ + +#include "ISO14443-3A.h" + +#define CRC_INIT 0x6363 +#define CRC_INIT_R 0xC6C6 /* Bit reversed */ + +#define USE_HW_CRC + +#ifdef USE_HW_CRC +void ISO14443AAppendCRCA(void* Buffer, uint16_t ByteCount) +{ + uint8_t* DataPtr = (uint8_t*) Buffer; + + CRC.CTRL = CRC_RESET0_bm; + CRC.CHECKSUM1 = (CRC_INIT_R >> 8) & 0xFF; + CRC.CHECKSUM0 = (CRC_INIT_R >> 0) & 0xFF; + CRC.CTRL = CRC_SOURCE_IO_gc; + + while(ByteCount--) { + uint8_t Byte = *DataPtr++; + Byte = BitReverseByte(Byte); + + CRC.DATAIN = Byte; + } + + DataPtr[0] = BitReverseByte(CRC.CHECKSUM1); + DataPtr[1] = BitReverseByte(CRC.CHECKSUM0); + + CRC.CTRL = CRC_SOURCE_DISABLE_gc; +} +#else +#include +void ISO14443AAppendCRCA(void* Buffer, uint16_t ByteCount) +{ + uint16_t Checksum = CRC_INIT; + uint8_t* DataPtr = (uint8_t*) Buffer; + + while(ByteCount--) { + uint8_t Byte = *DataPtr++; + Checksum = _crc_ccitt_update(Checksum, Byte); + } + + DataPtr[0] = (Checksum >> 0) & 0x00FF; + DataPtr[1] = (Checksum >> 8) & 0x00FF; +} +#endif + +#ifdef USE_HW_CRC +bool ISO14443ACheckCRCA(void* Buffer, uint16_t ByteCount) +{ + uint8_t* DataPtr = (uint8_t*) Buffer; + + CRC.CTRL = CRC_RESET0_bm; + CRC.CHECKSUM1 = (CRC_INIT_R >> 8) & 0xFF; + CRC.CHECKSUM0 = (CRC_INIT_R >> 0) & 0xFF; + CRC.CTRL = CRC_SOURCE_IO_gc; + + while(ByteCount--) { + uint8_t Byte = *DataPtr++; + Byte = BitReverseByte(Byte); + + CRC.DATAIN = Byte; + } + + bool Result = (DataPtr[0] == BitReverseByte(CRC.CHECKSUM1)) && (DataPtr[1] == BitReverseByte(CRC.CHECKSUM0)); + + CRC.CTRL = CRC_SOURCE_DISABLE_gc; + + return Result; +} +#else +#include +bool ISO14443ACheckCRCA(void* Buffer, uint16_t ByteCount) +{ + uint16_t Checksum = CRC_INIT; + uint8_t* DataPtr = (uint8_t*) Buffer; + + while(ByteCount--) { + uint8_t Byte = *DataPtr++; + + Checksum = _crc_ccitt_update(Checksum, Byte); + } + + return (DataPtr[0] == ((Checksum >> 0) & 0xFF)) && (DataPtr[1] == ((Checksum >> 8) & 0xFF)); +} +#endif + +#if 0 +bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue) +{ + uint8_t* DataPtr = (uint8_t*) Buffer; + uint8_t NVB = DataPtr[1]; + //uint8_t CollisionByteCount = (NVB >> 4) & 0x0F; + //uint8_t CollisionBitCount = (NVB >> 0) & 0x0F; + + switch (NVB) { + case ISO14443A_NVB_AC_START: + /* Start of anticollision procedure. + * Send whole UID CLn + BCC */ + DataPtr[0] = UidCL[0]; + DataPtr[1] = UidCL[1]; + DataPtr[2] = UidCL[2]; + DataPtr[3] = UidCL[3]; + DataPtr[4] = ISO14443A_CALC_BCC(DataPtr); + + *BitCount = ISO14443A_CL_FRAME_SIZE; + + return false; + + case ISO14443A_NVB_AC_END: + /* End of anticollision procedure. + * Send SAK CLn if we are selected. */ + if ( (DataPtr[2] == UidCL[0]) && + (DataPtr[3] == UidCL[1]) && + (DataPtr[4] == UidCL[2]) && + (DataPtr[5] == UidCL[3]) ) { + + DataPtr[0] = SAKValue; + ISO14443AAppendCRCA(Buffer, 1); + + *BitCount = ISO14443A_SAK_FRAME_SIZE; + return true; + } else { + /* We have not been selected. Don't send anything. */ + *BitCount = 0; + return false; + } + default: + /* TODO: No anticollision supported */ + *BitCount = 0; + return false; + } +} + +bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue) +{ + uint8_t* DataPtr = (uint8_t*) Buffer; + + if ( (DataPtr[0] == ISO14443A_CMD_REQA) || (DataPtr[0] == ISO14443A_CMD_WUPA) ){ + DataPtr[0] = (ATQAValue >> 0) & 0x00FF; + DataPtr[1] = (ATQAValue >> 8) & 0x00FF; + + *BitCount = ISO14443A_ATQA_FRAME_SIZE; + + return true; + } else { + return false; + } +} +#endif diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h new file mode 100644 index 00000000..87f6ff29 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -0,0 +1,117 @@ +/* + * ISO14443-2A.h + * + * Created on: 19.03.2013 + * Author: skuser + */ + +#ifndef ISO14443_3A_H_ +#define ISO14443_3A_H_ + +#include "../Common.h" + +#define ISO14443A_UID_SIZE_SINGLE 4 /* bytes */ +#define ISO14443A_UID_SIZE_DOUBLE 7 +#define ISO14443A_UID_SIZE_TRIPLE 10 + +#define ISO14443A_CMD_REQA 0x26 +#define ISO14443A_CMD_WUPA 0x52 +#define ISO14443A_CMD_SELECT_CL1 0x93 +#define ISO14443A_CMD_SELECT_CL2 0x95 +#define ISO14443A_CMD_SELECT_CL3 0x97 +#define ISO14443A_CMD_HLTA 0x50 + +#define ISO14443A_NVB_AC_START 0x20 +#define ISO14443A_NVB_AC_END 0x70 + +#define ISO14443A_CL_UID_OFFSET 0 +#define ISO14443A_CL_UID_SIZE 4 +#define ISO14443A_CL_BCC_OFFSET 4 +#define ISO14443A_CL_BCC_SIZE 1 /* Byte */ +#define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */ +#define ISO14443A_SAK_INCOMPLETE 0x04 +#define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20 +#define ISO14443A_SAK_COMPLETE_NOT_COMPLIANT 0x00 + +#define ISO14443A_ATQA_FRAME_SIZE (2 * 8) /* Bit */ +#define ISO14443A_SAK_FRAME_SIZE (3 * 8) /* Bit */ + +#define ISO14443A_UID0_RANDOM 0x08 +#define ISO14443A_UID0_CT 0x88 + +#define ISO14443A_CRCA_SIZE 2 + +#define ISO14443A_CALC_BCC(ByteBuffer) \ + ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] ) + +void ISO14443AAppendCRCA(void* Buffer, uint16_t ByteCount); +bool ISO14443ACheckCRCA(void* Buffer, uint16_t ByteCount); + +INLINE bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue); +INLINE bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue); + +INLINE +bool ISO14443ASelect(void* Buffer, uint16_t* BitCount, uint8_t* UidCL, uint8_t SAKValue) +{ + uint8_t* DataPtr = (uint8_t*) Buffer; + uint8_t NVB = DataPtr[1]; + //uint8_t CollisionByteCount = (NVB >> 4) & 0x0F; + //uint8_t CollisionBitCount = (NVB >> 0) & 0x0F; + + switch (NVB) { + case ISO14443A_NVB_AC_START: + /* Start of anticollision procedure. + * Send whole UID CLn + BCC */ + DataPtr[0] = UidCL[0]; + DataPtr[1] = UidCL[1]; + DataPtr[2] = UidCL[2]; + DataPtr[3] = UidCL[3]; + DataPtr[4] = ISO14443A_CALC_BCC(DataPtr); + + *BitCount = ISO14443A_CL_FRAME_SIZE; + + return false; + + case ISO14443A_NVB_AC_END: + /* End of anticollision procedure. + * Send SAK CLn if we are selected. */ + if ( (DataPtr[2] == UidCL[0]) && + (DataPtr[3] == UidCL[1]) && + (DataPtr[4] == UidCL[2]) && + (DataPtr[5] == UidCL[3]) ) { + + DataPtr[0] = SAKValue; + ISO14443AAppendCRCA(Buffer, 1); + + *BitCount = ISO14443A_SAK_FRAME_SIZE; + return true; + } else { + /* We have not been selected. Don't send anything. */ + *BitCount = 0; + return false; + } + default: + /* TODO: No anticollision supported */ + *BitCount = 0; + return false; + } +} + +INLINE +bool ISO14443AWakeUp(void* Buffer, uint16_t* BitCount, uint16_t ATQAValue) +{ + uint8_t* DataPtr = (uint8_t*) Buffer; + + if ( (DataPtr[0] == ISO14443A_CMD_REQA) || (DataPtr[0] == ISO14443A_CMD_WUPA) ){ + DataPtr[0] = (ATQAValue >> 0) & 0x00FF; + DataPtr[1] = (ATQAValue >> 8) & 0x00FF; + + *BitCount = ISO14443A_ATQA_FRAME_SIZE; + + return true; + } else { + return false; + } +} + +#endif diff --git a/Firmware/Chameleon-Mini/Application/MifareClassic.c b/Firmware/Chameleon-Mini/Application/MifareClassic.c new file mode 100644 index 00000000..b11848a3 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/MifareClassic.c @@ -0,0 +1,713 @@ +/* + * MifareClassic.c + * + * Created on: 13.05.2013 + * Author: skuser + */ + +#include "MifareClassic.h" + +#include "ISO14443-3A.h" +#include "../Codec/ISO14443-2A.h" +#include "../Memory.h" +#include "Crypto1.h" +#include "../Random.h" + +#define MFCLASSIC_1K_ATQA_VALUE 0x0004 +#define MFCLASSIC_1K_7B_ATQA_VALUE 0x0044 +#define MFCLASSIC_4K_ATQA_VALUE 0x0002 +#define MFCLASSIC_4K_7B_ATQA_VALUE 0x0042 + +#define MFCLASSIC_1K_SAK_VALUE 0x08 +#define MFCLASSIC_4K_SAK_VALUE 0x18 +#define SAK_UID_NOT_FINISHED 0x04 + +#define MEM_UID_CL1_ADDRESS 0x00 +#define MEM_UID_CL1_SIZE 4 +#define MEM_UID_BCC1_ADDRESS 0x04 +#define MEM_UID_CL2_ADDRESS 0x03 +#define MEM_UID_CL2_SIZE 4 +#define MEM_KEY_A_OFFSET 48 /* Bytes */ +#define MEM_KEY_B_OFFSET 58 /* Bytes */ +#define MEM_KEY_BIGSECTOR_OFFSET 192 +#define MEM_KEY_SIZE 6 /* Bytes */ +#define MEM_SECTOR_ADDR_MASK 0xFC +#define MEM_BYTES_PER_BLOCK 16 /* Bytes */ +#define MEM_VALUE_SIZE 4 /* Bytes */ + +#define ACK_NAK_FRAME_SIZE 4 /* Bits */ +#define ACK_VALUE 0x0A +#define NAK_INVALID_ARG 0x00 +#define NAK_CRC_ERROR 0x01 +#define NAK_NOT_AUTHED 0x04 +#define NAK_EEPROM_ERROR 0x05 +#define NAK_OTHER_ERROR 0x06 + +#define CMD_AUTH_A 0x60 +#define CMD_AUTH_B 0x61 +#define CMD_AUTH_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_AUTH_RB_FRAME_SIZE 4 /* Bytes */ +#define CMD_AUTH_AB_FRAME_SIZE 8 /* Bytes */ +#define CMD_AUTH_BA_FRAME_SIZE 4 /* Bytes */ +#define CMD_HALT 0x50 +#define CMD_HALT_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_READ 0x30 +#define CMD_READ_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_READ_RESPONSE_FRAME_SIZE 16 /* Bytes without CRCA */ +#define CMD_WRITE 0xA0 +#define CMD_WRITE_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_DECREMENT 0xC0 +#define CMD_DECREMENT_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_INCREMENT 0xC1 +#define CMD_INCREMENT_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_RESTORE 0xC2 +#define CMD_RESTORE_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_TRANSFER 0xB0 +#define CMD_TRANSFER_FRAME_SIZE 2 /* Bytes without CRCA */ +#define CMD_CHINESE_UNLOCK 0x40 +#define CMD_CHINESE_WIPE 0x41 +#define CMD_CHINESE_UNLOCK_RW 0x43 + +static enum { + STATE_HALT, + STATE_IDLE, + STATE_CHINESE_IDLE, + STATE_CHINESE_WRITE, + STATE_READY1, + STATE_READY2, + STATE_ACTIVE, + STATE_AUTHING, + STATE_AUTHED_IDLE, + STATE_WRITE, + STATE_INCREMENT, + STATE_DECREMENT, + STATE_RESTORE +} State; + +static uint8_t CardResponse[4]; +static uint8_t ReaderResponse[4]; +static uint8_t CurrentAddress; +static uint8_t BlockBuffer[MEM_BYTES_PER_BLOCK]; +static uint16_t CardATQAValue; +static uint8_t CardSAKValue; + + +INLINE bool CheckValueIntegrity(uint8_t* Block) +{ + /* Value Blocks contain a value stored three times, with + * the middle portion inverted. */ + if ( (Block[0] == (uint8_t) ~Block[4]) && (Block[0] == Block[8]) + && (Block[1] == (uint8_t) ~Block[5]) && (Block[1] == Block[9]) + && (Block[2] == (uint8_t) ~Block[6]) && (Block[2] == Block[10]) + && (Block[3] == (uint8_t) ~Block[7]) && (Block[3] == Block[11]) + && (Block[12] == (uint8_t) ~Block[13]) + && (Block[12] == Block[14]) + && (Block[14] == (uint8_t) ~Block[15])) { + return true; + } else { + return false; + } +} + +INLINE void ValueFromBlock(uint32_t* Value, uint8_t* Block) +{ + *Value = 0; + *Value |= ((uint32_t) Block[0] << 0); + *Value |= ((uint32_t) Block[1] << 8); + *Value |= ((uint32_t) Block[2] << 16); + *Value |= ((uint32_t) Block[3] << 24); +} + +INLINE void ValueToBlock(uint8_t* Block, uint32_t Value) +{ + Block[0] = (uint8_t) (Value >> 0); + Block[1] = (uint8_t) (Value >> 8); + Block[2] = (uint8_t) (Value >> 16); + Block[3] = (uint8_t) (Value >> 24); + Block[4] = ~Block[0]; + Block[5] = ~Block[1]; + Block[6] = ~Block[2]; + Block[7] = ~Block[3]; + Block[8] = Block[0]; + Block[9] = Block[1]; + Block[10] = Block[2]; + Block[11] = Block[3]; +} + +void MifareClassicAppInit1K(void) +{ + State = STATE_IDLE; + CardATQAValue = MFCLASSIC_1K_ATQA_VALUE; + CardSAKValue = MFCLASSIC_1K_SAK_VALUE; +} + +void MifareClassicAppInit4K(void) +{ + State = STATE_IDLE; + CardATQAValue = MFCLASSIC_4K_7B_ATQA_VALUE; + CardSAKValue = MFCLASSIC_4K_SAK_VALUE; +} + +void MifareClassicAppReset(void) +{ + State = STATE_IDLE; +} + +void MifareClassicAppTask(void) +{ + +} + +uint16_t MifareClassicAppProcess(uint8_t* Buffer, uint16_t BitCount) +{ + switch(State) { + case STATE_IDLE: + case STATE_HALT: + if (ISO14443AWakeUp(Buffer, &BitCount, CardATQAValue)) { + State = STATE_READY1; + return BitCount; + } +#ifdef SUPPORT_MF_CLASSIC_MAGIC_MODE + else if (Buffer[0] == CMD_CHINESE_UNLOCK) { + State = STATE_CHINESE_IDLE; + Buffer[0] = ACK_VALUE; + return ACK_NAK_FRAME_SIZE; + } +#endif + break; + +#ifdef SUPPORT_MF_CLASSIC_MAGIC_MODE + case STATE_CHINESE_IDLE: + /* Support special china commands that dont require authentication. */ + if (Buffer[0] == CMD_CHINESE_UNLOCK_RW) { + /* Unlock read and write commands */ + Buffer[0] = ACK_VALUE; + return ACK_NAK_FRAME_SIZE; + } else if (Buffer[0] == CMD_CHINESE_WIPE) { + /* Wipe memory */ + Buffer[0] = ACK_VALUE; + return ACK_NAK_FRAME_SIZE; + } else if (Buffer[0] == CMD_READ) { + if (ISO14443ACheckCRCA(Buffer, CMD_READ_FRAME_SIZE)) { + /* Read command. Read data from memory and append CRCA. */ + MemoryReadBlock(Buffer, (uint16_t) Buffer[1] * MEM_BYTES_PER_BLOCK, MEM_BYTES_PER_BLOCK); + ISO14443AAppendCRCA(Buffer, MEM_BYTES_PER_BLOCK); + + return (CMD_READ_RESPONSE_FRAME_SIZE + ISO14443A_CRCA_SIZE ) + * BITS_PER_BYTE; + } else { + Buffer[0] = NAK_CRC_ERROR; + return ACK_NAK_FRAME_SIZE; + } + } else if (Buffer[0] == CMD_WRITE) { + if (ISO14443ACheckCRCA(Buffer, CMD_WRITE_FRAME_SIZE)) { + /* Write command. Store the address and prepare for the upcoming data. + * Respond with ACK. */ + CurrentAddress = Buffer[1]; + State = STATE_CHINESE_WRITE; + + Buffer[0] = ACK_VALUE; + return ACK_NAK_FRAME_SIZE; + } else { + Buffer[0] = NAK_CRC_ERROR; + return ACK_NAK_FRAME_SIZE; + } + } else if (Buffer[0] == CMD_HALT) { + /* Halts the tag. According to the ISO14443, the second + * byte is supposed to be 0. */ + if (Buffer[1] == 0) { + if (ISO14443ACheckCRCA(Buffer, CMD_HALT_FRAME_SIZE)) { + /* According to ISO14443, we must not send anything + * in order to acknowledge the HALT command. */ + LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + State = STATE_HALT; + return ISO14443A_APP_NO_RESPONSE; + } else { + Buffer[0] = NAK_CRC_ERROR; + return ACK_NAK_FRAME_SIZE; + } + } else { + Buffer[0] = NAK_INVALID_ARG; + return ACK_NAK_FRAME_SIZE; + } + } + break; + + case STATE_CHINESE_WRITE: + if (ISO14443ACheckCRCA(Buffer, MEM_BYTES_PER_BLOCK)) { + /* CRC check passed. Write data into memory and send ACK. */ + if (!ActiveConfiguration.ReadOnly) { + MemoryWriteBlock(Buffer, CurrentAddress * MEM_BYTES_PER_BLOCK, MEM_BYTES_PER_BLOCK); + } + + Buffer[0] = ACK_VALUE; + } else { + /* CRC Error. */ + Buffer[0] = NAK_CRC_ERROR; + } + + State = STATE_CHINESE_IDLE; + + return ACK_NAK_FRAME_SIZE; +#endif + + case STATE_READY1: + if (ISO14443AWakeUp(Buffer, &BitCount, CardATQAValue)) { + State = STATE_READY1; + return BitCount; + } else if (Buffer[0] == ISO14443A_CMD_SELECT_CL1) { + /* Load UID CL1 and perform anticollision */ + uint8_t UidCL1[ISO14443A_CL_UID_SIZE]; + /* For Longer UIDs indicate that more UID-Bytes follow (-> CL2) */ + if (ActiveConfiguration.UidSize == 7) { + MemoryReadBlock(&UidCL1[1], MEM_UID_CL1_ADDRESS, MEM_UID_CL1_SIZE-1); + UidCL1[0] = ISO14443A_UID0_CT; + if (ISO14443ASelect(Buffer, &BitCount, UidCL1, SAK_UID_NOT_FINISHED)) + State = STATE_READY2; + } else { + MemoryReadBlock(UidCL1, MEM_UID_CL1_ADDRESS, MEM_UID_CL1_SIZE); + if (ISO14443ASelect(Buffer, &BitCount, UidCL1, CardSAKValue)) + State = STATE_ACTIVE; + } + + return BitCount; + } else { + /* Unknown command. Enter HALT state. */ + State = STATE_HALT; + } + break; + + case STATE_READY2: + if (ISO14443AWakeUp(Buffer, &BitCount, CardATQAValue)) { + State = STATE_READY1; + return BitCount; + } else if (Buffer[0] == ISO14443A_CMD_SELECT_CL2) { + /* Load UID CL2 and perform anticollision */ + uint8_t UidCL2[ISO14443A_CL_UID_SIZE]; + MemoryReadBlock(UidCL2, MEM_UID_CL2_ADDRESS, MEM_UID_CL2_SIZE); + + if (ISO14443ASelect(Buffer, &BitCount, UidCL2, CardSAKValue)) { + State = STATE_ACTIVE; + } + + return BitCount; + } else { + /* Unknown command. Enter HALT state. */ + State = STATE_HALT; + } + break; + case STATE_ACTIVE: + if (ISO14443AWakeUp(Buffer, &BitCount, MFCLASSIC_1K_ATQA_VALUE)) { + State = STATE_READY1; + return BitCount; + } else if (Buffer[0] == CMD_HALT) { + /* Halts the tag. According to the ISO14443, the second + * byte is supposed to be 0. */ + if (Buffer[1] == 0) { + if (ISO14443ACheckCRCA(Buffer, CMD_HALT_FRAME_SIZE)) { + /* According to ISO14443, we must not send anything + * in order to acknowledge the HALT command. */ + LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + + State = STATE_HALT; + return ISO14443A_APP_NO_RESPONSE; + } else { + Buffer[0] = NAK_CRC_ERROR; + return ACK_NAK_FRAME_SIZE; + } + } else { + Buffer[0] = NAK_INVALID_ARG; + return ACK_NAK_FRAME_SIZE; + } + } else if ( (Buffer[0] == CMD_AUTH_A) || (Buffer[0] == CMD_AUTH_B)) { + if (ISO14443ACheckCRCA(Buffer, CMD_AUTH_FRAME_SIZE)) + { + /* Fix for MFClassic 4k cards */ + uint16_t SectorAddress = Buffer[1] & MEM_SECTOR_ADDR_MASK; + uint16_t KeyOffset = (Buffer[0] == CMD_AUTH_A ? MEM_KEY_A_OFFSET : MEM_KEY_B_OFFSET); + uint16_t KeyAddress = (uint16_t) SectorAddress * MEM_BYTES_PER_BLOCK + KeyOffset; + + if(Buffer[1] >= 128) + { + KeyAddress = (Buffer[1] & 0xF0) * 16 + KeyOffset + MEM_KEY_BIGSECTOR_OFFSET; + } + uint8_t Key[6]; + uint8_t Uid[4]; + uint8_t CardNonce[4]; + + LogEntry(LOG_INFO_APP_CMD_AUTH, Buffer, 2); + + /* Generate a random nonce and read UID and key from memory */ + RandomGetBuffer(CardNonce, sizeof(CardNonce)); + if (ActiveConfiguration.UidSize == 7) + MemoryReadBlock(Uid, MEM_UID_CL2_ADDRESS, MEM_UID_CL2_SIZE); + else + MemoryReadBlock(Uid, MEM_UID_CL1_ADDRESS, MEM_UID_CL1_SIZE); + MemoryReadBlock(Key, KeyAddress, MEM_KEY_SIZE); + + /* Precalculate the reader response from card-nonce */ + for (uint8_t i=0; i= 128) + { + KeyAddress = (Buffer[1] & 0xF0) * 16 + KeyOffset + MEM_KEY_BIGSECTOR_OFFSET; + } + + uint8_t Key[6]; + uint8_t Uid[4]; + uint8_t CardNonce[4]; + + LogEntry(LOG_INFO_APP_CMD_AUTH, Buffer, 2); + + /* Generate a random nonce and read UID and key from memory */ + RandomGetBuffer(CardNonce, sizeof(CardNonce)); + if (ActiveConfiguration.UidSize == 7) + MemoryReadBlock(Uid, MEM_UID_CL2_ADDRESS, MEM_UID_CL2_SIZE); + else + MemoryReadBlock(Uid, MEM_UID_CL1_ADDRESS, MEM_UID_CL1_SIZE); + MemoryReadBlock(Key, KeyAddress, MEM_KEY_SIZE); + + /* Precalculate the reader response from card-nonce */ + for (uint8_t i=0; i= PAGE_READ_MIN) + && (PageAddress <= PAGE_READ_MAX) ) { + /* TODO: Missing address wrap around behaviour. + * Implement using a for-loop copying 4 bytes each iteration + * and mask pageaddress */ + MemoryReadBlock(Buffer, PageAddress * BYTES_PER_PAGE, BYTES_PER_READ); + ISO14443AAppendCRCA(Buffer, BYTES_PER_READ); + return (BYTES_PER_READ + ISO14443A_CRCA_SIZE) * 8; + } else { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + } else { + Buffer[0] = NAK_CRC_ERROR; + return NAK_FRAME_SIZE; + } + } else if (Cmd == CMD_WRITE) { + /* This is a write command containing 4 bytes of data that + * should be written to the given page address. */ + uint8_t PageAddress = Buffer[1]; + if (ISO14443ACheckCRCA(Buffer, CMD_WRITE_FRAME_SIZE)) { + /* CRC check passed */ + if ( (PageAddress >= PAGE_WRITE_MIN) + && (PageAddress <= PAGE_WRITE_MAX) ) { + /* PageAddress is within bounds. */ + + if (!ActiveConfiguration.ReadOnly) { + MemoryWriteBlock(&Buffer[2], PageAddress * BYTES_PER_PAGE, BYTES_PER_WRITE); + } else { + /* If the chameleon is in read only mode, it silently + * ignores any attempt to write data. */ + } + + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + + } else { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + } else { + Buffer[0] = NAK_CRC_ERROR; + return NAK_FRAME_SIZE; + } + } else if (Cmd == CMD_COMPAT_WRITE) { + /* The Mifare compatbility write command is a 2-frame command. + * The first frame contains the page-address and the second frame + * holds the data. */ + uint8_t PageAddress = Buffer[1]; + + if (ISO14443ACheckCRCA(Buffer, CMD_COMPAT_WRITE_FRAME_SIZE)) { + if ( (PageAddress >= PAGE_WRITE_MIN) + && (PageAddress <= PAGE_WRITE_MAX) ) { + /* CRC check passed and page-address is within bounds. + * Store address and proceed to receiving the data. */ + CompatWritePageAddress = PageAddress; + State = STATE_COMPAT_WRITE; + + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } else { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + } else { + Buffer[0] = NAK_CRC_ERROR; + return NAK_FRAME_SIZE; + } + } else if (Cmd == CMD_HALT) { + /* Halts the tag. According to the ISO14443, the second + * byte is supposed to be 0. */ + if (Buffer[1] == 0) { + if (ISO14443ACheckCRCA(Buffer, 2)) { + /* According to ISO14443, we must not send anything + * in order to acknowledge the HALT command. */ + State = STATE_HALT; + return ISO14443A_APP_NO_RESPONSE; + } else { + Buffer[0] = NAK_CRC_ERROR; + return NAK_FRAME_SIZE; + } + } else { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + } else { + /* Unknown command. Enter halt state */ + State = STATE_IDLE; + } + break; + + case STATE_COMPAT_WRITE: + /* Compatibility write. Receiving 16 bytes of data of which 4 bytes are valid. */ + if (ISO14443ACheckCRCA(Buffer, BYTES_PER_COMPAT_WRITE)) { + /* We don't perform any checks here. You will be able to program the + * whole memory. Also there is no OTP behaviour. */ + if (!ActiveConfiguration.ReadOnly) { + MemoryWriteBlock(Buffer, CompatWritePageAddress * BYTES_PER_PAGE, BYTES_PER_WRITE); + } else { + /* If we are told to be read only, we silently ignore the write command + * and pretend to have written data. */ + } + + State = STATE_ACTIVE; + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } else { + State = STATE_ACTIVE; + Buffer[0] = NAK_CRC_ERROR; + return NAK_FRAME_SIZE; + } + + default: + /* Unknown state? Should never happen. */ + break; + } + + /* No response has been sent, when we reach here */ + return ISO14443A_APP_NO_RESPONSE; +} + +void MifareUltralightGetUid(ConfigurationUidType Uid) +{ + /* Read UID from memory */ + MemoryReadBlock(&Uid[0], UID_CL1_ADDRESS, UID_CL1_SIZE); + MemoryReadBlock(&Uid[UID_CL1_SIZE], UID_CL2_ADDRESS, UID_CL2_SIZE); +} + +void MifareUltralightSetUid(ConfigurationUidType Uid) +{ + /* Calculate check bytes and write everything into memory */ + uint8_t BCC1 = ISO14443A_UID0_CT ^ Uid[0] ^ Uid[1] ^ Uid[2]; + uint8_t BCC2 = Uid[3] ^ Uid[4] ^ Uid[5] ^ Uid[6]; + + MemoryWriteBlock(&Uid[0], UID_CL1_ADDRESS, UID_CL1_SIZE); + MemoryWriteBlock(&BCC1, UID_BCC1_ADDRESS, ISO14443A_CL_BCC_SIZE); + MemoryWriteBlock(&Uid[UID_CL1_SIZE], UID_CL2_ADDRESS, UID_CL2_SIZE); + MemoryWriteBlock(&BCC2, UID_BCC2_ADDRESS, ISO14443A_CL_BCC_SIZE); +} + diff --git a/Firmware/Chameleon-Mini/Application/MifareUltralight.h b/Firmware/Chameleon-Mini/Application/MifareUltralight.h new file mode 100644 index 00000000..275685c4 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/MifareUltralight.h @@ -0,0 +1,28 @@ +/* + * MifareUltralight.h + * + * Created on: 20.03.2013 + * Author: skuser + */ + +#ifndef MIFAREULTRALIGHT_H_ +#define MIFAREULTRALIGHT_H_ + +#include "Application.h" +#include "ISO14443-3A.h" + +#define MIFARE_ULTRALIGHT_UID_SIZE ISO14443A_UID_SIZE_DOUBLE +#define MIFARE_ULTRALIGHT_MEM_SIZE 64 + +void MifareUltralightAppInit(void); +void MifareUltralightAppReset(void); +void MifareUltralightAppTask(void); + +uint16_t MifareUltralightAppProcess(uint8_t* Buffer, uint16_t BitCount); + +void MifareUltralightGetUid(ConfigurationUidType Uid); +void MifareUltralightSetUid(ConfigurationUidType Uid); + + + +#endif /* MIFAREULTRALIGHT_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c new file mode 100644 index 00000000..6018701d --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -0,0 +1,747 @@ +#include "Reader14443A.h" +#include "Application.h" +#include "ISO14443-3A.h" +#include "../Codec/Reader14443-2A.h" +#include "Crypto1.h" +#include "../System.h" + +#include "../Terminal/Terminal.h" + +#define CHECK_BCC(B) ((B[0] ^ B[1] ^ B[2] ^ B[3]) == B[4]) +#define IS_CASCADE_BIT_SET(buf) (buf[0] & 0x04) +#define IS_ISO14443A_4_COMPLIANT(buf) (buf[0] & 0x20) + +// TODO replace remaining magic numbers + +static bool Selected = false; +Reader14443Command Reader14443CurrentCommand = Reader14443_Do_Nothing; + +static enum { + STATE_IDLE, + STATE_HALT, + STATE_READY, + STATE_ACTIVE_CL1, // must be ordered sequentially + STATE_ACTIVE_CL2, + STATE_ACTIVE_CL3, + STATE_SAK_CL1, // must be ordered sequentially + STATE_SAK_CL2, + STATE_SAK_CL3, + STATE_ATS, + STATE_DESELECT, + STATE_DESFIRE_INFO, + STATE_END +} ReaderState = STATE_IDLE; + +static struct { + uint16_t ATQA; + uint8_t SAK; + uint8_t UID[10]; + enum { + UIDSize_No_UID = 0, + UIDSize_Single = 4, + UIDSize_Double = 7, + UIDSize_Triple = 10 + } UIDSize; +} CardCharacteristics = {0}; + +typedef enum { + CardType_NXP_MIFARE_Mini = 0, // do NOT assign another CardType item with a specific value since there are loops over this type + CardType_NXP_MIFARE_Classic_1k, + CardType_NXP_MIFARE_Classic_4k, + CardType_NXP_MIFARE_Ultralight, + CardType_NXP_MIFARE_DESFire, + CardType_NXP_MIFARE_DESFire_EV1, + CardType_IBM_JCOP31, + CardType_IBM_JCOP31_v241, + CardType_IBM_JCOP41_v22, + CardType_IBM_JCOP41_v231, + CardType_Infineon_MIFARE_Classic_1k, + CardType_Gemplus_MPCOS, + CardType_Innovision_Jewel, + CardType_Nokia_MIFARE_Classic_4k_emulated_6212, + CardType_Nokia_MIFARE_Classic_4k_emulated_6131 +} CardType; + +typedef struct { + uint16_t ATQA; + bool ATQARelevant; + + uint8_t SAK; + bool SAKRelevant; + + uint8_t ATS[16]; + uint8_t ATSSize; + bool ATSRelevant; + + char Manufacturer[16]; + char Type[64]; +} CardIdentificationType; + +static const CardIdentificationType PROGMEM CardIdentificationList[] = { + [CardType_NXP_MIFARE_Mini] = { .ATQA=0x0004, .ATQARelevant=true, .SAK=0x09, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Mini" }, + [CardType_NXP_MIFARE_Classic_1k] = { .ATQA=0x0004, .ATQARelevant=true, .SAK=0x08, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Classic 1k" }, + [CardType_NXP_MIFARE_Classic_4k] = { .ATQA=0x0002, .ATQARelevant=true, .SAK=0x18, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Classic 4k" }, + [CardType_NXP_MIFARE_Ultralight] = { .ATQA=0x0044, .ATQARelevant=true, .SAK=0x00, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Ultralight" }, + // for the following two, setting ATSRelevant to true would cause checking the ATS value, but the NXP paper for distinguishing cards does not recommend this + [CardType_NXP_MIFARE_DESFire] = { .ATQA=0x0344, .ATQARelevant=true, .SAK=0x20, .SAKRelevant=true, .ATSRelevant=false, .ATSSize= 5, .ATS={0x75, 0x77, 0x81, 0x02, 0x80}, .Manufacturer="NXP", .Type="MIFARE DESFire" }, + [CardType_NXP_MIFARE_DESFire_EV1] = { .ATQA=0x0344, .ATQARelevant=true, .SAK=0x20, .SAKRelevant=true, .ATSRelevant=false, .ATSSize= 5, .ATS={0x75, 0x77, 0x81, 0x02, 0x80}, .Manufacturer="NXP", .Type="MIFARE DESFire EV1" }, + [CardType_IBM_JCOP31] = { .ATQA=0x0304, .ATQARelevant=true, .SAK=0x28, .SAKRelevant=true, .ATSRelevant=true, .ATSSize= 9, .ATS={0x38, 0x77, 0xb1, 0x4a, 0x43, 0x4f, 0x50, 0x33, 0x31}, .Manufacturer="IBM", .Type="JCOP31" }, + [CardType_IBM_JCOP31_v241] = { .ATQA=0x0048, .ATQARelevant=true, .SAK=0x20, .SAKRelevant=true, .ATSRelevant=true, .ATSSize=12, .ATS={0x78, 0x77, 0xb1, 0x02, 0x4a, 0x43, 0x4f, 0x50, 0x76, 0x32, 0x34, 0x31}, .Manufacturer="IBM", .Type="JCOP31 v2.4.1" }, + [CardType_IBM_JCOP41_v22] = { .ATQA=0x0048, .ATQARelevant=true, .SAK=0x20, .SAKRelevant=true, .ATSRelevant=true, .ATSSize=12, .ATS={0x38, 0x33, 0xb1, 0x4a, 0x43, 0x4f, 0x50, 0x34, 0x31, 0x56, 0x32, 0x32}, .Manufacturer="IBM", .Type="JCOP41 v2.2" }, + [CardType_IBM_JCOP41_v231] = { .ATQA=0x0004, .ATQARelevant=true, .SAK=0x28, .SAKRelevant=true, .ATSRelevant=true, .ATSSize=13, .ATS={0x38, 0x33, 0xb1, 0x4a, 0x43, 0x4f, 0x50, 0x34, 0x31, 0x56, 0x32, 0x33, 0x31}, .Manufacturer="IBM", .Type="JCOP41 v2.3.1" }, + [CardType_Infineon_MIFARE_Classic_1k] = { .ATQA=0x0004, .ATQARelevant=true, .SAK=0x88, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="Infineon", .Type="MIFARE Classic 1k" }, + [CardType_Gemplus_MPCOS] = { .ATQA=0x0002, .ATQARelevant=true, .SAK=0x98, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="Gemplus", .Type="MPCOS" }, + [CardType_Innovision_Jewel] = { .ATQA=0x0C00, .ATQARelevant=true, .SAKRelevant=false, .ATSRelevant=false, .Manufacturer="Innovision R&T", .Type="Jewel" }, + [CardType_Nokia_MIFARE_Classic_4k_emulated_6212] = { .ATQA=0x0002, .ATQARelevant=true, .SAK=0x38, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="Nokia", .Type="MIFARE Classic 4k - emulated (6212 Classic)" }, + [CardType_Nokia_MIFARE_Classic_4k_emulated_6131] = { .ATQA=0x0008, .ATQARelevant=true, .SAK=0x38, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="Nokia", .Type="MIFARE Classic 4k - emulated (6131 NFC)" } +}; + +static CardType CardCandidates[sizeof(CardIdentificationList) / sizeof(CardIdentificationType)]; +static uint8_t CardCandidatesIdx = 0; + +uint16_t addParityBits(uint8_t * Buffer, uint16_t BitCount) +{ + uint8_t i = CardIdentificationList[0].ATQA; + if (i == 0) + return 0; + if (BitCount == 7) + return 7; + if (BitCount % 8) + return BitCount; + uint8_t * currByte, * tmpByte; + uint8_t * const lastByte = Buffer + BitCount/8 + BitCount/64; // starting address + number of bytes + number of parity bytes + currByte = Buffer + BitCount/8 - 1; + uint8_t parity; + memset(currByte+1, 0, lastByte-currByte); // zeroize all bytes used for parity bits + while (currByte >= Buffer) // loop over all input bytes + { + parity = OddParityBit(*currByte); // get parity bit + tmpByte = lastByte; + while (tmpByte > currByte) // loop over all bytes from the last byte to the current one -- shifts the whole byte string + { + *tmpByte <<= 1; // shift this byte + *tmpByte |= (*(tmpByte-1) & 0x80) >> 7; // insert the last bit from the previous byte + tmpByte--; // go to the previous byte + } + *(++tmpByte) &= 0xFE; // zeroize the bit, where we want to put the parity bit + *tmpByte |= parity & 1; // add the parity bit + currByte--; // go to previous input byte + } + return BitCount + (BitCount / 8); +} + +uint16_t removeParityBits(uint8_t * Buffer, uint16_t BitCount) +{ + if (BitCount == 7) + return 7; + + uint16_t i; + for (i = 0; i < (BitCount / 9); i++) + { + Buffer[i] = (Buffer[i + i/8] >> (i%8)); + if (i%8) + Buffer[i] |= (Buffer[i + i/8 + 1] << (8 - (i % 8))); + } + return BitCount/9*8; +} + +uint16_t removeSOC(uint8_t * Buffer, uint16_t BitCount) +{ + if (BitCount == 0) + return 0; + uint16_t i; + Buffer[0] >>= 1; + for (i = 1; i < (BitCount + 7) / 8; i++) + { + Buffer[i-1] |= Buffer[i] << 7; + Buffer[i] >>= 1; + } + return BitCount - 1; +} + +bool checkParityBits(uint8_t * Buffer, uint16_t BitCount) +{ + if (BitCount == 7) + return true; + + //if (BitCount % 9 || BitCount == 0) + // return false; + + uint16_t i; + uint8_t currentByte, parity; + for (i = 0; i < (BitCount / 9); i++) + { + currentByte = (Buffer[i + i/8] >> (i%8)); + if (i%8) + currentByte |= (Buffer[i + i/8 + 1] << (8 - (i % 8))); + parity = OddParityBit(currentByte); + if (((Buffer[i + i/8 + 1] >> (i % 8)) ^ parity) & 1) { + return false; + } + } + return true; +} + +void Reader14443AAppTimeout(void) +{ + Reader14443AAppReset(); + Reader14443ACodecReset(); + ReaderState = STATE_IDLE; +} + +void Reader14443AAppInit(void) +{ + ReaderState = STATE_IDLE; +} + +void Reader14443AAppReset(void) +{ + ReaderState = STATE_IDLE; + Reader14443CurrentCommand = Reader14443_Do_Nothing; + Selected = false; +} + +void Reader14443AAppTask(void) +{ + +} + +void Reader14443AAppTick(void) +{ + +} + +INLINE uint16_t Reader14443A_Deselect(uint8_t* Buffer) // deselects the card because of an error, so we will continue to select the card afterwards +{ + Buffer[0] = 0xC2; + uint16_t crc = ISO14443_CRCA(Buffer, 1); + Buffer[1] = crc; + Buffer[2] = crc >> 8; + ReaderState = STATE_DESELECT; + Selected = false; + return addParityBits(Buffer, 24); +} + +INLINE uint16_t Reader14443A_Select(uint8_t * Buffer, uint16_t BitCount) +{ + if (Selected) + return 0; + switch (ReaderState) + { + case STATE_IDLE: + case STATE_HALT: + /* Send a REQA */ + Buffer[0] = ISO14443A_CMD_WUPA; // whenever REQA works, WUPA also works, so we choose WUPA always + ReaderState = STATE_READY; + return 7; + + case STATE_READY: + if (BitCount < 19) + { + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + BitCount = removeSOC(Buffer, BitCount); + if (!checkParityBits(Buffer, BitCount)) + { + ReaderState = STATE_IDLE; + LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, (BitCount + 8) / 7); + Reader14443ACodecStart(); + return 0; + } + BitCount = removeParityBits(Buffer, BitCount); + CardCharacteristics.ATQA = Buffer[1] << 8 | Buffer[0]; // save ATQA for possible later use + Buffer[0] = ISO14443A_CMD_SELECT_CL1; + Buffer[1] = 0x20; // NVB = 16 + ReaderState = STATE_ACTIVE_CL1; + return addParityBits(Buffer, 16); + + case STATE_ACTIVE_CL1 ... STATE_ACTIVE_CL3: + BitCount = removeSOC(Buffer, BitCount); + if (!checkParityBits(Buffer, BitCount) || BitCount < 8) + { + ReaderState = STATE_IDLE; + LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, (BitCount + 8) / 7); + Reader14443ACodecStart(); + return 0; + } + BitCount = removeParityBits(Buffer, BitCount); + if (!CHECK_BCC(Buffer)) + { + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + + if (Buffer[0] == ISO14443A_UID0_CT) + { + memcpy(CardCharacteristics.UID + (ReaderState - STATE_ACTIVE_CL1) * 3, Buffer + 1, 3); + } else { + memcpy(CardCharacteristics.UID + (ReaderState - STATE_ACTIVE_CL1) * 3, Buffer, 4); + } + // shift received UID two bytes to the right + memmove(Buffer+2, Buffer, 5); + Buffer[0] = (ReaderState == STATE_ACTIVE_CL1) ? ISO14443A_CMD_SELECT_CL1 : (ReaderState == STATE_ACTIVE_CL2) ? ISO14443A_CMD_SELECT_CL2 : ISO14443A_CMD_SELECT_CL3; + Buffer[1] = 0x70; // NVB = 56 + uint16_t crc = ISO14443_CRCA(Buffer, 7); + Buffer[7] = crc & 0xFF; + Buffer[8] = crc >> 8; + ReaderState = ReaderState - STATE_ACTIVE_CL1 + STATE_SAK_CL1; + return addParityBits(Buffer, 72); + + case STATE_SAK_CL1 ... STATE_SAK_CL3: + if (BitCount < 9) + { + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + BitCount = removeSOC(Buffer, BitCount); + if (!checkParityBits(Buffer, BitCount)) + { + LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, (BitCount + 8) / 7); + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + BitCount = removeParityBits(Buffer, BitCount); + if (ISO14443_CRCA(Buffer, 3)) + { + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + if (IS_CASCADE_BIT_SET(Buffer) && ReaderState != STATE_SAK_CL3) + { + Buffer[0] = (ReaderState == STATE_SAK_CL1) ? ISO14443A_CMD_SELECT_CL2 : ISO14443A_CMD_SELECT_CL3; + Buffer[1] = 0x20; // NVB = 16 bit + ReaderState = ReaderState - STATE_SAK_CL1 + STATE_ACTIVE_CL1 + 1; + return addParityBits(Buffer, 16); + } else if (IS_CASCADE_BIT_SET(Buffer) && ReaderState == STATE_SAK_CL3) { + // TODO handle this very strange hopefully not happening error + } + Selected = true; + CardCharacteristics.UIDSize = (ReaderState - STATE_SAK_CL1) * 3 + 4; + CardCharacteristics.SAK = Buffer[0]; // save last SAK for possible later use + + return 0; + + case STATE_DESELECT: + if (BitCount == 0) // most likely the card already understood the deselect + { + ReaderState = STATE_HALT; + Reader14443ACodecStart(); + return 0; + } + BitCount = removeSOC(Buffer, BitCount); + if (!checkParityBits(Buffer, BitCount)) + { + LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, (BitCount + 8) / 7); + return Reader14443A_Deselect(Buffer); + } + BitCount = removeParityBits(Buffer, BitCount); + if (ISO14443_CRCA(Buffer, 3)) + { + return Reader14443A_Deselect(Buffer); + } + ReaderState = STATE_HALT; + Reader14443ACodecStart(); + return 0; + + default: + return 0; + } +} + +INLINE uint16_t Reader14443A_Halt(uint8_t* Buffer) +{ + Buffer[0] = ISO14443A_CMD_HLTA; + Buffer[1] = 0x00; + uint16_t crc = ISO14443_CRCA(Buffer, 2); + Buffer[2] = crc; + Buffer[3] = crc >> 8; + ReaderState = STATE_HALT; + Selected = false; + return addParityBits(Buffer, 32); +} + +INLINE uint16_t Reader14443A_RATS(uint8_t* Buffer) +{ + Buffer[0] = 0xE0; // RATS command + Buffer[1] = 0x80; + uint16_t crc = ISO14443_CRCA(Buffer, 2); + Buffer[2] = crc; + Buffer[3] = crc >> 8; + ReaderState = STATE_ATS; + return addParityBits(Buffer, 32); +} + +uint16_t Reader14443AAppProcess(uint8_t* Buffer, uint16_t BitCount) +{ + switch (Reader14443CurrentCommand) + { + case Reader14443_Send: + { + if (ReaderSendBitCount) + { + memcpy(Buffer, ReaderSendBuffer, (ReaderSendBitCount + 7) / 8); + uint16_t tmp = addParityBits(Buffer, ReaderSendBitCount); + ReaderSendBitCount = 0; + return tmp; + } + + if (BitCount == 0) + { + char tmpBuf[] = "NO DATA"; + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + return 0; + } + char tmpBuf[128]; + BitCount = removeSOC(Buffer, BitCount); + bool parity = checkParityBits(Buffer, BitCount); + BitCount = removeParityBits(Buffer, BitCount); + if ((2 * (BitCount + 7) / 8 + 2 + 4) > 128) // 2 = \r\n, 4 = size of bitcount in hex + { + sprintf(tmpBuf, "Too many data."); + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + return 0; + } + uint16_t charCnt = BufferToHexString(tmpBuf, 128, Buffer, (BitCount + 7) / 8); + uint8_t count[2] = {(BitCount>>8)&0xFF, BitCount&0xFF}; + charCnt += snprintf(tmpBuf + charCnt, 128 - charCnt, "\r\n"); + charCnt += BufferToHexString(tmpBuf + charCnt, 128 - charCnt, count, 2); + if (!parity) + snprintf(tmpBuf + charCnt, 128 - charCnt, "\r\nPARITY ERROR"); + else + snprintf(tmpBuf + charCnt, 128 - charCnt, "\r\nPARITY OK"); + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + return 0; + } + + + case Reader14443_Send_Raw: + { + if (ReaderSendBitCount) + { + memcpy(Buffer, ReaderSendBuffer, (ReaderSendBitCount + 7) / 8); + uint16_t tmp = ReaderSendBitCount; + ReaderSendBitCount = 0; + return tmp; + } + + if (BitCount == 0) + { + char tmpBuf[] = "NO DATA"; + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + return 0; + } + + char tmpBuf[128]; + uint16_t charCnt = BufferToHexString(tmpBuf, 128, Buffer, (BitCount + 7) / 8); + uint8_t count[2] = {(BitCount>>8)&0xFF, BitCount&0xFF}; + charCnt += snprintf(tmpBuf + charCnt, 128 - charCnt, "\r\n"); + charCnt += BufferToHexString(tmpBuf + charCnt, 128 - charCnt, count, 2); + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + return 0; + } + + case Reader14443_Get_UID: + { + uint16_t rVal = Reader14443A_Select(Buffer, BitCount); + if (Selected) // we are done finding the UID + { + char tmpBuf[20]; + BufferToHexString(tmpBuf, 20, CardCharacteristics.UID, CardCharacteristics.UIDSize); + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + Selected = false; + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CodecReaderFieldStop(); + return 0; + } + return rVal; + } + + case Reader14443_Read_MF_Ultralight: + { + static uint8_t MFURead_CurrentAdress = 0; + static uint8_t MFUContents[64]; + + uint16_t rVal = Reader14443A_Select(Buffer, BitCount); + if (Selected) + { + if (MFURead_CurrentAdress != 0) + { + BitCount = removeSOC(Buffer, BitCount); + if (BitCount == 0) // relaunch select protocol + { + MFURead_CurrentAdress = 0; // reset read address + Selected = false; + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + bool readPageAgain = (BitCount < 162) || !checkParityBits(Buffer, BitCount); + BitCount = removeParityBits(Buffer, BitCount); + if (readPageAgain || ISO14443_CRCA(Buffer, 18)) // the CRC function should return 0 if everything is ok + { + MFURead_CurrentAdress -= 4; + } else { // everything is ok for this page + memcpy(MFUContents + (MFURead_CurrentAdress - 4) * 4, Buffer, 16); + } + } else { + uint16_t RefATQA; + memcpy_P(&RefATQA, &CardIdentificationList[CardType_NXP_MIFARE_Ultralight].ATQA, 2); + uint8_t RefSAK = pgm_read_byte(&CardIdentificationList[CardType_NXP_MIFARE_Ultralight].SAK); + if (CardCharacteristics.ATQA != RefATQA || CardCharacteristics.SAK != RefSAK) // seems to be no MiFare Ultralight card, so retry + { + ReaderState = STATE_IDLE; + Reader14443ACodecStart(); + return 0; + } + } + if (MFURead_CurrentAdress == 16) + { + Selected = false; + MFURead_CurrentAdress = 0; + Reader14443CurrentCommand = Reader14443_Do_Nothing; + + char tmpBuf[135]; // 135 = 128 hex digits + 3 * \r\n + \0 + BufferToHexString( tmpBuf, 135, MFUContents, 16); + snprintf( tmpBuf + 32, 135 - 32, "\r\n"); + BufferToHexString( tmpBuf + 32 + 2, 135 - 32 - 2, MFUContents + 16, 16); + snprintf( tmpBuf + 32 + 2 + 32, 135 - 32 - 2 - 32, "\r\n"); + BufferToHexString( tmpBuf + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2, MFUContents + 32, 16); + snprintf( tmpBuf + 32 + 2 + 32 + 2 + 32, 135 - 32 - 2 - 32 - 2 - 32, "\r\n"); + BufferToHexString( tmpBuf + 32 + 2 + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2 - 32 - 2, MFUContents + 48, 16); + CodecReaderFieldStop(); + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + return 0; + } + Buffer[0] = 0x30; // MiFare Ultralight read command + Buffer[1] = MFURead_CurrentAdress; + uint16_t crc = ISO14443_CRCA(Buffer, 2); + Buffer[2] = crc; + Buffer[3] = crc >> 8; + + MFURead_CurrentAdress += 4; + + return addParityBits(Buffer, 32); + } + return rVal; + } + + /************************************ + * This function identifies a PICC. * + ************************************/ + case Reader14443_Indentify: + { + uint16_t rVal = Reader14443A_Select(Buffer, BitCount); + if (Selected) + { + if (ReaderState >= STATE_SAK_CL1 && ReaderState <= STATE_SAK_CL3) + { + bool ISO14443_4A_compliant = IS_ISO14443A_4_COMPLIANT(Buffer); + + uint8_t i; + for (i = 0; i < sizeof(CardIdentificationList)/sizeof(CardIdentificationType); i++) + { + CardIdentificationType card; + memcpy_P(&card, &CardIdentificationList[i], sizeof(CardIdentificationType)); + if (card.ATQARelevant && card.ATQA != CardCharacteristics.ATQA) + continue; + if (card.SAKRelevant && card.SAK != CardCharacteristics.SAK) + continue; + if (card.ATSRelevant && !ISO14443_4A_compliant) + continue; // for this card type candidate, the ATS is relevant, but the card does not support ISO14443-4A + CardCandidates[CardCandidatesIdx++] = i; + } + + if (ISO14443_4A_compliant) + { + // send RATS + return Reader14443A_RATS(Buffer); + } + // if we don't have to send the RATS, we are finished for distinguishing with ISO 14443A + + } else if (ReaderState == STATE_ATS) { // we have got the ATS + BitCount = removeSOC(Buffer, BitCount); + if (!checkParityBits(Buffer, BitCount)) + { + LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, (BitCount + 8) / 7); + return Reader14443A_Deselect(Buffer); + } + BitCount = removeParityBits(Buffer, BitCount); + + if (Buffer[0] != BitCount / 8 - 2 || ISO14443_CRCA(Buffer, Buffer[0] + 2)) + { + return Reader14443A_Deselect(Buffer); + } + + uint8_t i; + for (i = 0; i < CardCandidatesIdx; i++) + { + CardIdentificationType card; + memcpy_P(&card, &CardIdentificationList[CardCandidates[i]], sizeof(CardIdentificationType)); + if (!card.ATSRelevant || (card.ATSRelevant && card.ATSSize == Buffer[0] - 1 && memcmp(card.ATS, Buffer + 1, card.ATSSize) == 0)) + /* + * If for this candidate the ATS is not relevant, it remains being a candidate. + * If the ATS is relevant and the size is correct and the ATS is the same as the reference value, this candidate remains a candidate. + */ + continue; + + // Else, we have to delete this candidate + uint8_t j; + for (j = i; j < CardCandidatesIdx - 1; j++) + CardCandidates[j] = CardCandidates[j+1]; + CardCandidatesIdx--; + i--; + } + } + + /* + * If any cards are not distinguishable with ISO14443A commands only, this is the place to run some proprietary commands. + */ + + if ((ReaderState >= STATE_SAK_CL1 && ReaderState <= STATE_SAK_CL3) || ReaderState == STATE_ATS) + { + uint8_t i; + for (i = 0; i < CardCandidatesIdx; i++) + { + switch (CardCandidates[i]) + { + case CardType_NXP_MIFARE_DESFire: + case CardType_NXP_MIFARE_DESFire_EV1: + Buffer[0] = 0x02; + Buffer[1] = 0x60; + uint16_t crc = ISO14443_CRCA(Buffer, 2); + Buffer[2] = crc; + Buffer[3] = crc >> 8; + ReaderState = STATE_DESFIRE_INFO; + return addParityBits(Buffer, 32); + + default: + break; + } + } + } else { + switch (ReaderState) + { + case STATE_DESFIRE_INFO: + if (BitCount == 0) + { + CardCandidatesIdx = 0; // this will return that this card is unknown to us + break; + } + BitCount = removeSOC(Buffer, BitCount); + if (!checkParityBits(Buffer, BitCount)) + { + LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, (BitCount + 8) / 7); + CardCandidatesIdx = 0; + return Reader14443A_Deselect(Buffer); + } + BitCount = removeParityBits(Buffer, BitCount); + if (ISO14443_CRCA(Buffer, BitCount / 8)) + { + CardCandidatesIdx = 0; + return Reader14443A_Deselect(Buffer); + } + switch (Buffer[3]) + { + case 0x00: + CardCandidatesIdx = 1; + CardCandidates[0] = CardType_NXP_MIFARE_DESFire; + break; + + case 0x01: + CardCandidatesIdx = 1; + CardCandidates[0] = CardType_NXP_MIFARE_DESFire_EV1; + break; + + default: + CardCandidatesIdx = 0; + } + break; + + default: + break; + } + } + + if (CardCandidatesIdx == 0) + { + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Unknown card type."); + } else if (CardCandidatesIdx == 1) { + char tmpType[64]; + memcpy_P(tmpType, &CardIdentificationList[CardCandidates[0]].Type, 64); + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpType); + } else { + char tmpBuf[TERMINAL_BUFFER_SIZE]; + uint16_t size = 0, tmpsize = 0; + bool enoughspace = true; + + uint8_t i; + for (i = 0; i < CardCandidatesIdx; i++) + { + if (size <= TERMINAL_BUFFER_SIZE) // prevents buffer overflow + { + char tmpType[64]; + memcpy_P(tmpType, &CardIdentificationList[CardCandidates[i]].Type, 64); + tmpsize = snprintf(tmpBuf + size, TERMINAL_BUFFER_SIZE - size, "%s or ", tmpType); + size += tmpsize; + } else { + break; + } + } + if (size > TERMINAL_BUFFER_SIZE) + { + size -= tmpsize; + enoughspace = false; + } + tmpBuf[size-4] = '.'; + tmpBuf[size-3] = '\0'; + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + if (!enoughspace) + TerminalSendString("There is at least one more card type candidate, but there was not enough terminal buffer space.\r\n"); + } + // print general data + TerminalSendString("ATQA:\t"); + CommandLineAppendData(&CardCharacteristics.ATQA, 2); + TerminalSendString("UID:\t"); + CommandLineAppendData(CardCharacteristics.UID, CardCharacteristics.UIDSize); + TerminalSendString("SAK:\t"); + CommandLineAppendData(&CardCharacteristics.SAK, 1); + + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CardCandidatesIdx = 0; + CodecReaderFieldStop(); + Selected = false; + return 0; + } + return rVal; + } + + default: // e.g. Do_Nothing + return 0; + } + return 0; +} + +uint16_t ISO14443_CRCA(uint8_t * Buffer, uint8_t ByteCount) +{ + uint8_t * DataPtr = Buffer; + uint16_t crc = 0x6363; + uint8_t ch; + while (ByteCount--) + { + ch = *DataPtr++ ^ crc; + ch = ch ^ (ch << 4); + crc = (crc >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4); + } + return crc; +} diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.h b/Firmware/Chameleon-Mini/Application/Reader14443A.h new file mode 100644 index 00000000..66f243fc --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.h @@ -0,0 +1,36 @@ +#ifndef READER14443A_H +#define READER14443A_H + +#include "Application.h" +#include "Codec/Codec.h" + +#define CRC_INIT 0x6363 + +uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE]; +uint16_t ReaderSendBitCount; + +void Reader14443AAppInit(void); +void Reader14443AAppReset(void); +void Reader14443AAppTask(void); +void Reader14443AAppTick(void); +void Reader14443AAppTimeout(void); + +uint16_t Reader14443AAppProcess(uint8_t* Buffer, uint16_t BitCount); + +uint16_t addParityBits(uint8_t * Buffer, uint16_t bits); +uint16_t removeParityBits(uint8_t * Buffer, uint16_t BitCount); +uint16_t removeSOC(uint8_t * Buffer, uint16_t BitCount); +bool checkParityBits(uint8_t * Buffer, uint16_t BitCount); +uint16_t ISO14443_CRCA(uint8_t * Buffer, uint8_t ByteCount); + +typedef enum { + Reader14443_Do_Nothing, + Reader14443_Send, + Reader14443_Send_Raw, + Reader14443_Get_UID, + Reader14443_Read_MF_Ultralight, + Reader14443_Indentify +} Reader14443Command; + + +#endif //READER14443A_H diff --git a/Firmware/Chameleon-Mini/Battery.h b/Firmware/Chameleon-Mini/Battery.h new file mode 100644 index 00000000..3cb335b4 --- /dev/null +++ b/Firmware/Chameleon-Mini/Battery.h @@ -0,0 +1,31 @@ +/* + * Battery.h + * + * Created on: 20.08.2014 + * Author: sk + */ + +#ifndef BATTERY_H_ +#define BATTERY_H_ + +#include "Common.h" + +#define BATTERY_PORT PORTD +#define BATTERY_STAT_PIN PIN0_bm +#define BATTERY_STAT_PINCTRL PIN0CTRL +#define BATTERY_PORT_MASK (BATTERY_STAT_PIN) + +INLINE void BatteryInit(void) { + BATTERY_PORT.DIRCLR = BATTERY_PORT_MASK; + BATTERY_PORT.BATTERY_STAT_PINCTRL = PORT_OPC_PULLUP_gc; +} + +INLINE bool BatteryIsCharging(void) { + if (!(BATTERY_PORT.IN & BATTERY_STAT_PIN)) { + return true; + } else { + return false; + } +} + +#endif /* BATTERY_H_ */ diff --git a/Firmware/Chameleon-Mini/Button.c b/Firmware/Chameleon-Mini/Button.c new file mode 100644 index 00000000..8d205425 --- /dev/null +++ b/Firmware/Chameleon-Mini/Button.c @@ -0,0 +1,274 @@ +#include "Button.h" +#include "Random.h" +#include "Common.h" +#include "Settings.h" +#include "Memory.h" +#include "Map.h" +#include "Application/Application.h" + +#define BUTTON_PORT PORTA +#define BUTTON_L PIN5_bm +#define BUTTON_R PIN6_bm +#define BUTTON_L_PINCTRL PIN5CTRL +#define BUTTON_R_PINCTRL PIN6CTRL +#define BUTTON_MASK (BUTTON_L | BUTTON_R) + +#define LONG_PRESS_TICK_COUNT 10 + +static const MapEntryType PROGMEM ButtonActionMap[] = { + { .Id = BUTTON_ACTION_NONE, .Text = "NONE" }, + { .Id = BUTTON_ACTION_UID_RANDOM, .Text = "UID_RANDOM" }, + { .Id = BUTTON_ACTION_UID_LEFT_INCREMENT, .Text = "UID_LEFT_INCREMENT" }, + { .Id = BUTTON_ACTION_UID_RIGHT_INCREMENT, .Text = "UID_RIGHT_INCREMENT" }, + { .Id = BUTTON_ACTION_UID_LEFT_DECREMENT, .Text = "UID_LEFT_DECREMENT" }, + { .Id = BUTTON_ACTION_UID_RIGHT_DECREMENT, .Text = "UID_RIGHT_DECREMENT" }, + { .Id = BUTTON_ACTION_CYCLE_SETTINGS, .Text = "CYCLE_SETTINGS" }, + { .Id = BUTTON_ACTION_STORE_MEM, .Text = "STORE_MEM" }, + { .Id = BUTTON_ACTION_RECALL_MEM, .Text = "RECALL_MEM" }, + { .Id = BUTTON_ACTION_TOGGLE_FIELD, .Text = "TOGGLE_FIELD" }, + { .Id = BUTTON_ACTION_STORE_LOG, .Text = "STORE_LOG" }, +}; + +static void ExecuteButtonAction(ButtonActionEnum ButtonAction) +{ + uint8_t UidBuffer[32]; + + switch (ButtonAction) + { + case BUTTON_ACTION_UID_RANDOM: + { + for (uint8_t i=0; i 0) { + if (Carry) { + if (UidBuffer[i] == 0xFF) { + Carry = 1; + } else { + Carry = 0; + } + + UidBuffer[i] = (UidBuffer[i] + 1) & 0xFF; + } + } + + ApplicationSetUid(UidBuffer); + break; + } + + case BUTTON_ACTION_UID_LEFT_DECREMENT: + { + ApplicationGetUid(UidBuffer); + bool Carry = 1; + uint8_t i; + + for (i=0; i 0) { + if (Carry) { + if (UidBuffer[i] == 0x00) { + Carry = 1; + } else { + Carry = 0; + } + + UidBuffer[i] = (UidBuffer[i] - 1) & 0xFF; + } + } + + ApplicationSetUid(UidBuffer); + break; + } + + case BUTTON_ACTION_CYCLE_SETTINGS: + { + SettingsCycle(); + break; + } + + case BUTTON_ACTION_STORE_MEM: + { + MemoryStore(); + break; + } + + case BUTTON_ACTION_RECALL_MEM: + { + MemoryRecall(); + break; + } + + case BUTTON_ACTION_TOGGLE_FIELD: + { + if (!CodecGetReaderField()) + { + CodecReaderFieldStart(); + } else { + CodecReaderFieldStop(); + } + break; + } + + case BUTTON_ACTION_STORE_LOG: + { + LogSRAMToFRAM(); + break; + } + + + default: + break; + + } +} + +void ButtonInit(void) +{ + BUTTON_PORT.DIRCLR = BUTTON_MASK; + BUTTON_PORT.BUTTON_R_PINCTRL = PORT_OPC_PULLUP_gc; + BUTTON_PORT.BUTTON_L_PINCTRL = PORT_OPC_PULLUP_gc; +} + +void ButtonTick(void) +{ + static uint8_t ButtonRPressTick = 0; + static uint8_t ButtonLPressTick = 0; + uint8_t ThisButtonState = ~BUTTON_PORT.IN; + + if (ThisButtonState & BUTTON_R) { + /* Button is currently pressed */ + if (ButtonRPressTick < LONG_PRESS_TICK_COUNT) { + /* Count ticks while button is being pressed */ + ButtonRPressTick++; + } else if (ButtonRPressTick == LONG_PRESS_TICK_COUNT) { + /* Long button press detected execute button action and advance PressTickCounter + * to an invalid state. */ + ExecuteButtonAction(GlobalSettings.ActiveSettingPtr->ButtonActions[BUTTON_R_PRESS_LONG]); + ButtonRPressTick++; + } else { + /* Button is still pressed, ignore */ + } + } else if (!(ThisButtonState & BUTTON_MASK)) { + /* Button is currently not being pressed. Check if PressTickCounter contains + * a recent short button press. */ + if ( (ButtonRPressTick > 0) && (ButtonRPressTick <= LONG_PRESS_TICK_COUNT) ) { + /* We have a short button press */ + ExecuteButtonAction(GlobalSettings.ActiveSettingPtr->ButtonActions[BUTTON_R_PRESS_SHORT]); + } + + ButtonRPressTick = 0; + } + + if (ThisButtonState & BUTTON_L) { + /* Button is currently pressed */ + if (ButtonLPressTick < LONG_PRESS_TICK_COUNT) { + /* Count ticks while button is being pressed */ + ButtonLPressTick++; + } else if (ButtonLPressTick == LONG_PRESS_TICK_COUNT) { + /* Long button press detected execute button action and advance PressTickCounter + * to an invalid state. */ + ExecuteButtonAction(GlobalSettings.ActiveSettingPtr->ButtonActions[BUTTON_L_PRESS_LONG]); + ButtonLPressTick++; + } else { + /* Button is still pressed, ignore */ + } + } else if (!(ThisButtonState & BUTTON_MASK)) { + /* Button is currently not being pressed. Check if PressTickCounter contains + * a recent short button press. */ + if ( (ButtonLPressTick > 0) && (ButtonLPressTick <= LONG_PRESS_TICK_COUNT) ) { + /* We have a short button press */ + ExecuteButtonAction(GlobalSettings.ActiveSettingPtr->ButtonActions[BUTTON_L_PRESS_SHORT]); + } + + ButtonLPressTick = 0; + } +} + +void ButtonGetActionList(char* List, uint16_t BufferSize) +{ + MapToString(ButtonActionMap, sizeof(ButtonActionMap)/sizeof(*ButtonActionMap), List, BufferSize); +} + +void ButtonSetActionById(ButtonTypeEnum Type, ButtonActionEnum Action) +{ +#ifndef BUTTON_SETTING_GLOBAL + GlobalSettings.ActiveSettingPtr->ButtonActions[Type] = Action; +#else + /* Write button action to all settings when using global settings */ + for (uint8_t i=0; iButtonActions[Type], Action, BufferSize); +} + +bool ButtonSetActionByName(ButtonTypeEnum Type, const char* Action) +{ + MapIdType Id; + + if (MapTextToId(ButtonActionMap, sizeof(ButtonActionMap)/sizeof(*ButtonActionMap), + Action, &Id)) { + ButtonSetActionById(Type, Id); + return true; + } else { + return false; + } +} diff --git a/Firmware/Chameleon-Mini/Button.h b/Firmware/Chameleon-Mini/Button.h new file mode 100644 index 00000000..0bc67c97 --- /dev/null +++ b/Firmware/Chameleon-Mini/Button.h @@ -0,0 +1,48 @@ +/* + * Button.h + * + * Created on: 13.05.2013 + * Author: skuser + */ + +#ifndef BUTTON_H_ +#define BUTTON_H_ + +#include "Common.h" + +typedef enum { + BUTTON_R_PRESS_SHORT = 0, + BUTTON_R_PRESS_LONG, + BUTTON_L_PRESS_SHORT, + BUTTON_L_PRESS_LONG, + + /* Must be last element */ + BUTTON_TYPE_COUNT +} ButtonTypeEnum; + +typedef enum { + BUTTON_ACTION_NONE, + BUTTON_ACTION_UID_RANDOM, + BUTTON_ACTION_UID_LEFT_INCREMENT, + BUTTON_ACTION_UID_RIGHT_INCREMENT, + BUTTON_ACTION_UID_LEFT_DECREMENT, + BUTTON_ACTION_UID_RIGHT_DECREMENT, + BUTTON_ACTION_CYCLE_SETTINGS, + BUTTON_ACTION_STORE_MEM, + BUTTON_ACTION_RECALL_MEM, + BUTTON_ACTION_TOGGLE_FIELD, + BUTTON_ACTION_STORE_LOG, + + /* This has to be last element */ + BUTTON_ACTION_COUNT +} ButtonActionEnum; + +void ButtonInit(void); +void ButtonTick(void); + +void ButtonGetActionList(char* List, uint16_t BufferSize); +void ButtonSetActionById(ButtonTypeEnum Type, ButtonActionEnum Action); +void ButtonGetActionByName(ButtonTypeEnum Type, char* Action, uint16_t BufferSize); +bool ButtonSetActionByName(ButtonTypeEnum Type, const char* Action); + +#endif /* BUTTON_H_ */ diff --git a/Firmware/Chameleon-Mini/Chameleon-Mini.bin b/Firmware/Chameleon-Mini/Chameleon-Mini.bin new file mode 100755 index 00000000..88c0aaf3 Binary files /dev/null and b/Firmware/Chameleon-Mini/Chameleon-Mini.bin differ diff --git a/Firmware/Chameleon-Mini/Chameleon-Mini.c b/Firmware/Chameleon-Mini/Chameleon-Mini.c new file mode 100644 index 00000000..ff4d2410 --- /dev/null +++ b/Firmware/Chameleon-Mini/Chameleon-Mini.c @@ -0,0 +1,38 @@ +#include "Chameleon-Mini.h" + +int main(void) +{ + SystemInit(); + SettingsLoad(); + LEDInit(); + MemoryInit(); + CodecInitCommon(); + ConfigurationInit(); + TerminalInit(); + RandomInit(); + ButtonInit(); + AntennaLevelInit(); + LogInit(); + SystemInterruptInit(); + + while(1) { + if (SystemTick100ms()) { + RandomTick(); + TerminalTick(); + ButtonTick(); + LogTick(); + LEDTick(); + ApplicationTick(); + CommandLineTick(); + AntennaLevelTick(); + + LEDHook(LED_POWERED, LED_ON); + } + + TerminalTask(); + LogTask(); + ApplicationTask(); + CodecTask(); + } +} + diff --git a/Firmware/Chameleon-Mini/Chameleon-Mini.h b/Firmware/Chameleon-Mini/Chameleon-Mini.h new file mode 100644 index 00000000..8c66796e --- /dev/null +++ b/Firmware/Chameleon-Mini/Chameleon-Mini.h @@ -0,0 +1,26 @@ +#ifndef CHAMELEON_MINI_H +#define CHAMELEON_MINI_H + +#include +#include +#include +#include + +#include "System.h" +#include "Memory.h" +#include "LED.h" +#include "LEDHook.h" +#include "Terminal/Terminal.h" +#include "Codec/Codec.h" +#include "Application/Application.h" +#include "Configuration.h" +#include "Random.h" +#include "Button.h" +#include "Log.h" +#include "AntennaLevel.h" +#include "Settings.h" + +#define CHAMELEON_MINI_VERSION_STRING BUILD_DATE + +#endif //CHAMELEON_MINI_H + diff --git a/Firmware/Chameleon-Mini/ChameleonFirmwareUpgrade.bat b/Firmware/Chameleon-Mini/ChameleonFirmwareUpgrade.bat new file mode 100644 index 00000000..3746e431 --- /dev/null +++ b/Firmware/Chameleon-Mini/ChameleonFirmwareUpgrade.bat @@ -0,0 +1,48 @@ +@ECHO OFF + +if not exist "%~dp0dfu-programmer.exe" ( + echo Cannot find dfu-programmer.exe. Please run this .bat script in the same directory where dfu-programmer.exe is saved. + pause > nul + exit +) + +if not exist "%~dp0Chameleon-Mini.eep" ( + echo Cannot find Chameleon-Mini.eep. Please run this .bat script in the same directory where Chameleon-Mini.eep and Chameleon-Mini.hex are saved. + pause > nul + exit +) + +if not exist "%~dp0Chameleon-Mini.hex" ( + echo Cannot find Chameleon-Mini.hex. Please run this .bat script in the same directory where Chameleon-Mini.eep and Chameleon-Mini.hex are saved. + pause > nul + exit +) + +"%~dp0dfu-programmer.exe" atxmega128a4u erase + +IF %ERRORLEVEL% NEQ 0 ( + echo There was an error with executing this command. Maybe your ChameleonMini is not in bootloader mode? + pause > nul + exit +) + +"%~dp0dfu-programmer.exe" atxmega128a4u flash-eeprom "%~dp0Chameleon-Mini.eep" --force + +IF %ERRORLEVEL% NEQ 0 ( + echo There was an error with executing this command. Maybe your ChameleonMini is not in bootloader mode? + pause > nul + exit +) + +"%~dp0dfu-programmer.exe" atxmega128a4u flash "%~dp0Chameleon-Mini.hex" + +IF %ERRORLEVEL% NEQ 0 ( + echo There was an error with executing this command. Maybe your ChameleonMini is not in bootloader mode? + pause > nul + exit +) + +"%~dp0dfu-programmer.exe" atxmega128a4u launch + +echo Flashing the firmware to your ChameleonMini is finished now. +pause > nul \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Codec/Codec.c b/Firmware/Chameleon-Mini/Codec/Codec.c new file mode 100644 index 00000000..05f1481c --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/Codec.c @@ -0,0 +1,56 @@ +/* + * CODEC.c + * + * Created on: 18.02.2013 + * Author: skuser + */ + +#include "Codec.h" +#include "../System.h" +#include "../LEDHook.h" + +#define READER_FIELD_MINIMUM_WAITING_TIME 70 // ms + +static uint16_t ReaderFieldStartTimestamp = 0; +static volatile struct { + bool Started; + bool Ready; +} ReaderFieldFlags = { false }; + +uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; +uint16_t ReaderThreshold = 400; // standard value + +// the following three functions prevent sending data directly after turning on the reader field +void CodecReaderFieldStart(void) // DO NOT CALL THIS FUNCTION INSIDE APPLICATION! +{ + if (!CodecGetReaderField()) + { + CodecSetReaderField(true); + ReaderFieldFlags.Started = true; + ReaderFieldFlags.Ready = false; + ReaderFieldStartTimestamp = SystemGetSysTick(); + } +} + +void CodecReaderFieldStop(void) +{ + CodecSetReaderField(false); + ReaderFieldFlags.Started = false; + ReaderFieldFlags.Ready = false; +} + +/* + * This function returns false if and only if the reader field has been turned on in the last READER_FIELD_MIN..._TIME ms. + * If the reader field is not active, true is returned. + */ +bool CodecIsReaderFieldReady(void) +{ + if (!ReaderFieldFlags.Started) + return true; + if (ReaderFieldFlags.Ready || (ReaderFieldFlags.Started && SYSTICK_DIFF(ReaderFieldStartTimestamp) >= READER_FIELD_MINIMUM_WAITING_TIME)) + { + ReaderFieldFlags.Ready = true; + return true; + } + return false; +} diff --git a/Firmware/Chameleon-Mini/Codec/Codec.h b/Firmware/Chameleon-Mini/Codec/Codec.h new file mode 100644 index 00000000..0070c37a --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/Codec.h @@ -0,0 +1,248 @@ +/* + * CODEC.h + * + * Created on: 18.02.2013 + * Author: skuser + */ + +#ifndef CODEC_H_ +#define CODEC_H_ + +#include +#include +#include +#include "../Common.h" +#include "../Configuration.h" + +#include "ISO14443-2A.h" +#include "Reader14443-2A.h" + +/* Timing definitions for ISO14443A */ +#define ISO14443A_SUBCARRIER_DIVIDER 16 +#define ISO14443A_BIT_GRID_CYCLES 128 +#define ISO14443A_BIT_RATE_CYCLES 128 +#define ISO14443A_FRAME_DELAY_PREV1 1236 +#define ISO14443A_FRAME_DELAY_PREV0 1172 +#define ISO14443A_RX_PENDING_TIMEOUT 1 // ms + +/* Peripheral definitions */ +#define CODEC_DEMOD_POWER_PORT PORTB +#define CODEC_DEMOD_POWER_MASK PIN0_bm +#define CODEC_DEMOD_IN_PORT PORTB +#define CODEC_DEMOD_IN_MASK (CODEC_DEMOD_IN_MASK0 | CODEC_DEMOD_IN_MASK1) +#define CODEC_DEMOD_IN_MASK0 PIN1_bm +#define CODEC_DEMOD_IN_MASK1 PIN2_bm +#define CODEC_DEMOD_IN_PINCTRL0 PIN1CTRL +#define CODEC_DEMOD_IN_PINCTRL1 PIN2CTRL +#define CODEC_DEMOD_IN_EVMUX0 EVSYS_CHMUX_PORTB_PIN1_gc +#define CODEC_DEMOD_IN_EVMUX1 EVSYS_CHMUX_PORTB_PIN2_gc +#define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect +#define CODEC_LOADMOD_PORT PORTC +#define CODEC_LOADMOD_MASK PIN6_bm +#define CODEC_CARRIER_IN_PORT PORTC +#define CODEC_CARRIER_IN_MASK PIN2_bm +#define CODEC_CARRIER_IN_PINCTRL PIN2CTRL +#define CODEC_CARRIER_IN_EVMUX EVSYS_CHMUX_PORTC_PIN2_gc +#define CODEC_CARRIER_IN_DIV 2 /* external clock division factor */ +#define CODEC_SUBCARRIER_PORT PORTC +#define CODEC_SUBCARRIER_MASK_PSK PIN4_bm +#define CODEC_SUBCARRIER_MASK_OOK PIN5_bm +#define CODEC_SUBCARRIER_MASK (CODEC_SUBCARRIER_MASK_PSK | CODEC_SUBCARRIER_MASK_OOK) +#define CODEC_SUBCARRIER_TIMER TCC1 +#define CODEC_SUBCARRIER_CC_PSK CCA +#define CODEC_SUBCARRIER_CC_OOK CCB +#define CODEC_SUBCARRIER_CCEN_PSK TC1_CCAEN_bm +#define CODEC_SUBCARRIER_CCEN_OOK TC1_CCBEN_bm +#define CODEC_TIMER_SAMPLING TCD0 +#define CODEC_TIMER_SAMPLING_CCA_VECT TCD0_CCA_vect +#define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect +#define CODEC_TIMER_LOADMOD TCE0 +#define CODEC_TIMER_LOADMOD_OVF_VECT TCE0_OVF_vect +#define CODEC_TIMER_LOADMOD_CCA_VECT TCE0_CCA_vect +#define CODEC_TIMER_LOADMOD_CCB_VECT TCE0_CCB_vect +#define CODEC_TIMER_LOADMOD_CCC_VECT TCE0_CCC_vect +#define CODEC_TIMER_MODSTART_EVSEL TC_EVSEL_CH0_gc +#define CODEC_TIMER_MODEND_EVSEL TC_EVSEL_CH1_gc +#define CODEC_TIMER_CARRIER_CLKSEL TC_CLKSEL_EVCH6_gc +#define CODEC_READER_TIMER TCC0 +#define CODEC_READER_PORT PORTC +#define CODEC_READER_MASK_LEFT PIN0_bm +#define CODEC_READER_MASK_RIGHT PIN1_bm +#define CODEC_READER_MASK (CODEC_READER_MASK_LEFT | CODEC_READER_MASK_RIGHT) +#define CODEC_READER_PINCTRL_LEFT PIN0CTRL +#define CODEC_READER_PINCTRL_RIGHT PIN1CTRL +#define CODEC_AC_DEMOD_SETTINGS AC_HSMODE_bm | AC_HYSMODE_NO_gc +#define CODEC_MAXIMUM_THRESHOLD 0xFFF // the maximum voltage can be calculated with ch0data * Vref / 0xFFF +#define CODEC_TIMER_TIMESTAMPS TCD1 +#define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect + +#define CODEC_BUFFER_SIZE 256 + +#define CODEC_CARRIER_FREQ 13560000 + +#define Codec8Reg0 GPIOR0 +#define Codec8Reg1 GPIOR1 +#define Codec8Reg2 GPIOR2 +#define Codec8Reg3 GPIOR3 +#define CodecCount16Register1 (*((volatile uint16_t*) &GPIOR4)) /* GPIOR4 & GPIOR5 */ +#define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR4 & GPIOR5 */ +#define CodecPtrRegister1 (*((volatile uint8_t**) &GPIOR8)) +#define CodecPtrRegister2 (*((volatile uint8_t**) &GPIORA)) + +extern uint16_t ReaderThreshold; + +typedef enum { + CODEC_SUBCARRIERMOD_OFF, + CODEC_SUBCARRIERMOD_OOK +} SubcarrierModType; + +extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; + +INLINE void CodecInit(void) { + ActiveConfiguration.CodecInitFunc(); +} + +INLINE void CodecDeInit(void) { + ActiveConfiguration.CodecDeInitFunc(); +} + +INLINE void CodecTask(void) { + ActiveConfiguration.CodecTaskFunc(); +} + +/* Helper Functions for Codec implementations */ +INLINE void CodecInitCommon(void) +{ + /* Configure CARRIER input pin and route it to EVSYS. + * Multiply by 2 again by using both edges when externally + * dividing by 2 */ +#if CODEC_CARRIER_IN_DIV == 2 + CODEC_CARRIER_IN_PORT.CODEC_CARRIER_IN_PINCTRL = PORT_ISC_BOTHEDGES_gc; +#else +#error Option not supported +#endif + CODEC_CARRIER_IN_PORT.DIRCLR = CODEC_CARRIER_IN_MASK; + EVSYS.CH6MUX = CODEC_CARRIER_IN_EVMUX; + + /* Configure two DEMOD pins for input. + * Configure event channel 0 for rising edge (begin of modulation pause) + * Configure event channel 1 for falling edge (end of modulation pause) */ + CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK; + CODEC_DEMOD_POWER_PORT.DIRSET = CODEC_DEMOD_POWER_MASK; + CODEC_DEMOD_IN_PORT.DIRCLR = CODEC_DEMOD_IN_MASK; + CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL0 = PORT_ISC_RISING_gc; + CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL1 = PORT_ISC_FALLING_gc; + CODEC_DEMOD_IN_PORT.INT0MASK = 0; + CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc; + EVSYS.CH0MUX = CODEC_DEMOD_IN_EVMUX0; + EVSYS.CH1MUX = CODEC_DEMOD_IN_EVMUX1; + + /* Configure loadmod pin configuration and use a virtual port configuration + * for single instruction cycle access */ + CODEC_LOADMOD_PORT.DIRSET = CODEC_LOADMOD_MASK; + CODEC_LOADMOD_PORT.OUTCLR = CODEC_LOADMOD_MASK; + PORTCFG.VPCTRLA &= ~PORTCFG_VP0MAP_gm; + PORTCFG.VPCTRLA |= PORTCFG_VP02MAP_PORTC_gc; + + /* Configure subcarrier pins for output */ + CODEC_SUBCARRIER_PORT.DIRSET = CODEC_SUBCARRIER_MASK; + CODEC_SUBCARRIER_PORT.OUTCLR = CODEC_SUBCARRIER_MASK; + + /* Configure pins for reader field with the LEFT output being inverted + * and all bridge outputs static high */ + CODEC_READER_PORT.CODEC_READER_PINCTRL_LEFT = PORT_INVEN_bm; + CODEC_READER_PORT.OUTCLR = CODEC_READER_MASK_LEFT; + CODEC_READER_PORT.OUTSET = CODEC_READER_MASK_RIGHT; + CODEC_READER_PORT.DIRSET = CODEC_READER_MASK; + + /* Configure timer for generating reader field and configure AWEX for outputting pattern + * with disabled outputs. */ + CODEC_READER_TIMER.CTRLB = TC0_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc; + CODEC_READER_TIMER.PER = F_CPU / CODEC_CARRIER_FREQ - 1; + CODEC_READER_TIMER.CCA = F_CPU / CODEC_CARRIER_FREQ / 2 ; + + AWEXC.OUTOVEN = 0x00; + AWEXC.CTRL = AWEX_CWCM_bm | AWEX_DTICCAEN_bm | AWEX_DTICCBEN_bm; + + /* Configure DAC for the reference voltage */ + DACB.EVCTRL = 0; + DACB.CTRLB = DAC_CHSEL_SINGLE_gc; + DACB.CTRLC = DAC_REFSEL_AVCC_gc; + DACB.CTRLA = DAC_IDOEN_bm | DAC_ENABLE_bm; + DACB.CH0DATA = ReaderThreshold; // real threshold voltage can be calculated with ch0data * Vref / 0xFFF + + /* Configure Analog Comparator 0 to detect changes in demodulated reader field */ + ACA.AC0MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc; + ACA.AC0CTRL = CODEC_AC_DEMOD_SETTINGS; + + /* Configure Analog Comparator 1 to detect SOC */ + ACA.AC1MUXCTRL = AC_MUXPOS_DAC_gc | AC_MUXNEG_PIN7_gc; + ACA.AC1CTRL = CODEC_AC_DEMOD_SETTINGS; +} + +INLINE void CodecSetSubcarrier(SubcarrierModType ModType, uint16_t Divider) +{ + if (ModType == CODEC_SUBCARRIERMOD_OFF) { + CODEC_SUBCARRIER_TIMER.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_SUBCARRIER_TIMER.CTRLB = 0; + } else if (ModType == CODEC_SUBCARRIERMOD_OOK) { + /* Configure subcarrier generation with 50% DC output using OOK */ + CODEC_SUBCARRIER_TIMER.CNT = 0; + CODEC_SUBCARRIER_TIMER.PER = Divider - 1; + CODEC_SUBCARRIER_TIMER.CODEC_SUBCARRIER_CC_OOK = Divider/2; + CODEC_SUBCARRIER_TIMER.CTRLB = CODEC_SUBCARRIER_CCEN_OOK | TC_WGMODE_SINGLESLOPE_gc; + } +} + +INLINE void CodecStartSubcarrier(void) +{ + CODEC_SUBCARRIER_TIMER.CTRLA = CODEC_TIMER_CARRIER_CLKSEL; +} + +INLINE void CodecSetDemodPower(bool bOnOff) +{ + if (bOnOff) { + CODEC_DEMOD_POWER_PORT.OUTSET = CODEC_DEMOD_POWER_MASK; + } else { + CODEC_DEMOD_POWER_PORT.OUTCLR = CODEC_DEMOD_POWER_MASK; + } +} + +INLINE bool CodecGetLoadmodState(void) { + if (ACA.STATUS & AC_AC0STATE_bm) { + return true; + } else { + return false; + } +} + +INLINE void CodecSetLoadmodState(bool bOnOff) { + if (bOnOff) { + VPORT0.OUT |= CODEC_LOADMOD_MASK; + } else { + VPORT0.OUT &= ~CODEC_LOADMOD_MASK; + } +} + +INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turning on/off the reader field dumbly; before using this function, please consider to use CodecReaderField{Start,Stop} + + if (bOnOff) { + /* Start timer for field generation and unmask outputs */ + CODEC_READER_TIMER.CTRLA = TC_CLKSEL_DIV1_gc; + AWEXC.OUTOVEN = CODEC_READER_MASK; + } else { + /* Disable outputs of AWEX and stop field generation */ + AWEXC.OUTOVEN = 0x00; + CODEC_READER_TIMER.CTRLA = TC_CLKSEL_OFF_gc; + } +} + +INLINE bool CodecGetReaderField(void) { + return (CODEC_READER_TIMER.CTRLA == TC_CLKSEL_DIV1_gc) && (AWEXC.OUTOVEN == CODEC_READER_MASK); +} + +void CodecReaderFieldStart(void); +void CodecReaderFieldStop(void); +bool CodecIsReaderFieldReady(void); + +#endif /* CODEC_H_ */ diff --git a/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c new file mode 100644 index 00000000..4b3c9284 --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c @@ -0,0 +1,465 @@ +/* + * ISO14443A.c + * + * Created on: 18.02.2013 + * Author: skuser + */ + +#include "ISO14443-2A.h" +#include "../System.h" +#include "../Application/Application.h" +#include "../LEDHook.h" +#include "Codec.h" +#include "Log.h" + +/* Sampling is done using internal clock, synchronized to the field modulation. + * For that we need to convert the bit rate for the internal clock. */ +#define SAMPLE_RATE_SYSTEM_CYCLES ((uint16_t) (((uint64_t) F_CPU * ISO14443A_BIT_RATE_CYCLES) / CODEC_CARRIER_FREQ) ) + +#define ISO14443A_MIN_BITS_PER_FRAME 7 + +static volatile struct { + volatile bool DemodFinished; + volatile bool LoadmodFinished; +} Flags = { 0 }; + +typedef enum { + /* Demod */ + DEMOD_DATA_BIT, + DEMOD_PARITY_BIT, + + /* Loadmod */ + LOADMOD_FDT, + LOADMOD_START, + LOADMOD_START_BIT0, + LOADMOD_START_BIT1, + LOADMOD_DATA0, + LOADMOD_DATA1, + LOADMOD_PARITY0, + LOADMOD_PARITY1, + LOADMOD_STOP_BIT0, + LOADMOD_STOP_BIT1, + LOADMOD_FINISHED +} StateType; + +/* Define pseudo variables to use fast register access. This is useful for global vars */ +#define DataRegister Codec8Reg0 +#define StateRegister Codec8Reg1 +#define ParityRegister Codec8Reg2 +#define SampleIdxRegister Codec8Reg2 +#define SampleRegister Codec8Reg3 +#define BitSent CodecCount16Register1 +#define BitCount CodecCount16Register2 +#define CodecBufferPtr CodecPtrRegister1 +#define ParityBufferPtr CodecPtrRegister2 + +static void StartDemod(void) { + /* Activate Power for demodulator */ + CodecSetDemodPower(true); + + CodecBufferPtr = CodecBuffer; + ParityBufferPtr = &CodecBuffer[ISO14443A_BUFFER_PARITY_OFFSET]; + DataRegister = 0; + SampleRegister = 0; + SampleIdxRegister = 0; + BitCount = 0; + StateRegister = DEMOD_DATA_BIT; + + /* Configure sampling-timer free running and sync to first modulation-pause. */ + CODEC_TIMER_SAMPLING.CNT = 0; + CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; + CODEC_TIMER_SAMPLING.CCA = 0xFFFF; /* CCA Interrupt is not active! */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc; + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCAIF_bm; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCAINTLVL_HI_gc; + + /* Start looking out for modulation pause via interrupt. */ + CODEC_DEMOD_IN_PORT.INTFLAGS = 0x03; + CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; +} + +ISR(CODEC_DEMOD_IN_INT0_VECT) { + /* This is the first edge of the first modulation-pause after StartDemod. + * Now we have time to start + * demodulating beginning from one bit-width after this edge. */ + + /* Sampling timer has been preset to sample-rate and has automatically synced + * to THIS first modulation pause. Thus after exactly one bit-width from here, + * an OVF is generated. We want to start sampling with the next bit and use the + * XYZBUF mechanism of the xmega to automatically double the sampling rate on the + * next overflow. For this we have to temporarily deactivate the automatical alignment + * in order to catch next overflow event for updating the BUF registers. + * We want to sample the demodulated data stream in the first quarter of the half-bit + * where the pulsed miller encoded is located. */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + CODEC_TIMER_SAMPLING.PERBUF = SAMPLE_RATE_SYSTEM_CYCLES/2 - 1; /* Half bit width */ + CODEC_TIMER_SAMPLING.CCABUF = SAMPLE_RATE_SYSTEM_CYCLES/8 - 14 - 1; /* Compensate for DIGFILT and ISR prolog */ + + /* Setup Frame Delay Timer and wire to EVSYS. Frame delay time is + * measured from last change in RF field, therefore we use + * the event channel 1 (end of modulation pause) as the restart event. + * The preliminary frame delay time chosen here is irrelevant, because + * the correct FDT gets set automatically after demodulation. */ + CODEC_TIMER_LOADMOD.CNT = 0; + CODEC_TIMER_LOADMOD.PER = 0xFFFF; + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODEND_EVSEL; + CODEC_TIMER_LOADMOD.INTCTRLA = TC_OVFINTLVL_OFF_gc; + CODEC_TIMER_LOADMOD.INTFLAGS = TC0_OVFIF_bm; + CODEC_TIMER_LOADMOD.CTRLA = CODEC_TIMER_CARRIER_CLKSEL; + + /* Disable this interrupt */ + CODEC_DEMOD_IN_PORT.INT0MASK = 0; +} + +ISR(CODEC_TIMER_SAMPLING_CCA_VECT) { + /* This interrupt gets called twice for every bit to sample it. */ + uint8_t SamplePin = CODEC_DEMOD_IN_PORT.IN & CODEC_DEMOD_IN_MASK; + + /* Shift sampled bit into sampling register */ + SampleRegister = (SampleRegister << 1) | (!SamplePin ? 0x01 : 0x00); + + if (SampleIdxRegister) { + SampleIdxRegister = 0; + /* Analyze the sampling register after 2 samples. */ + if ((SampleRegister & 0x07) == 0x07) { + /* No carrier modulation for 3 sample points. EOC! */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCAIF_bm; + + /* By this time, the FDT timer is aligned to the last modulation + * edge of the reader. So we disable the auto-synchronization and + * let it count the frame delay time in the background, and generate + * an interrupt once it has reached the FDT. */ + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_OFF_gc; + + if (SampleRegister & 0x08) { + CODEC_TIMER_LOADMOD.PER = ISO14443A_FRAME_DELAY_PREV1 - 40; /* compensate for ISR prolog */ + } else { + CODEC_TIMER_LOADMOD.PER = ISO14443A_FRAME_DELAY_PREV0 - 40; /* compensate for ISR prolog */ + } + + StateRegister = LOADMOD_FDT; + + CODEC_TIMER_LOADMOD.INTFLAGS = TC0_OVFIF_bm; + CODEC_TIMER_LOADMOD.INTCTRLA = TC_OVFINTLVL_HI_gc; + + /* Determine if we did not receive a multiple of 8 bits. + * If this is the case, right-align the remaining data and + * store it into the buffer. */ + uint8_t RemainingBits = BitCount % 8; + if (RemainingBits != 0) { + uint8_t NewDataRegister = DataRegister; + + while (RemainingBits++ < 8) { + /* Pad with zeroes to right-align. */ + NewDataRegister >>= 1; + } + + /* TODO: Prevent buffer overflow */ + *CodecBufferPtr = NewDataRegister; + } + + /* Signal, that we have finished sampling */ + Flags.DemodFinished = 1; + } else { + /* Otherwise, we check the two sample bits from the bit before. */ + uint8_t BitSample = SampleRegister & 0xC; + uint8_t Bit = 0; + + if (BitSample != (0x0 << 2)) { + /* We have a valid bit. decode and process it. */ + if (BitSample & (0x1 << 2)) { + /* 01 sequence or 11 sequence -> This is a zero bit */ + Bit = 0; + } else { + /* 10 sequence -> This is a one bit */ + Bit = 1; + } + + if (StateRegister == DEMOD_DATA_BIT) { + /* This is a data bit, so shift it into the data register and + * hold a local copy of it. */ + uint8_t NewDataRegister = DataRegister >> 1; + NewDataRegister |= (Bit ? 0x80 : 0x00); + DataRegister = NewDataRegister; + + /* Update bitcount */ + uint16_t NewBitCount = ++BitCount; + if ((NewBitCount & 0x07) == 0) { + /* We have reached a byte boundary! Store the data register. */ + /* TODO: Prevent buffer overflow */ + *CodecBufferPtr++ = NewDataRegister; + + /* Store bit for determining FDT at EOC and enable parity + * handling on next bit. */ + StateRegister = DEMOD_PARITY_BIT; + } + + } else if (StateRegister == DEMOD_PARITY_BIT) { + /* This is a parity bit. Store it */ + *ParityBufferPtr++ = Bit; + StateRegister = DEMOD_DATA_BIT; + } else { + /* Should never Happen (TM) */ + } + } else { + /* 00 sequence. -> No valid data yet. This also occurs if we just started + * sampling and have sampled less than 2 bits yet. Thus ignore. */ + } + } + } else { + /* On odd sample position just sample. */ + SampleIdxRegister = ~SampleIdxRegister; + } + + /* Make sure the sampling timer gets automatically aligned to the + * modulation pauses by using the RESTART event. + * This can be understood as a "poor mans PLL" and makes sure that we are + * never too far out the bit-grid while sampling. */ + //CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; +} + +ISR(CODEC_TIMER_LOADMOD_OVF_VECT) { + /* Bit rate timer. Output a half bit on the output. */ + + static void* JumpTable[] = { + [LOADMOD_FDT] = &&LOADMOD_FDT_LABEL, + [LOADMOD_START] = &&LOADMOD_START_LABEL, + [LOADMOD_START_BIT0] = &&LOADMOD_START_BIT0_LABEL, + [LOADMOD_START_BIT1] = &&LOADMOD_START_BIT1_LABEL, + [LOADMOD_DATA0] = &&LOADMOD_DATA0_LABEL, + [LOADMOD_DATA1] = &&LOADMOD_DATA1_LABEL, + [LOADMOD_PARITY0] = &&LOADMOD_PARITY0_LABEL, + [LOADMOD_PARITY1] = &&LOADMOD_PARITY1_LABEL, + [LOADMOD_STOP_BIT0] = &&LOADMOD_STOP_BIT0_LABEL, + [LOADMOD_STOP_BIT1] = &&LOADMOD_STOP_BIT1_LABEL, + [LOADMOD_FINISHED] = &&LOADMOD_FINISHED_LABEL + }; + + if ( (StateRegister >= LOADMOD_FDT) && (StateRegister <= LOADMOD_FINISHED) ) { + goto *JumpTable[StateRegister]; + } else { + return; + } + + LOADMOD_FDT_LABEL: + /* No data has been produced, but FDT has ended. Switch over to bit-grid aligning. */ + CODEC_TIMER_LOADMOD.PER = ISO14443A_BIT_GRID_CYCLES - 1; + return; + + LOADMOD_START_LABEL: + /* Application produced data. With this interrupt we are aligned to the bit-grid. */ + /* Fallthrough to first bit */ + + LOADMOD_START_BIT0_LABEL: + /* Start subcarrier generation, output startbit and align to bitrate. */ + CodecSetLoadmodState(true); + CodecStartSubcarrier(); + + CODEC_TIMER_LOADMOD.PER = ISO14443A_BIT_RATE_CYCLES / 2 - 1; + StateRegister = LOADMOD_START_BIT1; + return; + + + LOADMOD_START_BIT1_LABEL: + CodecSetLoadmodState(false); + StateRegister = LOADMOD_DATA0; + ParityRegister = ~0; + BitSent = 0; + + /* Prefetch first byte */ + DataRegister = *CodecBufferPtr; + return; + + LOADMOD_DATA0_LABEL: + if (DataRegister & 1) { + CodecSetLoadmodState(true); + ParityRegister = ~ParityRegister; + } else { + CodecSetLoadmodState(false); + } + + StateRegister = LOADMOD_DATA1; + return; + + LOADMOD_DATA1_LABEL: + if (DataRegister & 1) { + CodecSetLoadmodState(false); + } else { + CodecSetLoadmodState(true); + } + + DataRegister = DataRegister >> 1; + BitSent++; + + if ((BitSent % 8) == 0) { + /* Byte boundary. Load parity bit and output it later. */ + StateRegister = LOADMOD_PARITY0; + } else if (BitSent == BitCount) { + /* End of transmission without byte boundary. Don't send parity. */ + StateRegister = LOADMOD_STOP_BIT0; + } else { + /* Next bit is data */ + StateRegister = LOADMOD_DATA0; + } + + return; + + LOADMOD_PARITY0_LABEL: + if (ParityBufferPtr != NULL) { + if (*ParityBufferPtr) { + CodecSetLoadmodState(true); + } else { + CodecSetLoadmodState(false); + } + } else { + if (ParityRegister) { + CodecSetLoadmodState(true); + } else { + CodecSetLoadmodState(false); + } + } + StateRegister = LOADMOD_PARITY1; + return; + + LOADMOD_PARITY1_LABEL: + if (ParityBufferPtr != NULL) { + if (*ParityBufferPtr) { + CodecSetLoadmodState(false); + } else { + CodecSetLoadmodState(true); + } + + ParityBufferPtr++; + } else { + if (ParityRegister) { + CodecSetLoadmodState(false); + } else { + CodecSetLoadmodState(true); + } + + ParityRegister = ~0; + } + + if (BitSent == BitCount) { + /* No data left */ + StateRegister = LOADMOD_STOP_BIT0; + } else { + /* Fetch next data and continue sending bits. */ + DataRegister = *++CodecBufferPtr; + StateRegister = LOADMOD_DATA0; + } + + return; + + LOADMOD_STOP_BIT0_LABEL: + CodecSetLoadmodState(false); + StateRegister = LOADMOD_STOP_BIT1; + return; + + LOADMOD_STOP_BIT1_LABEL: + CodecSetLoadmodState(false); + StateRegister = LOADMOD_FINISHED; + return; + + LOADMOD_FINISHED_LABEL: + /* We have written all of our bits. Deactivate the loadmod + * timer. Also disable the bit-rate interrupt again. And + * stop the subcarrier divider. */ + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OFF, ISO14443A_SUBCARRIER_DIVIDER); + + /* Signal application that we have finished loadmod */ + Flags.LoadmodFinished = 1; + return; +} + +void ISO14443ACodecInit(void) { + /* Initialize some global vars and start looking out for reader commands */ + Flags.DemodFinished = 0; + Flags.LoadmodFinished = 0; + + CodecInitCommon(); + StartDemod(); +} + +void ISO14443ACodecDeInit(void) +{ + /* Gracefully shutdown codec */ + CODEC_DEMOD_IN_PORT.INT0MASK = 0; + + Flags.DemodFinished = 0; + Flags.LoadmodFinished = 0; + + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCAINTLVL_OFF_gc; + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCAIF_bm; + + + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_OFF_gc; + CODEC_TIMER_LOADMOD.INTCTRLA = TC_OVFINTLVL_OFF_gc; + CODEC_TIMER_LOADMOD.INTFLAGS = TC0_OVFIF_bm; + + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OFF, 0); + CodecSetDemodPower(false); + CodecSetLoadmodState(false); + +} + +void ISO14443ACodecTask(void) { + if (Flags.DemodFinished) { + Flags.DemodFinished = 0; + /* Reception finished. Process the received bytes */ + uint16_t DemodBitCount = BitCount; + uint16_t AnswerBitCount = ISO14443A_APP_NO_RESPONSE; + + if (DemodBitCount >= ISO14443A_MIN_BITS_PER_FRAME) { + LogEntry(LOG_INFO_CODEC_RX_DATA, CodecBuffer, (DemodBitCount+7)/8); + LEDHook(LED_CODEC_RX, LED_PULSE); + + /* Call application if we received data */ + AnswerBitCount = ApplicationProcess(CodecBuffer, DemodBitCount); + + if (AnswerBitCount & ISO14443A_APP_CUSTOM_PARITY) { + /* Application has generated it's own parity bits. + * Clear this option bit. */ + AnswerBitCount &= ~ISO14443A_APP_CUSTOM_PARITY; + ParityBufferPtr = &CodecBuffer[ISO14443A_BUFFER_PARITY_OFFSET]; + } else { + /* We have to generate the parity bits ourself */ + ParityBufferPtr = 0; + } + } else { + ApplicationReset(); + } + + if (AnswerBitCount != ISO14443A_APP_NO_RESPONSE) { + LogEntry(LOG_INFO_CODEC_TX_DATA, CodecBuffer, (AnswerBitCount + 7) / 8); + LEDHook(LED_CODEC_TX, LED_PULSE); + + BitCount = AnswerBitCount; + CodecBufferPtr = CodecBuffer; + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OOK, ISO14443A_SUBCARRIER_DIVIDER); + + StateRegister = LOADMOD_START; + } else { + /* No data to be processed. Disable loadmodding and start listening again */ + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + + StartDemod(); + } + } + + if (Flags.LoadmodFinished) { + Flags.LoadmodFinished = 0; + /* Load modulation has been finished. Stop it and start to listen + * for incoming data again. */ + StartDemod(); + } +} + diff --git a/Firmware/Chameleon-Mini/Codec/ISO14443-2A.h b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.h new file mode 100644 index 00000000..73919413 --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.h @@ -0,0 +1,25 @@ +/* + * ISO14443-2A.h + * + * Created on: 18.02.2013 + * Author: skuser + */ + +#ifndef ISO14443_2A_H_ +#define ISO14443_2A_H_ + +#include "Codec.h" + +#define ISO14443A_APP_NO_RESPONSE 0x0000 +#define ISO14443A_APP_CUSTOM_PARITY 0x1000 + +#define ISO14443A_BUFFER_PARITY_OFFSET (CODEC_BUFFER_SIZE/2) + +/* Codec Interface */ +void ISO14443ACodecInit(void); +void ISO14443ACodecDeInit(void); +void ISO14443ACodecTask(void); + + + +#endif diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c new file mode 100644 index 00000000..9d87662b --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c @@ -0,0 +1,414 @@ +/* + * Reader14443-2A.c + * + * Created on: 26.08.2014 + * Author: sk + */ + +#include "Reader14443-2A.h" +#include "Codec.h" +#include "../System.h" +#include "../Application/Application.h" +#include "LEDHook.h" +#include "Terminal/Terminal.h" +#include + +#define SAMPLE_RATE_SYSTEM_CYCLES ((uint16_t) (((uint64_t) F_CPU * ISO14443A_BIT_RATE_CYCLES) / CODEC_CARRIER_FREQ) ) +#define ISO14443A_RX_MINIMUM_BITCOUNT 4 +#define ISO14443A_PICC_TO_PCD_FDT_PRESCALER TC_CLKSEL_DIV8_gc // please change ISO14443A_PICC_TO_PCD_MIN_FDT when changing this +#define ISO14443A_PICC_TO_PCD_MIN_FDT 293 + +static volatile struct { + volatile bool Start; + volatile bool RxDone; + volatile bool RxPending; +} Flags = { 0 }; + +static volatile uint16_t RxPendingSince; + +static volatile enum { + STATE_IDLE, + STATE_MILLER_SOF0, + STATE_MILLER_SOF1, + STATE_MILLER_TX0, + STATE_MILLER_TX1, + STATE_MILLER_EOF0, + STATE_MILLER_EOF1, + STATE_FDT +} State; + +// GPIOR0 and 1 are used as storage for the timer value of the current modulation +#define LastBit Codec8Reg2 // GPIOR2 +// GPIOR3 is used for some internal flags +#define BitCount CodecCount16Register1 // GPIOR5:4 +#define SampleRegister GPIOR6 +#define BitCountUp GPIOR7 +#define CodecBufferIdx GPIOR8 +#define CodecBufferPtr CodecPtrRegister2 + +#define UINT8DIFF(a,b) ((uint8_t) (a-b)) + +void Reader14443ACodecInit(void) { + /* Initialize common peripherals and start listening + * for incoming data. */ + CodecInitCommon(); + CodecSetDemodPower(true); + + CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES/2 - 1; + CODEC_TIMER_SAMPLING.CCB = 1; + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_SAMPLING.INTCTRLA = 0; + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCBINTLVL_HI_gc; + + CODEC_TIMER_LOADMOD.CTRLA = 0; + State = STATE_IDLE; + + Flags.Start = false; + Flags.RxPending = false; + Flags.RxDone = false; +} + +void Reader14443ACodecDeInit(void) { + CodecSetDemodPower(false); + CodecReaderFieldStop(); + CODEC_TIMER_SAMPLING.CTRLA = 0; + CODEC_TIMER_SAMPLING.INTCTRLB = 0; + CODEC_TIMER_LOADMOD.CTRLA = 0; + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + Flags.RxDone = false; + Flags.RxPending = false; + Flags.Start = false; +} + +INLINE void Reader14443A_EOC(void) +{ + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; + CODEC_TIMER_TIMESTAMPS.INTCTRLB = 0; + CODEC_TIMER_TIMESTAMPS.CTRLA = TC_CLKSEL_OFF_gc; + ACA.AC1CTRL &= ~AC_ENABLE_bm; + + if (BitCount % 8) // copy the last byte, if there is an incomplete byte + CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8)); + Flags.RxDone = true; + Flags.RxPending = false; + + // set up timer that forces the minimum frame delay time from PICC to PCD + CODEC_TIMER_LOADMOD.PER = 0xFFFF; + CODEC_TIMER_LOADMOD.CNT = 0; + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + CODEC_TIMER_LOADMOD.CTRLD = 0; + CODEC_TIMER_LOADMOD.CTRLA = ISO14443A_PICC_TO_PCD_FDT_PRESCALER; + + State = STATE_FDT; +} + +ISR(CODEC_TIMER_SAMPLING_CCB_VECT) +{ + static void * JumpTable[] = { + [STATE_IDLE] = &&STATE_IDLE_LABEL, + [STATE_MILLER_SOF0] = &&STATE_MILLER_SOF0_LABEL, + [STATE_MILLER_SOF1] = &&STATE_MILLER_SOF1_LABEL, + [STATE_MILLER_TX0] = &&STATE_MILLER_TX0_LABEL, + [STATE_MILLER_TX1] = &&STATE_MILLER_TX1_LABEL, + [STATE_MILLER_EOF0] = &&STATE_MILLER_EOF0_LABEL, + [STATE_MILLER_EOF1] = &&STATE_MILLER_EOF1_LABEL, + [STATE_FDT] = &&STATE_FDT_LABEL + }; + + goto *JumpTable[State]; + + STATE_MILLER_SOF0_LABEL: + /* Output a SOF */ + CodecSetReaderField(false); + _delay_us(2.5); + CodecSetReaderField(true); + + CodecBufferIdx = 0; + SampleRegister = CodecBuffer[0]; + BitCountUp = 0; + + State = STATE_MILLER_SOF1; + return; + + STATE_MILLER_SOF1_LABEL: + State = STATE_MILLER_TX0; + return; + + STATE_MILLER_TX0_LABEL: + /* First half of bit-slot */ + if (SampleRegister & 0x01) { + /* Do Nothing */ + } else { + if (LastBit == 0) { + CodecSetReaderField(false); + _delay_us(2.5); + CodecSetReaderField(true); + } else { + /* Do Nothing */ + } + } + + State = STATE_MILLER_TX1; + return; + + STATE_MILLER_TX1_LABEL: + /* Second half of bit-slot */ + if (SampleRegister & 0x01) { + CodecSetReaderField(false); + _delay_us(2.5); + CodecSetReaderField(true); + LastBit = 1; + } else { + /* No modulation pauses */ + LastBit = 0; + } + + SampleRegister >>= 1; + if (--BitCount == 0) { + State = STATE_MILLER_EOF0; + } else { + State = STATE_MILLER_TX0; + } + + if ((++BitCountUp % 8) == 0) + SampleRegister = CodecBuffer[++CodecBufferIdx]; + return; + + STATE_MILLER_EOF0_LABEL: + if (LastBit == 0) { + CodecSetReaderField(false); + _delay_us(2.5); + CodecSetReaderField(true); + } else { + /* Do Nothing */ + } + + State = STATE_MILLER_EOF1; + return; + + STATE_MILLER_EOF1_LABEL: + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + _delay_us(50); // wait for DEMOD signal to stabilize + + /* Enable the AC interrupt, which either finds the SOC and then starts the pause-finding timer, + * or it is triggered before the SOC, which mostly isn't bad at all, since the first pause + * needs to be found. */ + ACA.STATUS = AC_AC1IF_bm; + ACA.AC1CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_BOTHEDGES_gc | AC_INTLVL_HI_gc | AC_ENABLE_bm; + + CodecBufferPtr = CodecBuffer; // use GPIOR for faster access + BitCount = 1; // the first modulation of the SOC is "found" implicitly + SampleRegister = 0x80; + + RxPendingSince = SystemGetSysTick(); + Flags.RxPending = true; + + // reset for future use + CodecBufferIdx = 0; + BitCountUp = 0; + + State = STATE_IDLE; + return; + + STATE_IDLE_LABEL: + STATE_FDT_LABEL: + return; + } + +ISR(CODEC_TIMER_TIMESTAMPS_CCA_VECT) // EOC found +{ + Reader14443A_EOC(); +} + +INLINE void Insert0(void) +{ + SampleRegister >>= 1; + if (++BitCount % 8) + return; + *CodecBufferPtr++ = SampleRegister; +} + +INLINE void Insert1(void) +{ + SampleRegister = (SampleRegister >> 1) | 0x80; + if (++BitCount % 8) + return; + *CodecBufferPtr++ = SampleRegister; +} + +ISR(ACA_AC1_vect) // this interrupt either finds the SOC or gets triggered before +{ + ACA.AC1CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt + // enable the pause-finding timer + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_RESTART_gc | TC_EVSEL_CH0_gc; + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_DIV1_gc; +} + +ISR(CODEC_TIMER_LOADMOD_CCA_VECT) // pause found +{ + uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL; + CODEC_TIMER_TIMESTAMPS.CNT = 0; + + /* This needs to be done only on the first call, + * but doing this only on a condition means wasting time, so we do it every time. */ + CODEC_TIMER_TIMESTAMPS.CTRLA = TC_CLKSEL_DIV2_gc; + + switch (tmp) // decide how many half bit periods have been modulations + { + case 0 ... 96: // 64 ticks is one half of a bit period + Insert0(); + // If one full bit period is over AND the last half bit period also was a pause, + // we have found the EOC. + if ((BitCount & 1) == 0 && (SampleRegister & 0x40) == 0) + Reader14443A_EOC(); + return; + + case 97 ... 160: // 128 ticks is a full bit period + Insert1(); + Insert0(); + return; + + default: // every value over 128 + 32 (tolerance) is considered to be 3 half bit periods + Insert1(); + Insert1(); + Insert0(); + return; + } + return; +} + +void Reader14443ACodecTask(void) +{ + if (Flags.RxPending && SYSTICK_DIFF(RxPendingSince) > ISO14443A_RX_PENDING_TIMEOUT + 1) + { + BitCount = 0; + Flags.RxDone = true; + Flags.RxPending = false; + } + if (!CodecIsReaderFieldReady()) + return; + if (!Flags.RxPending && (Flags.Start || Flags.RxDone)) + { + if (State == STATE_FDT && CODEC_TIMER_LOADMOD.CNT < ISO14443A_PICC_TO_PCD_MIN_FDT) // we are in frame delay time, so we can return later + return; + if (Flags.RxDone && BitCount > 0) // decode the raw received data + { + if (BitCount < ISO14443A_RX_MINIMUM_BITCOUNT * 2) + { + BitCount = 0; + } else { + uint8_t TmpCodecBuffer[CODEC_BUFFER_SIZE]; + memcpy(TmpCodecBuffer, CodecBuffer, (BitCount + 7) / 8); + + CodecBufferPtr = CodecBuffer; + uint16_t BitCountTmp = 0, TotalBitCount = BitCount; + BitCount = 0; + + bool breakflag = false; + + while (!breakflag && BitCountTmp < TotalBitCount) + { + uint8_t Bit = TmpCodecBuffer[BitCountTmp / 8] & 0x03; + TmpCodecBuffer[BitCountTmp / 8] >>= 2; + switch (Bit) + { + case 0b10: + Insert0(); + break; + + case 0b01: + Insert1(); + break; + + case 0b00: // EOC + if (BitCount % 8) // copy the last byte, if there is an incomplete byte + CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8)); + LEDHook(LED_CODEC_RX, LED_PULSE); + LogEntry(LOG_INFO_CODEC_RX_DATA, CodecBuffer, (BitCount + 7) / 8); + breakflag = true; + break; + + default: + // error, should not happen, TODO handle this + break; + } + BitCountTmp += 2; + } + } + } + Flags.Start = false; + Flags.RxDone = false; + + /* Call application with received data */ + BitCount = ApplicationProcess(CodecBuffer, BitCount); + + if (BitCount > 0) + { + /* + * Prepare for Manchester decoding. + * The basic idea is to use two timers. The first one will be reset everytime the DEMOD signal + * passes a (configurable) threshold. This is realized with the event system and an analog + * comparator. + * Once this timer reaches 3/4 of a bit half (this means it has not been reset this long), we + * assume there is a pause. Now we read the second timers count value and can decide how many + * bit halves had modulations since the last pause. + */ + + /* Configure and enable the analog comparator for finding pauses in the DEMOD signal. */ + ACA.AC1CTRL = AC_HSMODE_bm | AC_HYSMODE_NO_gc | AC_INTMODE_BOTHEDGES_gc | AC_ENABLE_bm; + + /* This timer will be used to detect the pauses between the modulation sequences. */ + CODEC_TIMER_LOADMOD.CTRLA = 0; + CODEC_TIMER_LOADMOD.CNT = 0; + CODEC_TIMER_LOADMOD.PER = 127; // with 27.12 MHz this is exactly one half bit width + CODEC_TIMER_LOADMOD.CCA = 95; // with 27.12 MHz this is 3/4 of a half bit width + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + CODEC_TIMER_LOADMOD.INTFLAGS = TC1_CCAIF_bm; + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCAINTLVL_HI_gc; + + /* This timer will be used to find out how many bit halfs since the last pause have been passed. */ + CODEC_TIMER_TIMESTAMPS.CNT = 0; + CODEC_TIMER_TIMESTAMPS.PER = 0xFFFF; + CODEC_TIMER_TIMESTAMPS.CCA = 256; + CODEC_TIMER_TIMESTAMPS.INTCTRLA = 0; + CODEC_TIMER_TIMESTAMPS.INTFLAGS = TC1_CCAIF_bm; + CODEC_TIMER_TIMESTAMPS.INTCTRLB = TC_CCAINTLVL_LO_gc; + + /* Use the event system for resetting the pause-detecting timer. */ + EVSYS.CH0MUX = EVSYS_CHMUX_ACA_CH1_gc; // on every ACA_AC1 INT + EVSYS.CH0CTRL = EVSYS_DIGFILT_1SAMPLE_gc; + + ACA.AC0CTRL = 0; + CODEC_DEMOD_IN_PORT.INTCTRL = 0; + + LEDHook(LED_CODEC_TX, LED_PULSE); + LogEntry(LOG_INFO_CODEC_TX_DATA, CodecBuffer, (BitCount + 7) / 8); + + /* Set state and start timer for Miller encoding. */ + State = STATE_MILLER_SOF0; + LastBit = 0; + CODEC_TIMER_SAMPLING.CNT = 0; + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc; + } + } +} + +void Reader14443ACodecStart(void) +{ + /* Application wants us to start a card transaction */ + BitCount = 0; + Flags.Start = true; + + CodecReaderFieldStart(); +} + +void Reader14443ACodecReset(void) +{ + Reader14443A_EOC(); // this breaks every interrupt etc. + State = STATE_IDLE; + Flags.RxDone = false; + Flags.Start = false; + CodecReaderFieldStop(); +} diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h new file mode 100644 index 00000000..5abca801 --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.h @@ -0,0 +1,23 @@ +/* + * Reader14443-2A.h + * + * Created on: 26.08.2014 + * Author: sk + */ + +#ifndef READER14443_2A_H_ +#define READER14443_2A_H_ + +#include "Codec.h" +#include "Terminal/CommandLine.h" + +/* Codec Interface */ +void Reader14443ACodecInit(void); +void Reader14443ACodecDeInit(void); +void Reader14443ACodecTask(void); + +/* Application Interface */ +void Reader14443ACodecStart(void); +void Reader14443ACodecReset(void); + +#endif /* READER14443_2A_H_ */ diff --git a/Firmware/Chameleon-Mini/Common.c b/Firmware/Chameleon-Mini/Common.c new file mode 100644 index 00000000..51dd4520 --- /dev/null +++ b/Firmware/Chameleon-Mini/Common.c @@ -0,0 +1,86 @@ +#include "Common.h" + +const uint8_t PROGMEM BitReverseByteTable[256] = { +# define R2(n) n, n + 2*64, n + 1*64, n + 3*64 +# define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16) +# define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 ) + R6(0), R6(2), R6(1), R6(3) +}; + +const uint8_t PROGMEM OddParityByteTable[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, +}; + +uint16_t BufferToHexString(char* HexOut, uint16_t MaxChars, const void* Buffer, uint16_t ByteCount) +{ + uint8_t* ByteBuffer = (uint8_t*) Buffer; + uint16_t CharCount = 0; + + /* Account for '\0' at the end */ + MaxChars--; + + while( (ByteCount > 0) && (MaxChars >= 2) ) { + uint8_t Byte = *ByteBuffer; + + HexOut[0] = NIBBLE_TO_HEXCHAR( (Byte >> 4) & 0x0F ); + HexOut[1] = NIBBLE_TO_HEXCHAR( (Byte >> 0) & 0x0F ); + + HexOut += 2; + MaxChars -= 2; + CharCount += 2; + ByteBuffer++; + ByteCount -= 1; + } + + *HexOut = '\0'; + + return CharCount; +} + +uint16_t HexStringToBuffer(void* Buffer, uint16_t MaxBytes, const char* HexIn) +{ + uint8_t* ByteBuffer = (uint8_t*) Buffer; + uint16_t ByteCount = 0; + + while( (HexIn[0] != '\0') && (HexIn[1] != '\0') && (MaxBytes > 0) ) { + if (VALID_HEXCHAR(HexIn[0]) && VALID_HEXCHAR(HexIn[1])) { + uint8_t Byte = 0; + + Byte |= HEXCHAR_TO_NIBBLE(HexIn[0]) << 4; + Byte |= HEXCHAR_TO_NIBBLE(HexIn[1]) << 0; + + *ByteBuffer = Byte; + + ByteBuffer++; + MaxBytes--; + ByteCount++; + HexIn += 2; + } else { + /* HEX chars only */ + return 0; + } + } + + if ( (HexIn[0] != '\0') && (HexIn[1] == '\0') ) { + /* Odd number of characters */ + return 0; + } + + return ByteCount; +} + diff --git a/Firmware/Chameleon-Mini/Common.h b/Firmware/Chameleon-Mini/Common.h new file mode 100644 index 00000000..fbb7515e --- /dev/null +++ b/Firmware/Chameleon-Mini/Common.h @@ -0,0 +1,65 @@ +/* + * Common.h + * + * Created on: 20.03.2013 + * Author: skuser + */ + +#ifndef COMMON_H_ +#define COMMON_H_ + +#include +#include +#include +#include +#include +#include + +#define ODD_PARITY(Value) OddParityBit(Value)//(parity_even_bit(Value) ? 0 : 1) + +#define INLINE \ + static inline __attribute__((always_inline)) + +#define NIBBLE_TO_HEXCHAR(x) ( (x) < 0x0A ? (x) + '0' : (x) + 'A' - 0x0A ) +#define HEXCHAR_TO_NIBBLE(x) ( (x) < 'A' ? (x) - '0' : (x) - 'A' + 0x0A ) +#define VALID_HEXCHAR(x) ( ( (x) >= '0' && (x) <= '9' ) || ( (x) >= 'A' && (x) <= 'F' ) ) +#define MIN(x,y) ( (x) < (y) ? (x) : (y) ) +#define MAX(x,y) ( (x) > (y) ? (x) : (y) ) +#define SYSTICK_DIFF(since) ((uint16_t) (SystemGetSysTick() - since)) +#define SYSTICK_DIFF_100MS(since) (SYSTICK_DIFF(since) / 100) + +#define BITS_PER_BYTE 8 + +uint16_t BufferToHexString(char* HexOut, uint16_t MaxChars, const void* Buffer, uint16_t ByteCount); +uint16_t HexStringToBuffer(void* Buffer, uint16_t MaxBytes, const char* HexIn); + +INLINE uint8_t BitReverseByte(uint8_t Byte) +{ + extern const uint8_t PROGMEM BitReverseByteTable[]; + + return pgm_read_byte(&BitReverseByteTable[Byte]); +} + +INLINE uint8_t OddParityBit(uint8_t Byte) +{ + extern const uint8_t PROGMEM OddParityByteTable[]; + + return pgm_read_byte(&OddParityByteTable[Byte]); +} + +INLINE uint8_t StringLength(const char* Str, uint8_t MaxLen) +{ + uint8_t StrLen = 0; + + while(MaxLen > 0) { + if (*Str++ == '\0') + break; + + MaxLen--; + StrLen++; + } + + return StrLen; +} + +#endif /* COMMON_H_ */ diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c new file mode 100644 index 00000000..6f0a860c --- /dev/null +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -0,0 +1,241 @@ +/* + * Standards.c + * + * Created on: 15.02.2013 + * Author: skuser + */ + +#include "Configuration.h" +#include "Settings.h" +#include +#include "Map.h" +#include "AntennaLevel.h" + +/* Map IDs to text */ +static const MapEntryType PROGMEM ConfigurationMap[] = { + { .Id = CONFIG_NONE, .Text = "NONE" }, +#ifdef CONFIG_MF_ULTRALIGHT_SUPPORT + { .Id = CONFIG_MF_ULTRALIGHT, .Text = "MF_ULTRALIGHT" }, +#endif +#ifdef CONFIG_MF_CLASSIC_1K_SUPPORT + { .Id = CONFIG_MF_CLASSIC_1K, .Text = "MF_CLASSIC_1K" }, +#endif +#ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT + { .Id = CONFIG_MF_CLASSIC_1K_7B, .Text = "MF_CLASSIC_1K_7B" }, +#endif +#ifdef CONFIG_MF_CLASSIC_4K_SUPPORT + { .Id = CONFIG_MF_CLASSIC_4K, .Text = "MF_CLASSIC_4K" }, +#endif +#ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT + { .Id = CONFIG_MF_CLASSIC_4K_7B, .Text = "MF_CLASSIC_4K_7B" }, +#endif +#ifdef CONFIG_ISO14443A_SNIFF_SUPPORT + { .Id = CONFIG_ISO14443A_SNIFF, .Text = "ISO14443A_SNIFF" }, +#endif +#ifdef CONFIG_ISO14443A_READER_SUPPORT + { .Id = CONFIG_ISO14443A_READER, .Text = "ISO14443A_READER" }, +#endif +}; + +/* Include all Codecs and Applications */ +#include "Codec/Codec.h" +#include "Application/Application.h" + +static void CodecInitDummy(void) { } +static void CodecDeInitDummy(void) { } +static void CodecTaskDummy(void) { } +static void ApplicationInitDummy(void) {} +static void ApplicationResetDummy(void) {} +static void ApplicationTaskDummy(void) {} +static void ApplicationTickDummy(void) {} +static uint16_t ApplicationProcessDummy(uint8_t* ByteBuffer, uint16_t ByteCount) { return 0; } +static void ApplicationGetUidDummy(ConfigurationUidType Uid) { } +static void ApplicationSetUidDummy(ConfigurationUidType Uid) { } + + +static const PROGMEM ConfigurationType ConfigurationTable[] = { + [CONFIG_NONE] = { + .CodecInitFunc = CodecInitDummy, + .CodecDeInitFunc = CodecDeInitDummy, + .CodecTaskFunc = CodecTaskDummy, + .ApplicationInitFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationTaskFunc = ApplicationTaskDummy, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = ApplicationProcessDummy, + .ApplicationGetUidFunc = ApplicationGetUidDummy, + .ApplicationSetUidFunc = ApplicationSetUidDummy, + .UidSize = 0, + .MemorySize = 0, + .ReadOnly = true + }, +#ifdef CONFIG_MF_ULTRALIGHT_SUPPORT + [CONFIG_MF_ULTRALIGHT] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareUltralightAppInit, + .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationTaskFunc = MifareUltralightAppTask, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = MifareUltralightAppProcess, + .ApplicationGetUidFunc = MifareUltralightGetUid, + .ApplicationSetUidFunc = MifareUltralightSetUid, + .UidSize = MIFARE_ULTRALIGHT_UID_SIZE, + .MemorySize = MIFARE_ULTRALIGHT_MEM_SIZE, + .ReadOnly = false + }, +#endif +#ifdef CONFIG_MF_CLASSIC_1K_SUPPORT + [CONFIG_MF_CLASSIC_1K] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareClassicAppInit1K, + .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationTaskFunc = MifareClassicAppTask, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = MifareClassicAppProcess, + .ApplicationGetUidFunc = MifareClassicGetUid, + .ApplicationSetUidFunc = MifareClassicSetUid, + .UidSize = MIFARE_CLASSIC_UID_SIZE, + .MemorySize = MIFARE_CLASSIC_1K_MEM_SIZE, + .ReadOnly = false + }, +#endif +#ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT + [CONFIG_MF_CLASSIC_1K_7B] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareClassicAppInit1K, + .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationTaskFunc = MifareClassicAppTask, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = MifareClassicAppProcess, + .ApplicationGetUidFunc = MifareClassicGetUid, + .ApplicationSetUidFunc = MifareClassicSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = MIFARE_CLASSIC_1K_MEM_SIZE, + .ReadOnly = false + }, +#endif +#ifdef CONFIG_MF_CLASSIC_4K_SUPPORT + [CONFIG_MF_CLASSIC_4K] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareClassicAppInit4K, + .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationTaskFunc = MifareClassicAppTask, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = MifareClassicAppProcess, + .ApplicationGetUidFunc = MifareClassicGetUid, + .ApplicationSetUidFunc = MifareClassicSetUid, + .UidSize = MIFARE_CLASSIC_UID_SIZE, + .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, + .ReadOnly = false + }, +#endif +#ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT + [CONFIG_MF_CLASSIC_4K_7B] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareClassicAppInit4K, + .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationTaskFunc = MifareClassicAppTask, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = MifareClassicAppProcess, + .ApplicationGetUidFunc = MifareClassicGetUid, + .ApplicationSetUidFunc = MifareClassicSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, + .ReadOnly = false + }, +#endif +#ifdef CONFIG_ISO14443A_SNIFF_SUPPORT + [CONFIG_ISO14443A_SNIFF] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationTaskFunc = ApplicationTaskDummy, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = ApplicationProcessDummy, + .ApplicationGetUidFunc = ApplicationGetUidDummy, + .ApplicationSetUidFunc = ApplicationSetUidDummy, + .UidSize = 0, + .MemorySize = 0, + .ReadOnly = true + }, +#endif +#ifdef CONFIG_ISO14443A_READER_SUPPORT + [CONFIG_ISO14443A_READER] = { + .CodecInitFunc = Reader14443ACodecInit, + .CodecDeInitFunc = Reader14443ACodecDeInit, + .CodecTaskFunc = Reader14443ACodecTask, + .ApplicationInitFunc = Reader14443AAppInit, + .ApplicationResetFunc = Reader14443AAppReset, + .ApplicationTaskFunc = Reader14443AAppTask, + .ApplicationTickFunc = Reader14443AAppTick, + .ApplicationProcessFunc = Reader14443AAppProcess, + .ApplicationGetUidFunc = ApplicationGetUidDummy, + .ApplicationSetUidFunc = ApplicationSetUidDummy, + .UidSize = 0, + .MemorySize = 0, + .ReadOnly = false + }, +#endif +}; + +ConfigurationType ActiveConfiguration; + +void ConfigurationInit(void) +{ + memcpy_P(&ActiveConfiguration, + &ConfigurationTable[CONFIG_NONE], sizeof(ConfigurationType)); + + ConfigurationSetById(GlobalSettings.ActiveSettingPtr->Configuration); +} + +void ConfigurationSetById( ConfigurationEnum Configuration ) +{ + CodecDeInit(); + + CommandLinePendingTaskBreak(); // break possibly pending task + + GlobalSettings.ActiveSettingPtr->Configuration = Configuration; + + /* Copy struct from PROGMEM to RAM */ + memcpy_P(&ActiveConfiguration, + &ConfigurationTable[Configuration], sizeof(ConfigurationType)); + + CodecInit(); + ApplicationInit(); +} + +void ConfigurationGetByName(char* Configuration, uint16_t BufferSize) +{ + MapIdToText(ConfigurationMap, sizeof(ConfigurationMap)/sizeof(*ConfigurationMap), GlobalSettings.ActiveSettingPtr->Configuration, Configuration, BufferSize); +} + +bool ConfigurationSetByName(const char* Configuration) +{ + MapIdType Id; + + if (MapTextToId(ConfigurationMap, sizeof(ConfigurationMap)/sizeof(*ConfigurationMap), Configuration, &Id)) { + ConfigurationSetById(Id); + LogEntry(LOG_INFO_CONFIG_SET, Configuration, StringLength(Configuration, CONFIGURATION_NAME_LENGTH_MAX-1)); + return true; + } else { + return false; + } +} + +void ConfigurationGetList(char* List, uint16_t BufferSize) +{ + MapToString(ConfigurationMap, sizeof(ConfigurationMap)/sizeof(*ConfigurationMap), List, BufferSize); +} + diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h new file mode 100644 index 00000000..d6458573 --- /dev/null +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -0,0 +1,136 @@ +/* + * Standards.h + * + * Created on: 15.02.2013 + * Author: skuser + */ +/** \file */ +#ifndef STANDARDS_H_ +#define STANDARDS_H_ + +#include +#include + +#define CONFIGURATION_NAME_LENGTH_MAX 32 +#define CONFIGURATION_UID_SIZE_MAX 16 + +typedef uint8_t ConfigurationUidType[CONFIGURATION_UID_SIZE_MAX]; + +typedef enum { + /* This HAS to be the first element */ + CONFIG_NONE = 0, + +#ifdef CONFIG_MF_ULTRALIGHT_SUPPORT + CONFIG_MF_ULTRALIGHT, +#endif +#ifdef CONFIG_MF_CLASSIC_1K_SUPPORT + CONFIG_MF_CLASSIC_1K, +#endif +#ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT + CONFIG_MF_CLASSIC_1K_7B, +#endif +#ifdef CONFIG_MF_CLASSIC_4K_SUPPORT + CONFIG_MF_CLASSIC_4K, +#endif +#ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT + CONFIG_MF_CLASSIC_4K_7B, +#endif +#ifdef CONFIG_ISO14443A_SNIFF_SUPPORT + CONFIG_ISO14443A_SNIFF, +#endif +#ifdef CONFIG_ISO14443A_READER_SUPPORT + CONFIG_ISO14443A_READER, +#endif + /* This HAS to be the last element */ + CONFIG_COUNT +} ConfigurationEnum; + +/** With this `struct` the behavior of a configuration is defined. */ +typedef struct { + /** + * \defgroup + * \name Codec + * Codec related methods. + * @{ + */ + /** Function that initializes the codec. */ + void (*CodecInitFunc) (void); + /** Function that deinitializes the codec. */ + void (*CodecDeInitFunc) (void); + /** Function that is called on every iteration of the main loop. + * Within this function the essential codec work is done. + */ + void (*CodecTaskFunc) (void); + /** + * @} + */ + + /** + * \defgroup + * \name Application + * Application related functions. + * @{ + */ + /** Function that initializes the application. */ + void (*ApplicationInitFunc) (void); + /** Function that resets the application. */ + void (*ApplicationResetFunc) (void); + /** Function that is called on every iteration of the main loop. Application work that is independent from the codec layer can be done here. */ + void (*ApplicationTaskFunc) (void); + /** Function that is called roughly every 100ms. This can be used for parallel tasks of the application, that is independent of the codec module. */ + void (*ApplicationTickFunc) (void); + /** This function does two important things. It gets called by the codec. + * The first task is to deliver data that have been received by the codec module to + * the application module. The application then can decide how to answer to these data and return + * the response to the codec module, which will process it according to the configured codec. + * + * \param ByteBuffer Pointer to the start of the buffer, where the received data are and where the + * application can put the response data. + * \param BitCount Number of bits that have been received. + * + * \return Number of bits of the response. + */ + uint16_t (*ApplicationProcessFunc) (uint8_t* ByteBuffer, uint16_t BitCount); + /** + * Writes the UID for the current configuration to the given buffer. + * \param Uid The target buffer. + */ + void (*ApplicationGetUidFunc) (ConfigurationUidType Uid); + /** + * Writes a given UID to the current configuration. + * \param Uid The source buffer. + */ + void (*ApplicationSetUidFunc) (ConfigurationUidType Uid); + /** + * @} + */ + + /** + * Defines how many space the configuration needs. For emulating configurations this is the memory space of + * the emulated card. + * + * \note For reader or sniff configurations this is set to zero. + */ + uint16_t MemorySize; + /** + * Defines the size of the UID for emulating configurations. + * + * \note For reader or sniff configurations this is set to zero. + */ + uint8_t UidSize; + /** + * Implies whether the Memory can be changed. + */ + bool ReadOnly; + +} ConfigurationType; + +extern ConfigurationType ActiveConfiguration; + +void ConfigurationInit(void); +void ConfigurationSetById(ConfigurationEnum Configuration); +void ConfigurationGetByName(char* Configuration, uint16_t BufferSize); +bool ConfigurationSetByName(const char* Configuration); +void ConfigurationGetList(char* ConfigurationList, uint16_t BufferSize); + +#endif /* STANDARDS_H_ */ diff --git a/Firmware/Chameleon-Mini/LED.c b/Firmware/Chameleon-Mini/LED.c new file mode 100644 index 00000000..c7e99898 --- /dev/null +++ b/Firmware/Chameleon-Mini/LED.c @@ -0,0 +1,168 @@ +#include "LED.h" +#include "Settings.h" +#include "Map.h" + +#include "Terminal/CommandLine.h" +#include "System.h" + +#define BLINK_PRESCALER 2 /* x LEDTick(); */ + +LEDActionEnum LEDGreenAction = LED_NO_ACTION; +LEDActionEnum LEDRedAction = LED_NO_ACTION; + +static const MapEntryType PROGMEM LEDFunctionMap[] = { + { .Id = LED_NO_FUNC, .Text = "NONE" }, + { .Id = LED_POWERED, .Text = "POWERED" }, + { .Id = LED_TERMINAL_CONN, .Text = "TERMINAL_CONN" }, + { .Id = LED_TERMINAL_RXTX, .Text = "TERMINAL_RXTX" }, + { .Id = LED_SETTING_CHANGE, .Text = "SETTING_CHANGE" }, + { .Id = LED_MEMORY_STORED, .Text = "MEMORY_STORED" }, + { .Id = LED_MEMORY_CHANGED, .Text = "MEMORY_CHANGED" }, + { .Id = LED_CODEC_RX, .Text = "CODEC_RX" }, + { .Id = LED_CODEC_TX, .Text = "CODEC_TX" }, + { .Id = LED_FIELD_DETECTED, .Text = "FIELD_DETECTED" }, + { .Id = LED_LOG_MEM_FULL, .Text = "LOGMEM_FULL" }, +}; + +INLINE void Tick(uint8_t Mask, LEDActionEnum* Action) +{ + static uint8_t LEDRedBlinkPrescaler = 0; + static uint8_t LEDGreenBlinkPrescaler = 0; + uint8_t * BlinkPrescaler = (Action == &LEDGreenAction) ? &LEDGreenBlinkPrescaler : &LEDRedBlinkPrescaler; + + switch (*Action) + { + case LED_NO_ACTION: + /* Do nothing */ + break; + + case LED_OFF: + LED_PORT.OUTCLR = Mask; + *Action = LED_NO_ACTION; + break; + + case LED_ON: + LED_PORT.OUTSET = Mask; + *Action = LED_NO_ACTION; + break; + + case LED_TOGGLE: + LED_PORT.OUTTGL = Mask; + *Action = LED_NO_ACTION; + break; + + case LED_PULSE: + if (!(LED_PORT.OUT & Mask)) { + LED_PORT.OUTSET = Mask; + } else { + LED_PORT.OUTCLR = Mask; + *Action = LED_NO_ACTION; + } + break; + + case LED_BLINK_1X ... LED_BLINK_8X: + if (++(*BlinkPrescaler) == BLINK_PRESCALER) { + *BlinkPrescaler = 0; + + /* Blink functionality occurs at slower speed than Tick-frequency */ + if (!(LED_PORT.OUT & Mask)) { + /* LED is off, turn it on */ + LED_PORT.OUTSET = Mask; + } else { + /* LED is on, turn it off and change state */ + LED_PORT.OUTCLR = Mask; + + if (*Action == LED_BLINK_1X) { + *Action = LED_NO_ACTION; + } else { + /* Still some blinks to do. Use the fact that LED_BLINK_XY are ordered sequentially */ + *Action = *Action - 1; + } + } + } + break; + + default: + /* Should not happen (TM) */ + *Action = LED_NO_ACTION; + break; + + } +} + +void LEDInit(void) +{ + LED_PORT.DIRSET = LED_MASK; +} + + +void LEDTick(void) +{ + Tick(LED_RED, &LEDRedAction); + Tick(LED_GREEN, &LEDGreenAction); +} + +void LEDGetFuncList(char* List, uint16_t BufferSize) +{ + MapToString(LEDFunctionMap, sizeof(LEDFunctionMap)/sizeof(*LEDFunctionMap), List, BufferSize); +} + +void LEDSetFuncById(uint8_t Mask, LEDHookEnum Function) +{ +#ifndef LED_SETTING_GLOBAL + if (Mask & LED_GREEN) { + GlobalSettings.ActiveSettingPtr->LEDGreenFunction = Func; + } + + if (Mask & LED_RED) { + GlobalSettings.ActiveSettingPtr->LEDRedFunction = Func; + } +#else + /* Write LED func to all settings when using global settings */ + for (uint8_t i=0; iLEDGreenFunction, Function, BufferSize); + } else if (Mask == LED_RED) { + MapIdToText(LEDFunctionMap, sizeof(LEDFunctionMap)/sizeof(*LEDFunctionMap), + GlobalSettings.ActiveSettingPtr->LEDRedFunction, Function, BufferSize); + } +} + +bool LEDSetFuncByName(uint8_t Mask, const char* Function) +{ + MapIdType Id; + + if (MapTextToId(LEDFunctionMap, sizeof(LEDFunctionMap)/sizeof(*LEDFunctionMap), Function, &Id)) { + LEDSetFuncById(Mask, Id); + return true; + } else { + return false; + } +} + diff --git a/Firmware/Chameleon-Mini/LED.h b/Firmware/Chameleon-Mini/LED.h new file mode 100644 index 00000000..b739dd11 --- /dev/null +++ b/Firmware/Chameleon-Mini/LED.h @@ -0,0 +1,70 @@ +/* + * LED.h + * + * Created on: 10.02.2013 + * Author: skuser + */ + +#ifndef LED_H +#define LED_H + +#include +#include "Common.h" + +#define LED_PORT PORTA +#define LED_GREEN PIN4_bm +#define LED_RED PIN3_bm +#define LED_MASK (LED_GREEN | LED_RED) + +typedef enum LEDFunctionEnum { + LED_NO_FUNC = 0, /* Don't light up the LED */ + LED_POWERED, /* Light up the LED whenever the Chameleon is powered */ + + LED_TERMINAL_CONN, /* A Terminal/USB connection has been established */ + LED_TERMINAL_RXTX, /* There is traffic on the terminal */ + + LED_SETTING_CHANGE, /* Outputs a blink code that shows the current setting */ + + LED_MEMORY_STORED, /* Blink once when memory has been stored to flash */ + LED_MEMORY_CHANGED, /* Switch LED on when card memory has changed compared to flash */ + + LED_FIELD_DETECTED, /* Shows LED while a reader field is being detected or turned on by the chameleon itself */ + + LED_CODEC_RX, /* Blink LED when receiving codec data */ + LED_CODEC_TX, /* Blink LED when transmitting codec data */ + + LED_LOG_MEM_FULL, /* Light up if log memory is full. */ + + //TODO: LED_APP_SELECTED, /* Show LED while the correct UID has been selected and the application is active */ + /* Has to be last element */ + LED_FUNC_COUNT +} LEDHookEnum; + +typedef enum LEDActionEnum { + LED_NO_ACTION = 0x00, + LED_OFF = 0x10, + LED_ON = 0x11, + LED_TOGGLE = 0x12, + LED_PULSE = 0x13, + LED_BLINK = 0x20, + LED_BLINK_1X = 0x20, + LED_BLINK_2X, /* Have to be sequentially ordered */ + LED_BLINK_3X, + LED_BLINK_4X, + LED_BLINK_5X, + LED_BLINK_6X, + LED_BLINK_7X, + LED_BLINK_8X, +} LEDActionEnum; + + + +void LEDInit(void); +void LEDTick(void); + +void LEDGetFuncList(char* List, uint16_t BufferSize); +void LEDSetFuncById(uint8_t Mask, LEDHookEnum Func); +void LEDGetFuncByName(uint8_t Mask, char* Function, uint16_t BufferSize); +bool LEDSetFuncByName(uint8_t Mask, const char* Function); + +#endif /* LED_H */ diff --git a/Firmware/Chameleon-Mini/LEDHook.h b/Firmware/Chameleon-Mini/LEDHook.h new file mode 100644 index 00000000..ac883518 --- /dev/null +++ b/Firmware/Chameleon-Mini/LEDHook.h @@ -0,0 +1,26 @@ +/* + * LEDHook.h + * + * Created on: 02.12.2014 + * Author: sk + */ + +#ifndef LEDHOOK_H_ +#define LEDHOOK_H_ + +#include "Settings.h" + +INLINE void LEDHook(LEDHookEnum Func, LEDActionEnum Action) { + extern LEDActionEnum LEDGreenAction; + extern LEDActionEnum LEDRedAction; + + if (GlobalSettings.ActiveSettingPtr->LEDGreenFunction == Func) { + LEDGreenAction = Action; + } + + if (GlobalSettings.ActiveSettingPtr->LEDRedFunction == Func) { + LEDRedAction = Action; + } +} + +#endif /* LEDHOOK_H_ */ diff --git a/Firmware/Chameleon-Mini/LUFAConfig.h b/Firmware/Chameleon-Mini/LUFAConfig.h new file mode 100644 index 00000000..e86648b8 --- /dev/null +++ b/Firmware/Chameleon-Mini/LUFAConfig.h @@ -0,0 +1,78 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2012. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * \brief LUFA Library Configuration Header File + * + * This header file is used to configure LUFA's compile time options, + * as an alternative to the compile time constants supplied through + * a makefile. + * + * For information on what each token does, refer to the LUFA + * manual section "Summary of Compile Tokens". + */ + +#ifndef _LUFA_CONFIG_H_ +#define _LUFA_CONFIG_H_ + + /* Non-USB Related Configuration Tokens: */ +// #define DISABLE_TERMINAL_CODES + + /* USB Class Driver Related Tokens: */ +// #define HID_HOST_BOOT_PROTOCOL_ONLY +// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} +// #define HID_USAGE_STACK_DEPTH {Insert Value Here} +// #define HID_MAX_COLLECTIONS {Insert Value Here} +// #define HID_MAX_REPORTITEMS {Insert Value Here} +// #define HID_MAX_REPORT_IDS {Insert Value Here} +// #define NO_CLASS_DRIVER_AUTOFLUSH + + /* General USB Driver Related Tokens: */ + #define USE_STATIC_OPTIONS \ + (USB_OPT_BUSEVENT_PRIMED | USB_DEVICE_OPT_FULLSPEED | /*USB_OPT_PLLCLKSRC*/ USB_OPT_RC32MCLKSRC) + #define USB_DEVICE_ONLY +// #define USB_STREAM_TIMEOUT_MS {Insert Value Here} +// #define NO_LIMITED_CONTROLLER_CONNECT +// #define NO_SOF_EVENTS + + /* USB Device Mode Driver Related Tokens: */ +// #define USE_RAM_DESCRIPTORS + #define USE_FLASH_DESCRIPTORS +// #define USE_EEPROM_DESCRIPTORS +// #define NO_INTERNAL_SERIAL + #define FIXED_CONTROL_ENDPOINT_SIZE 8 +// #define DEVICE_STATE_AS_GPIOR {Insert Value Here} + #define FIXED_NUM_CONFIGURATIONS 1 +// #define CONTROL_ONLY_DEVICE + #define MAX_ENDPOINT_INDEX 5 +// #define NO_DEVICE_REMOTE_WAKEUP +// #define NO_DEVICE_SELF_POWER + +#endif diff --git a/Firmware/Chameleon-Mini/LUFADescriptors.c b/Firmware/Chameleon-Mini/LUFADescriptors.c new file mode 100644 index 00000000..2ae53667 --- /dev/null +++ b/Firmware/Chameleon-Mini/LUFADescriptors.c @@ -0,0 +1,271 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2012. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "LUFADescriptors.h" +#include + +/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +{ + .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, + +#if LUFA_VERSION_INTEGER >= 0x140928 + .USBSpecification = VERSION_BCD(1,1,0), +#else + .USBSpecification = VERSION_BCD(01.10), +#endif + .Class = CDC_CSCP_CDCClass, + .SubClass = CDC_CSCP_NoSpecificSubclass, + .Protocol = CDC_CSCP_NoSpecificProtocol, + + .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, + + .VendorID = 0x16D0, // MCS Electronics (http://www.mcselec.com) + .ProductID = 0x04B2, // darksimpson's PID #2 granted to Chameleon-Mini +#if LUFA_VERSION_INTEGER >= 0x140928 + .ReleaseNumber = VERSION_BCD(0,0,1), +#else + .ReleaseNumber = VERSION_BCD(00.01), +#endif + .ManufacturerStrIndex = 0x01, + .ProductStrIndex = 0x02, + .SerialNumStrIndex = USE_INTERNAL_SERIAL, + + .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS +}; + +/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +{ + .Config = + { + .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, + + .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), + .TotalInterfaces = 2, + + .ConfigurationNumber = 1, + .ConfigurationStrIndex = NO_DESCRIPTOR, + + .ConfigAttributes = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED), + + .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) + }, + + .CDC_CCI_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 0, + .AlternateSetting = 0, + + .TotalEndpoints = 1, + + .Class = CDC_CSCP_CDCClass, + .SubClass = CDC_CSCP_ACMSubclass, + .Protocol = CDC_CSCP_ATCommandProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .CDC_Functional_Header = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = DTYPE_CSInterface}, + .Subtype = CDC_DSUBTYPE_CSInterface_Header, + +#if LUFA_VERSION_INTEGER >= 0x140928 + .CDCSpecification = VERSION_BCD(1,1,0), +#else + .CDCSpecification = VERSION_BCD(01.10), +#endif + }, + + .CDC_Functional_ACM = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = DTYPE_CSInterface}, + .Subtype = CDC_DSUBTYPE_CSInterface_ACM, + + .Capabilities = 0x06, + }, + + .CDC_Functional_Union = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = DTYPE_CSInterface}, + .Subtype = CDC_DSUBTYPE_CSInterface_Union, + + .MasterInterfaceNumber = 0, + .SlaveInterfaceNumber = 1, + }, + + .CDC_NotificationEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_NOTIFICATION_EPADDR, + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_NOTIFICATION_EPSIZE, + .PollingIntervalMS = 0xFF + }, + + .CDC_DCI_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 1, + .AlternateSetting = 0, + + .TotalEndpoints = 2, + + .Class = CDC_CSCP_CDCDataClass, + .SubClass = CDC_CSCP_NoDataSubclass, + .Protocol = CDC_CSCP_NoDataProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .CDC_DataOutEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_RX_EPADDR, + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_TXRX_EPSIZE, + .PollingIntervalMS = 0x05 + }, + + .CDC_DataInEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_TX_EPADDR, + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_TXRX_EPSIZE, + .PollingIntervalMS = 0x05 + } +}; + +/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. + */ +const USB_Descriptor_String_t PROGMEM LanguageString = +{ + .Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String}, + + .UnicodeString = {LANGUAGE_ID_ENG} +}; + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +const USB_Descriptor_String_t PROGMEM ManufacturerString = +{ + .Header = {.Size = USB_STRING_LEN(20), .Type = DTYPE_String}, + + .UnicodeString = L"Kasper & Oswald GmbH" +}; + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +const USB_Descriptor_String_t PROGMEM ProductString = +{ + .Header = {.Size = USB_STRING_LEN(14), .Type = DTYPE_String}, + + .UnicodeString = L"Chameleon-Mini" +}; + +/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + const void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = &DeviceDescriptor; + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = &ConfigurationDescriptor; + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + switch (DescriptorNumber) + { + case 0x00: + Address = &LanguageString; + Size = pgm_read_byte(&LanguageString.Header.Size); + break; + case 0x01: + Address = &ManufacturerString; + Size = pgm_read_byte(&ManufacturerString.Header.Size); + break; + case 0x02: + Address = &ProductString; + Size = pgm_read_byte(&ProductString.Header.Size); + break; + } + + break; + } + + *DescriptorAddress = Address; + return Size; +} + diff --git a/Firmware/Chameleon-Mini/LUFADescriptors.h b/Firmware/Chameleon-Mini/LUFADescriptors.h new file mode 100644 index 00000000..500649f5 --- /dev/null +++ b/Firmware/Chameleon-Mini/LUFADescriptors.h @@ -0,0 +1,89 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2012. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include + + /* Macros: */ + /** Endpoint address of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2) + + /** Endpoint address of the CDC device-to-host data IN endpoint. */ + #define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3) + + /** Endpoint address of the CDC host-to-device data OUT endpoint. */ + #define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4) + + /** Size in bytes of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPSIZE 8 + + /** Size in bytes of the CDC data IN and OUT endpoints. */ + #define CDC_TXRX_EPSIZE 16 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; + + // CDC Control Interface + USB_Descriptor_Interface_t CDC_CCI_Interface; + USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header; + USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM; + USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union; + USB_Descriptor_Endpoint_t CDC_NotificationEndpoint; + + // CDC Data Interface + USB_Descriptor_Interface_t CDC_DCI_Interface; + USB_Descriptor_Endpoint_t CDC_DataOutEndpoint; + USB_Descriptor_Endpoint_t CDC_DataInEndpoint; + } USB_Descriptor_Configuration_t; + + /* Function Prototypes: */ + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/Firmware/Chameleon-Mini/Log.c b/Firmware/Chameleon-Mini/Log.c new file mode 100644 index 00000000..405ce00a --- /dev/null +++ b/Firmware/Chameleon-Mini/Log.c @@ -0,0 +1,209 @@ +#include "Log.h" +#include "Settings.h" +#include "Terminal/Terminal.h" +#include "System.h" +#include "Map.h" +#include "LEDHook.h" + +static uint8_t LogMem[LOG_SIZE]; +static uint8_t* LogMemPtr; +static uint16_t LogMemLeft; +static uint16_t LogFRAMAddr = FRAM_LOG_START_ADDR; +LogFuncType CurrentLogFunc; + +static const MapEntryType PROGMEM LogModeMap[] = { + { .Id = LOG_MODE_OFF, .Text = "OFF" }, + { .Id = LOG_MODE_MEMORY, .Text = "MEMORY" }, + { .Id = LOG_MODE_LIVE, .Text = "LIVE" } +}; + +static void LogFuncOff(LogEntryEnum Entry, const void* Data, uint8_t Length) +{ + /* Do nothing */ +} + +static void LogFuncMemory(LogEntryEnum Entry, const void* Data, uint8_t Length) +{ + uint16_t SysTick = SystemGetSysTick(); + + if (LogMemLeft >= (Length + 4)) { + LogMemLeft -= Length + 4; + + uint8_t* DataPtr = (uint8_t*) Data; + + /* Write down Entry Id, Data length and Timestamp */ + *LogMemPtr++ = (uint8_t) Entry; + *LogMemPtr++ = (uint8_t) Length; + *LogMemPtr++ = (uint8_t) (SysTick >> 8); + *LogMemPtr++ = (uint8_t) (SysTick >> 0); + + /* Write down data bytes */ + while(Length--) { + *LogMemPtr++ = *DataPtr++; + } + } else { + /* If memory full. Deactivate logmode */ + LogSetModeById(LOG_MODE_OFF); + LEDHook(LED_LOG_MEM_FULL, LED_ON); + } +} + +static void LogFuncLive(LogEntryEnum Entry, const void* Data, uint8_t Length) +{ + uint16_t SysTick = SystemGetSysTick(); + + TerminalSendByte((uint8_t) Entry); + TerminalSendByte((uint8_t) Length); + TerminalSendByte((uint8_t) (SysTick >> 8)); + TerminalSendByte((uint8_t) (SysTick >> 0)); + TerminalSendBlock(Data, Length); +} + +void LogInit(void) +{ + LogMemClear(); + LogSetModeById(GlobalSettings.ActiveSettingPtr->LogMode); +} + +void LogTick(void) +{ + +} + +void LogTask(void) +{ + +} + +bool LogMemLoadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount) +{ + if (BlockAddress < sizeof(LogMem) + (LogFRAMAddr - FRAM_LOG_START_ADDR)) + { + bool overflow = false; + uint16_t remainderByteCount = 0; + // prevent buffer overflows: + if ((BlockAddress + ByteCount) >= sizeof(LogMem) + (LogFRAMAddr - FRAM_LOG_START_ADDR)) + { + overflow = true; + uint16_t tmp = sizeof(LogMem) + (LogFRAMAddr - FRAM_LOG_START_ADDR) - BlockAddress; + remainderByteCount = ByteCount - tmp; + ByteCount = tmp; + } + + /* + * 1. case: The whole block is in FRAM. + * 2. case: The block wraps from FRAM to SRAM + * 3. case: The whole block is in SRAM. + */ + if (BlockAddress < (LogFRAMAddr - FRAM_LOG_START_ADDR) && (BlockAddress + ByteCount) < (LogFRAMAddr - FRAM_LOG_START_ADDR)) + { + MemoryReadBlock(Buffer, BlockAddress + FRAM_LOG_START_ADDR, ByteCount); + } else if (BlockAddress < (LogFRAMAddr - FRAM_LOG_START_ADDR)) { + uint16_t FramByteCount = LogFRAMAddr - (BlockAddress + FRAM_LOG_START_ADDR); + MemoryReadBlock(Buffer, BlockAddress + FRAM_LOG_START_ADDR, FramByteCount); + memcpy(Buffer + FramByteCount, LogMem, ByteCount - FramByteCount); + } else { + memcpy(Buffer, LogMem + BlockAddress - LogFRAMAddr, ByteCount); + } + + if (overflow) + { + while (remainderByteCount--) + ((uint8_t*) Buffer)[ByteCount + remainderByteCount] = 0x00; + } + + return true; + } else { + return false; + } +} + +void LogMemClear(void) +{ + uint16_t i; + + for (i=0; iLogMode = Mode; +#else + /* Write Log settings globally */ + for (uint8_t i=0; iLogMode, Mode, BufferSize); +} + +void LogGetModeList(char* List, uint16_t BufferSize) +{ + MapToString(LogModeMap, sizeof(LogModeMap)/sizeof(*LogModeMap), List, BufferSize); +} + +void LogSRAMToFRAM(void) +{ + if (LogMemLeft < sizeof(LogMem)) + { + if (FRAM_LOG_SIZE - (LogFRAMAddr - FRAM_LOG_START_ADDR) >= LOG_SIZE - LogMemLeft) + { + MemoryWriteBlock(LogMem, LogFRAMAddr, LOG_SIZE - LogMemLeft); + uint16_t tmp = LogFRAMAddr + (LOG_SIZE - LogMemLeft); + LogMemClear(); // this function also resets LogFRAMAddr, but does not delete anything from FRAM, so we just save the new FRAM address + LogFRAMAddr = tmp; + } else { + // TODO handle the case in which the FRAM is full + } + } +} diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h new file mode 100644 index 00000000..5b3f7769 --- /dev/null +++ b/Firmware/Chameleon-Mini/Log.h @@ -0,0 +1,70 @@ +#ifndef LOG_H_ +#define LOG_H_ +/** @file */ +#include "Common.h" + +#define LOG_SIZE 2048 +#define FRAM_LOG_START_ADDR 0x4000 // from the start of the second half of FRAM +#define FRAM_LOG_SIZE 0x4000 // the whole second half + +/** Enum for log entry type. \note Every entry type has a specific integer value, which can be found in the source code. */ +typedef enum { + /* Generic */ + LOG_INFO_GENERIC = 0x10, ///< Unspecific log entry. + LOG_INFO_CONFIG_SET = 0x11, ///< Configuration change. + LOG_INFO_SETTING_SET = 0x12, ///< Setting change. + LOG_INFO_UID_SET = 0x13, ///< UID change. + LOG_INFO_RESET_APP = 0x20, ///< Application reset. + + /* Codec */ + LOG_INFO_CODEC_RX_DATA = 0x40, ///< Currently active codec received data. + LOG_INFO_CODEC_TX_DATA = 0x41, ///< Currently active codec sent data. + + /* App */ + LOG_INFO_APP_CMD_READ = 0x80, ///< Application processed read command. + LOG_INFO_APP_CMD_WRITE = 0x81, ///< Application processed write command. + LOG_INFO_APP_CMD_INC = 0x84, ///< Application processed increment command. + LOG_INFO_APP_CMD_DEC = 0x85, ///< Application processed decrement command. + LOG_INFO_APP_CMD_TRANSFER = 0x86, ///< Application processed transfer command. + LOG_INFO_APP_CMD_RESTORE = 0x87, ///< Application processed restore command. + LOG_INFO_APP_CMD_AUTH = 0x90, ///< Application processed authentication command. + LOG_INFO_APP_CMD_HALT = 0x91, ///< Application processed halt command. + LOG_INFO_APP_CMD_UNKNOWN = 0x92, ///< Application processed an unknown command. + LOG_INFO_APP_AUTHING = 0xA0, ///< Application is in `authing` state. + LOG_INFO_APP_AUTHED = 0xA1, ///< Application is in `auth` state. + LOG_ERR_APP_AUTH_FAIL = 0xC0, ///< Application authentication failed. + LOG_ERR_APP_CHECKSUM_FAIL = 0xC1, ///< Application had a checksum fail. + LOG_ERR_APP_NOT_AUTHED = 0xC2, ///< Application is not authenticated. + + LOG_EMPTY = 0x00 ///< Empty Log Entry. This is not followed by a length byte nor the two systick bytes nor any data. +} LogEntryEnum; + +typedef enum { + LOG_MODE_OFF, + LOG_MODE_MEMORY, + LOG_MODE_LIVE +} LogModeEnum; + +typedef void (*LogFuncType) (LogEntryEnum Entry, const void* Data, uint8_t Length); + +extern LogFuncType CurrentLogFunc; + +void LogInit(void); +void LogTick(void); +void LogTask(void); + +void LogMemClear(void); +uint16_t LogMemFree(void); +/* XModem callback */ +bool LogMemLoadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount); + +void LogSetModeById(LogModeEnum Mode); +bool LogSetModeByName(const char* Mode); +void LogGetModeByName(char* Mode, uint16_t BufferSize); +void LogGetModeList(char* List, uint16_t BufferSize); +void LogSRAMToFRAM(void); + +/* Wrapper function to call current logging function */ +INLINE void LogEntry(LogEntryEnum Entry, const void* Data, uint8_t Length) { CurrentLogFunc(Entry, Data, Length); } + +#endif /* LOG_H_ */ diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile new file mode 100644 index 00000000..fb6337df --- /dev/null +++ b/Firmware/Chameleon-Mini/Makefile @@ -0,0 +1,148 @@ +# This makefile uses sh in order to build the project. +# Note when using AVR-Toolchain, you have to install cygwin and +# append cygwin's bin directory to the PATH environment variable +# because Atmel does not ship sh.exe anymore with the toolchain. +SHELL = /bin/sh + +#Supported configurations +SETTINGS += -DCONFIG_MF_CLASSIC_1K_SUPPORT +SETTINGS += -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT +SETTINGS += -DCONFIG_MF_CLASSIC_4K_SUPPORT +SETTINGS += -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT +SETTINGS += -DCONFIG_MF_ULTRALIGHT_SUPPORT +SETTINGS += -DCONFIG_ISO14443A_SNIFF_SUPPORT +SETTINGS += -DCONFIG_ISO14443A_READER_SUPPORT + +#Support magic mode on mifare classic configuration +SETTINGS += -DSUPPORT_MF_CLASSIC_MAGIC_MODE + +#Support activating firmware upgrade mode through command-line +SETTINGS += -DSUPPORT_FIRMWARE_UPGRADE + +#Default configuration +#SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_1K +#SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_4K +#SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_ULTRALIGHT +SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_NONE +#SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_ISO14443A_READER + +#Default button actions +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RANDOM +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_LEFT_INCREMENT +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RIGHT_INCREMENT +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_LEFT_DECREMENT +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RIGHT_DECREMENT +SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_CYCLE_SETTINGS +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_STORE_MEM +SETTINGS += -DDEFAULT_LBUTTON_ACTION=BUTTON_ACTION_RECALL_MEM + +#Define if button action setting should be independent of active setting +SETTINGS += -DBUTTON_SETTING_GLOBAL + +#Default LED functions +SETTINGS += -DDEFAULT_RED_LED_ACTION=LED_SETTING_CHANGE +SETTINGS += -DDEFAULT_GREEN_LED_ACTION=LED_POWERED + +#Define if LED function setting should be independent of active setting +SETTINGS += -DLED_SETTING_GLOBAL + +#Default logging mode +SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_OFF +#SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_MEMORY +#SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_TERMINAL + +#Define if log settings should be global +SETTINGS += -DLOG_SETTING_GLOBAL + +#Default setting +SETTINGS += -DDEFAULT_SETTING=SETTINGS_FIRST + +#Default pending task timeout +SETTINGS += -DDEFAULT_PENDING_TASK_TIMEOUT=10 #* 100ms + + +#Use EEPROM to store settings +SETTINGS += -DENABLE_EEPROM_SETTINGS + +#Memory definitions and objcopy flags to include sections in binaries +FLASH_DATA_ADDR = 0x10000 #Start of data section in flash +FLASH_DATA_SIZE = 0x10000 #Size of data section in flash +FLASH_DATA_OBJCOPY = --set-section-flags=.flashdata="alloc,load" +SPM_HELPER_ADDR = 0x21FE0 #Start of SPM helper section. Should be last 32Byte in bootloader section +SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" + +#Build configuration +BUILD_DATE = $(shell date +'\"%y%m%d\"') +COMMIT_ID = $(shell git rev-parse --short HEAD) +MCU = atxmega128a4u +ARCH = XMEGA +BOARD = NONE +F_CPU = 27120000 +F_USB = 48000000 +TARGET = Chameleon-Mini +OPTIMIZATION = s +SRC += $(TARGET).c LUFADescriptors.c System.c Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c +SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Terminal/CommandLine.c +SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c +SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c +SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) +LUFA_PATH = ../LUFA +CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -DFLASH_DATA_SIZE=$(FLASH_DATA_SIZE) -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) -DBUILD_DATE=$(BUILD_DATE) -DCOMMIT_ID=\"$(COMMIT_ID)\" $(SETTINGS) +LD_FLAGS = -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) +OBJDIR = Bin +OBJECT_FILES = + + +#AVRDUDE settings +AVRDUDE_PROGRAMMER = flip2 +AVRDUDE_MCU = atxmega128a4u +AVRDUDE_PORT = usb +AVRDUDE_WRITE_APP = -U application:w:$(TARGET).hex +AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep +AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) + +# Default target +all: + +# Include LUFA build script makefiles +include $(LUFA_PATH)/Build/lufa_core.mk +include $(LUFA_PATH)/Build/lufa_sources.mk +include $(LUFA_PATH)/Build/lufa_build.mk +include $(LUFA_PATH)/Build/lufa_cppcheck.mk +# include $(LUFA_PATH)/Build/lufa_doxygen.mk +# include $(LUFA_PATH)/Build/lufa_dfu.mk +# include $(LUFA_PATH)/Build/lufa_hid.mk +# include $(LUFA_PATH)/Build/lufa_avrdude.mk +# include $(LUFA_PATH)/Build/lufa_atprogram.mk + +#Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections +%.hex: %.elf + @echo $(MSG_OBJCPY_CMD) Extracting HEX file data from \"$<\" + $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ + +%.bin: %.elf + @echo $(MSG_OBJCPY_CMD) Extracting BIN file data from \"$<\" + $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ + +# Extract SPMHelper in the last 32 Byte of the bootloader section to externally combine it with any bootloader +spmhelper: $(TARGET).elf + @echo $(MSG_OBJCPY_CMD) Extracting SPM helper HEX file from $(TARGET).elf + $(CROSS)-objcopy -O ihex -j .spmhelper $(SPM_HELPER_OBJCOPY) $(TARGET).elf $(TARGET).hex + +# Program the device using avrdude +program: $(TARGET).hex $(TARGET).eep + avrdude $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_APP) $(AVRDUDE_WRITE_EEPROM) + +# Program the device using batchisp and the DFU bootloader +# Note that the device has to be in bootloader mode already +dfu-flip: $(TARGET).hex $(TARGET).eep + cp $(TARGET).eep EEPROM.hex + batchisp -hardware usb -device $(MCU) -operation erase f memory FLASH loadbuffer $(TARGET).hex program verify memory EEPROM loadbuffer EEPROM.hex program verify start reset 0 + rm EEPROM.hex + +# Program the device using dfu-programmer +dfu-prog: $(TARGET).hex $(TARGET).eep + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) flash-eeprom $(TARGET).eep + dfu-programmer $(MCU) flash $(TARGET).hex + dfu-programmer $(MCU) reset diff --git a/Firmware/Chameleon-Mini/Map.c b/Firmware/Chameleon-Mini/Map.c new file mode 100644 index 00000000..b6011d45 --- /dev/null +++ b/Firmware/Chameleon-Mini/Map.c @@ -0,0 +1,72 @@ +#include "Map.h" + +bool MapIdToText(const MapEntryType* MapPtr, uint8_t MapSize, MapIdType Id, char* Text, uint16_t MaxBufferSize) +{ + while (MapSize--) { + if (pgm_read_byte(&MapPtr->Id) == Id) { + strncpy_P(Text, MapPtr->Text, MaxBufferSize); + return true; + } + + MapPtr++; + } + + return false; +} + +bool MapTextToId(const MapEntryType* MapPtr, uint8_t MapSize, MapTextPtrType Text, MapIdType* IdPtr) +{ + while (MapSize--) { + if (strcmp_P(Text, MapPtr->Text) == 0) { + if (sizeof(MapIdType) == 1) { + *IdPtr = pgm_read_byte(&MapPtr->Id); + } else if (sizeof(MapIdType) == 2) { + *IdPtr = pgm_read_word(&MapPtr->Id); + } + return true; + } + + MapPtr++; + } + + return false; +} + +void MapToString(MapEntryType* MapPtr, uint8_t MapSize, char* String, uint16_t MaxBufferSize) +{ + uint8_t EntriesLeft = MapSize; + uint16_t BytesLeft = MaxBufferSize; + + while (EntriesLeft > 0) { + const char* Text = MapPtr->Text; + char c; + + while( (c = pgm_read_byte(Text)) != '\0') { + if (BytesLeft == 0) { + return; + } + + *String++ = c; + Text++; + BytesLeft--; + } + + if (EntriesLeft > 1) { + /* More than one map entries left */ + if (BytesLeft == 0) { + return; + } + + *String++ = ','; + } + + MapPtr++; + EntriesLeft--; + } + + /* Terminate string */ + if (BytesLeft > 0) { + *String++ = '\0'; + BytesLeft--; + } +} diff --git a/Firmware/Chameleon-Mini/Map.h b/Firmware/Chameleon-Mini/Map.h new file mode 100644 index 00000000..71802801 --- /dev/null +++ b/Firmware/Chameleon-Mini/Map.h @@ -0,0 +1,30 @@ +/* + * Map.h + * + * Created on: 07.12.2014 + * Author: sk + */ + +#ifndef MAP_H_ +#define MAP_H_ + +#include +#include +#include + +#define MAP_TEXT_BUF_SIZE 32 +#define MAP_MAX_TEXT_SIZE (MAP_TEXT_BUF_SIZE - 1) + +typedef uint8_t MapIdType; +typedef const char* MapTextPtrType; + +const typedef struct { + MapIdType Id; + const char Text[MAP_TEXT_BUF_SIZE]; +} MapEntryType; + +bool MapIdToText(const MapEntryType* MapPtr, uint8_t MapSize, MapIdType Id, char* Text, uint16_t MaxBufferSize); +bool MapTextToId(const MapEntryType* MapPtr, uint8_t MapSize, MapTextPtrType Text, MapIdType* IdPtr); +void MapToString(const MapEntryType* MapPtr, uint8_t MapSize, char* String, uint16_t MaxBufferSize); + +#endif /* MAP_H_ */ diff --git a/Firmware/Chameleon-Mini/Memory.c b/Firmware/Chameleon-Mini/Memory.c new file mode 100644 index 00000000..c8853979 --- /dev/null +++ b/Firmware/Chameleon-Mini/Memory.c @@ -0,0 +1,442 @@ +/* + * Flash.c + * + * Created on: 20.03.2013 + * Author: skuser + */ + +#include "Memory.h" +#include "Configuration.h" +#include "Common.h" +#include "Settings.h" +#include "LEDHook.h" + +#define USE_DMA +#define RECV_DMA DMA.CH0 +#define SEND_DMA DMA.CH1 + +/* Convert defines from Makefile */ +#define FLASH_DATA_START FLASH_DATA_ADDR +#define FLASH_DATA_END (FLASH_DATA_ADDR + FLASH_DATA_SIZE - 1) + +/* Definitions for FRAM */ +#define FRAM_USART USARTD0 +#define FRAM_PORT PORTD +#define FRAM_CS PIN4_bm +#define FRAM_MOSI PIN3_bm +#define FRAM_MISO PIN2_bm +#define FRAM_SCK PIN1_bm + +/* Declarations from assembler file */ +uint16_t FlashReadWord(uint32_t Address); +void FlashEraseApplicationPage(uint32_t Address); +void FlashLoadFlashWord(uint16_t Address, uint16_t Data); +void FlashEraseWriteApplicationPage(uint32_t Address); +void FlashEraseFlashBuffer(void); +void FlashWaitForSPM(void); + +static uint8_t ScrapBuffer[] = {0}; + +INLINE uint8_t SPITransferByte(uint8_t Data) +{ + FRAM_USART.DATA = Data; + + while (!(FRAM_USART.STATUS & USART_RXCIF_bm)); + + return FRAM_USART.DATA; +} + +#ifdef USE_DMA +INLINE void SPIReadBlock(void* Buffer, uint16_t ByteCount) +{ + /* Set up read and write transfers */ + RECV_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_INC_gc; + RECV_DMA.DESTADDR0 = ((uintptr_t) Buffer >> 0) & 0xFF; + RECV_DMA.DESTADDR1 = ((uintptr_t) Buffer >> 8) & 0xFF; + RECV_DMA.TRFCNT = ByteCount; + SEND_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc; + SEND_DMA.SRCADDR0 = ((uintptr_t) ScrapBuffer >> 0) & 0xFF; + SEND_DMA.SRCADDR1 = ((uintptr_t) ScrapBuffer >> 8) & 0xFF; + SEND_DMA.TRFCNT = ByteCount; + + + /* Enable read and write transfers */ + RECV_DMA.CTRLA |= DMA_CH_ENABLE_bm; + SEND_DMA.CTRLA |= DMA_CH_ENABLE_bm; + + /* Wait for DMA to finish */ + while( RECV_DMA.CTRLA & DMA_CH_ENABLE_bm ) + ; + + /* Clear Interrupt flag */ + RECV_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm; + SEND_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm; +} +#else +INLINE void SPIReadBlock(void* Buffer, uint16_t ByteCount) +{ + uint8_t* ByteBuffer = (uint8_t*) Buffer; + + while(ByteCount-- > 0) { + FRAM_USART.DATA = 0; + while (!(FRAM_USART.STATUS & USART_RXCIF_bm)); + + *ByteBuffer++ = FRAM_USART.DATA; + } +} + +#endif + +#ifdef USE_DMA +INLINE void SPIWriteBlock(const void* Buffer, uint16_t ByteCount) +{ + /* Set up read and write transfers */ + RECV_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc; + RECV_DMA.DESTADDR0 = ((uintptr_t) ScrapBuffer >> 0) & 0xFF; + RECV_DMA.DESTADDR1 = ((uintptr_t) ScrapBuffer >> 8) & 0xFF; + RECV_DMA.TRFCNT = ByteCount; + SEND_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc; + SEND_DMA.SRCADDR0 = ((uintptr_t) Buffer >> 0) & 0xFF; + SEND_DMA.SRCADDR1 = ((uintptr_t) Buffer >> 8) & 0xFF; + SEND_DMA.TRFCNT = ByteCount; + + /* Enable read and write transfers */ + RECV_DMA.CTRLA |= DMA_CH_ENABLE_bm; + SEND_DMA.CTRLA |= DMA_CH_ENABLE_bm; + + /* Wait for DMA to finish */ + while( RECV_DMA.CTRLA & DMA_CH_ENABLE_bm ) + ; + + /* Clear Interrupt flag */ + RECV_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm; + SEND_DMA.CTRLB = DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm; +} +#else +INLINE void SPIWriteBlock(const void* Buffer, uint16_t ByteCount) +{ + uint8_t* ByteBuffer = (uint8_t*) Buffer; + + while(ByteCount-- > 0) { + FRAM_USART.DATA = *ByteBuffer++; + while (!(FRAM_USART.STATUS & USART_RXCIF_bm)); + + FRAM_USART.DATA; /* Flush Buffer */ + } +} +#endif + +INLINE void FRAMRead(void* Buffer, uint16_t Address, uint16_t ByteCount) +{ + FRAM_PORT.OUTCLR = FRAM_CS; + + SPITransferByte(0x03); /* Read command */ + SPITransferByte( (Address >> 8) & 0xFF ); /* Address hi and lo byte */ + SPITransferByte( (Address >> 0) & 0xFF ); + + SPIReadBlock(Buffer, ByteCount); + + FRAM_PORT.OUTSET = FRAM_CS; +} + +INLINE void FRAMWrite(const void* Buffer, uint16_t Address, uint16_t ByteCount) +{ + FRAM_PORT.OUTCLR = FRAM_CS; + SPITransferByte(0x06); /* Write Enable */ + FRAM_PORT.OUTSET = FRAM_CS; + + asm volatile ("nop"); + asm volatile ("nop"); + + FRAM_PORT.OUTCLR = FRAM_CS; + + SPITransferByte(0x02); /* Write command */ + SPITransferByte( (Address >> 8) & 0xFF ); /* Address hi and lo byte */ + SPITransferByte( (Address >> 0) & 0xFF ); + + SPIWriteBlock(Buffer, ByteCount); + + FRAM_PORT.OUTSET = FRAM_CS; +} + +INLINE void FlashRead(void* Buffer, uint32_t Address, uint16_t ByteCount) +{ + uint8_t* BufPtr = (uint8_t*) Buffer; + + /* We assume that ByteCount is a multiple of 2 */ + uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR; + + if ( (PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END) ) { + /* Sanity check to limit access to the allocated area */ + while(ByteCount > 1) { + uint16_t Word = FlashReadWord(PhysicalAddress); + + *BufPtr++ = (Word >> 0) & 0xFF; + *BufPtr++ = (Word >> 8) & 0xFF; + + PhysicalAddress += 2; + ByteCount -= 2; + } + } +} + +INLINE void FlashWrite(const void* Buffer, uint32_t Address, uint16_t ByteCount) +{ + const uint8_t* BufPtr = (uint8_t*) Buffer; + + /* We assume that FlashWrite is always called for write actions that are + * aligned to APP_SECTION_PAGE_SIZE and a multiple of APP_SECTION_PAGE_SIZE. + * Thus only full pages are written into the flash. */ + uint16_t PageCount = ByteCount / APP_SECTION_PAGE_SIZE; + uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR; + + if ( (PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END) ) { + /* Sanity check to limit access to the allocated area */ + + while(PageCount-- > 0) { + /* For each page to program, wait for NVM to get ready, + * erase the flash page buffer, program all data to the + * flash page buffer and write buffer to flash using + * the atomic erase and write operation. */ + + FlashWaitForSPM(); + + FlashEraseFlashBuffer(); + FlashWaitForSPM(); + + for (uint16_t i=0; i= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END) ) { + /* Sanity check to limit access to the allocated area */ + while(PageCount-- > 0) { + FlashWaitForSPM(); + + FlashEraseApplicationPage(PhysicalAddress); + FlashWaitForSPM(); + + PhysicalAddress += APP_SECTION_PAGE_SIZE; + } + } +} + +INLINE void FlashToFRAM(uint32_t Address, uint16_t ByteCount) +{ + /* We assume that ByteCount is a multiple of 2 */ + uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR; + + if ( (PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END) ) { + /* Sanity check to limit access to the allocated area. + * Set up FRAM memory for writing. */ + FRAM_PORT.OUTCLR = FRAM_CS; + SPITransferByte(0x06); /* Write Enable */ + FRAM_PORT.OUTSET = FRAM_CS; + + asm volatile ("nop"); + asm volatile ("nop"); + + FRAM_PORT.OUTCLR = FRAM_CS; + + SPITransferByte(0x02); /* Write command */ + SPITransferByte(0); /* Address hi and lo byte */ + SPITransferByte(0); + + /* Loop through bytes, read words from flash and write + * double byte into FRAM. */ + while(ByteCount > 1) { + uint16_t Word = FlashReadWord(PhysicalAddress); + + SPITransferByte( (Word >> 0) & 0xFF ); + SPITransferByte( (Word >> 8) & 0xFF ); + + PhysicalAddress += 2; + ByteCount -= 2; + } + + /* End write procedure of FRAM */ + FRAM_PORT.OUTSET = FRAM_CS; + } +} + +INLINE void FRAMToFlash(uint32_t Address, uint16_t ByteCount) +{ + /* We assume that FlashWrite is always called for write actions that are + * aligned to APP_SECTION_PAGE_SIZE and a multiple of APP_SECTION_PAGE_SIZE. + * Thus only full pages are written into the flash. */ + uint16_t PageCount = ByteCount / APP_SECTION_PAGE_SIZE; + uint32_t PhysicalAddress = Address + FLASH_DATA_ADDR; + + if ( (PhysicalAddress >= FLASH_DATA_START) && (PhysicalAddress <= FLASH_DATA_END) ) { + /* Sanity check to limit access to the allocated area and setup FRAM + * read. */ + FRAM_PORT.OUTCLR = FRAM_CS; + + SPITransferByte(0x03); /* Read command */ + SPITransferByte(0); /* Address hi and lo byte */ + SPITransferByte(0); + + while(PageCount-- > 0) { + /* For each page to program, wait for NVM to get ready, + * erase the flash page buffer, program all data to the + * flash page buffer and write buffer to flash using + * the atomic erase and write operation. */ + + FlashWaitForSPM(); + + FlashEraseFlashBuffer(); + FlashWaitForSPM(); + + /* Write one page worth of data into flash buffer */ + for (uint16_t i=0; i> 0) & 0xFF; + RECV_DMA.SRCADDR1 = ((uintptr_t) &FRAM_USART.DATA >> 8) & 0xFF; + RECV_DMA.SRCADDR2 = 0; + RECV_DMA.DESTADDR0 = 0; + RECV_DMA.DESTADDR1 = 0; + RECV_DMA.DESTADDR2 = 0; + RECV_DMA.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_1BYTE_gc; + + SEND_DMA.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc | DMA_CH_SRCDIR_FIXED_gc | DMA_CH_DESTRELOAD_NONE_gc | DMA_CH_DESTDIR_FIXED_gc; + SEND_DMA.TRIGSRC = DMA_CH_TRIGSRC_USARTD0_DRE_gc; + SEND_DMA.TRFCNT = 0; + SEND_DMA.SRCADDR0 = 0; + SEND_DMA.SRCADDR1 = 0; + SEND_DMA.SRCADDR2 = 0; + SEND_DMA.DESTADDR0 = ((uintptr_t) &FRAM_USART.DATA >> 0) & 0xFF; + SEND_DMA.DESTADDR1 = ((uintptr_t) &FRAM_USART.DATA >> 8) & 0xFF; + SEND_DMA.DESTADDR2 = 0; + SEND_DMA.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_1BYTE_gc; +} + +void MemoryReadBlock(void* Buffer, uint16_t Address, uint16_t ByteCount) +{ + if (ByteCount == 0) + return; + FRAMRead(Buffer, Address, ByteCount); +} + +void MemoryWriteBlock(const void* Buffer, uint16_t Address, uint16_t ByteCount) +{ + if (ByteCount == 0) + return; + FRAMWrite(Buffer, Address, ByteCount); + + LEDHook(LED_MEMORY_CHANGED, LED_ON); +} + +void MemoryClear(void) +{ + FlashErase((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING); + + MemoryRecall(); +} + +void MemoryRecall(void) +{ + /* Recall memory from permanent flash */ + FlashToFRAM((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING); +} + +void MemoryStore(void) +{ + /* Store current memory into permanent flash */ + FRAMToFlash((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING); + + LEDHook(LED_MEMORY_CHANGED, LED_OFF); + LEDHook(LED_MEMORY_STORED, LED_PULSE); +} + +bool MemoryUploadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount) +{ + if (BlockAddress >= MEMORY_SIZE_PER_SETTING) { + /* Prevent writing out of bounds by silently ignoring it */ + return true; + } else { + /* Calculate bytes left in memory and start writing */ + uint32_t BytesLeft = MEMORY_SIZE_PER_SETTING - BlockAddress; + ByteCount = MIN(ByteCount, BytesLeft); + + /* Store to local memory */ + FRAMWrite(Buffer, BlockAddress, ByteCount); + + return true; + } +} + +bool MemoryDownloadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount) +{ + if (BlockAddress >= MEMORY_SIZE_PER_SETTING) { + /* There are bytes out of bounds to be read. Notify that we are done. */ + return false; + } else { + /* Calculate bytes left in memory and issue reading */ + uint32_t BytesLeft = MEMORY_SIZE_PER_SETTING - BlockAddress; + ByteCount = MIN(ByteCount, BytesLeft); + + /* Output local memory contents */ + FRAMRead(Buffer, BlockAddress, ByteCount); + + return true; + } +} + diff --git a/Firmware/Chameleon-Mini/Memory.h b/Firmware/Chameleon-Mini/Memory.h new file mode 100644 index 00000000..a10bb175 --- /dev/null +++ b/Firmware/Chameleon-Mini/Memory.h @@ -0,0 +1,33 @@ +/* + * Flash.h + * + * Created on: 20.03.2013 + * Author: skuser + */ + +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#define MEMORY_SIZE (FLASH_DATA_SIZE) /* From makefile */ +#define MEMORY_INIT_VALUE 0x00 +#define MEMORY_SIZE_PER_SETTING 8192 + +#ifndef __ASSEMBLER__ +#include "Common.h" + +void MemoryInit(void); +void MemoryReadBlock(void* Buffer, uint16_t Address, uint16_t ByteCount); +void MemoryWriteBlock(const void* Buffer, uint16_t Address, uint16_t ByteCount); +void MemoryClear(void); + + +void MemoryRecall(void); +void MemoryStore(void); + +/* For use with XModem */ +bool MemoryUploadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount); +bool MemoryDownloadBlock(void* Buffer, uint32_t BlockAddress, uint16_t ByteCount); + +#endif /* __ASSEMBLER__ */ + +#endif /* MEMORY_H_ */ diff --git a/Firmware/Chameleon-Mini/MemoryAsm.S b/Firmware/Chameleon-Mini/MemoryAsm.S new file mode 100644 index 00000000..efb33740 --- /dev/null +++ b/Firmware/Chameleon-Mini/MemoryAsm.S @@ -0,0 +1,225 @@ +#include +#include "Memory.h" + +#define NVM_CMD_NO_OPERATION_gc (0x00<<0) +#define NVM_CMD_READ_USER_SIG_ROW_gc (0x01<<0) +#define NVM_CMD_READ_CALIB_ROW_gc (0x02<<0) +#define NVM_CMD_READ_EEPROM_gc (0x06<<0) +#define NVM_CMD_READ_FUSES_gc (0x07<<0) +#define NVM_CMD_WRITE_LOCK_BITS_gc (0x08<<0) +#define NVM_CMD_ERASE_USER_SIG_ROW_gc (0x18<<0) +#define NVM_CMD_WRITE_USER_SIG_ROW_gc (0x1A<<0) +#define NVM_CMD_ERASE_APP_gc (0x20<<0) +#define NVM_CMD_ERASE_APP_PAGE_gc (0x22<<0) +#define NVM_CMD_LOAD_FLASH_BUFFER_gc (0x23<<0) +#define NVM_CMD_WRITE_APP_PAGE_gc (0x24<<0) +#define NVM_CMD_ERASE_WRITE_APP_PAGE_gc (0x25<<0) +#define NVM_CMD_ERASE_FLASH_BUFFER_gc (0x26<<0) +#define NVM_CMD_ERASE_BOOT_PAGE_gc (0x2A<<0) +#define NVM_CMD_WRITE_BOOT_PAGE_gc (0x2C<<0) +#define NVM_CMD_ERASE_WRITE_BOOT_PAGE_gc (0x2D<<0) +#define NVM_CMD_ERASE_EEPROM_gc (0x30<<0) +#define NVM_CMD_ERASE_EEPROM_PAGE_gc (0x32<<0) +#define NVM_CMD_LOAD_EEPROM_BUFFER_gc (0x33<<0) +#define NVM_CMD_WRITE_EEPROM_PAGE_gc (0x34<<0) +#define NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc (0x35<<0) +#define NVM_CMD_ERASE_EEPROM_BUFFER_gc (0x36<<0) +#define NVM_CMD_APP_CRC_gc (0x38<<0) +#define NVM_CMD_BOOT_CRC_gc (0x39<<0) +#define NVM_CMD_FLASH_RANGE_CRC_gc (0x3A<<0) +#define CCP_SPM_gc (0x9D<<0) +#define CCP_IOREG_gc (0xD8<<0) + +/* FlashCommonSPM needs to reside in boot loader section */ +#define SPM_HELPER_ADDR_REF (BOOT_SECTION_START + BOOT_SECTION_SIZE - 32) +#ifdef SPM_HELPER_ADDR +/* If enabled by makefile, we can check the hardcoded address from makefile + * against avr/io.h and generate an error on mismatch */ +#if ((SPM_HELPER_ADDR - SPM_HELPER_ADDR_REF) != 0) +#error SPM helper function addresses from Makefile and avr/io.h do not match! +#endif +#endif + +/* The following assembly code is taken from Atmels sp_driver.S in AVR1316 */ + +; This routine reads a word from flash given by the address in +; R25:R24:R23:R22. +; +; Input: +; R25:R24:R23:R22. +; +; Returns: +; R25:R24 - Read word. +.section .text +.global FlashReadWord +FlashReadWord: + in r19, RAMPZ ; Save RAMPZ. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw ZL, r22 ; Move the low bytes to the Z pointer + elpm r24, Z+ ; Extended load byte from address pointed to by Z. + elpm r25, Z ; Extended load byte from address pointed to by Z. + out RAMPZ, r19 ; Restore RAMPZ register. + ret + +; This routine erases the page at address R25:R24:R23:R22 in the application +; section. The address can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +.section .text +.global FlashEraseApplicationPage +FlashEraseApplicationPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in FlashCommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes for ZH:ZL to R25:R24 + ldi r20, NVM_CMD_ERASE_APP_PAGE_gc ; Prepare NVM command in R20. + jmp FlashCommonSPM ; Jump to common SPM code. + +; This routine writes the word from R23:R22 into the Flash page buffer at +; address R25:R24. +; +; Input: +; R25:R24 - Byte address into Flash page. +; R23:R22 - Word to write. +; +; Returns: +; Nothing. +.section .text +.global FlashLoadFlashWord +FlashLoadFlashWord: + in r19, RAMPZ ; Save RAMPZ, which is restored in FlashCommonSPM. + movw r0, r22 ; Prepare flash word in R1:R0. + ldi r20, NVM_CMD_LOAD_FLASH_BUFFER_gc ; Prepare NVM command in R20. + jmp FlashCommonSPM ; Jump to common SPM code. + + +; This routine erases first and then writes the page buffer to the +; Flash page at address R25:R24:R23:R22 in the application section. The address +; can point anywhere inside the page. +; +; Input: +; R25:R24:R23:R22 - Byte address into Flash page. +; +; Returns: +; Nothing. +.section .text +.global FlashEraseWriteApplicationPage +FlashEraseWriteApplicationPage: + in r19, RAMPZ ; Save RAMPZ, which is restored in FlashCommonSPM. + out RAMPZ, r24 ; Load RAMPZ with the MSB of the address. + movw r24, r22 ; Move low bytes of address to ZH:ZL from R23:R22 + ldi r20, NVM_CMD_ERASE_WRITE_APP_PAGE_gc ; Prepare NVM command in R20. + jmp FlashCommonSPM ; Jump to common SPM code. + +; This routine flushes the Flash page buffer. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +.section .text +.global FlashEraseFlashBuffer +FlashEraseFlashBuffer: + in r19, RAMPZ ; Save RAMPZ, which is restored in FlashCommonSPM. + ldi r20, NVM_CMD_ERASE_FLASH_BUFFER_gc ; Prepare NVM command in R20. + ;jmp FlashCommonSPM ; Jump to common SPM code. + jmp FlashCommonCMD + +; This routine wait for the SPM to finish and clears the command register. +; +; Note that this routine is blocking, and will halt any execution until the SPM +; is finished. +; +; Input: +; Nothing. +; +; Returns: +; Nothing. +.section .text +.global FlashWaitForSPM +FlashWaitForSPM: + lds r18, NVM_STATUS ; Load the NVM Status register. + sbrc r18, NVM_NVMBUSY_bp ; Check if bit is cleared. + rjmp FlashWaitForSPM ; Repeat check if bit is not cleared. + clr r18 + sts NVM_CMD, r18 ; Clear up command register to NO_OPERATION. + ret + +; This routine is called by several other routines, and contains common code +; for executing an NVM command, including the return statement itself. +; +; If the operation (NVM command) requires the NVM Address registers to be +; prepared, this must be done before jumping to this routine. +; +; Note that R25:R24:R23:R22 is used for returning results, even if the +; C-domain calling function only expects a single byte or even void. +; +; Input: +; R20 - NVM Command code. +; +; Returns: +; R25:R24:R23:R22 - 32-bit result from NVM operation. +.section .text +FlashCommonCMD: + sts NVM_CMD, r20 ; Load command into NVM Command register. + ldi r18, CCP_IOREG_gc ; Prepare Protect IO-register signature in R18. + ldi r19, NVM_CMDEX_bm ; Prepare bitmask for setting NVM Command Execute bit into R19. + sts CCP, r18 ; Enable IO-register operation (this disables interrupts for 4 cycles). + sts NVM_CTRLA, r19 ; Load bitmask into NVM Control Register A, which executes the command. + lds r22, NVM_DATA0 ; Load NVM Data Register 0 into R22. + lds r23, NVM_DATA1 ; Load NVM Data Register 1 into R23. + lds r24, NVM_DATA2 ; Load NVM Data Register 2 into R24. + clr r25 ; Clear R25 in order to return a clean 32-bit value. + ret + +; This routine is called by several other routines, and contains common code +; for executing an LPM command, including the return statement itself. +; +; Note that R24 is used for returning results, even if the +; C-domain calling function expects a void. +; +; Input: +; R25:R24 - Low bytes of Z pointer. +; R20 - NVM Command code. +; +; Returns: +; R24 - Result from LPM operation. +.section .text +FlashCommonLPM: + movw ZL, r24 ; Load index into Z. + sts NVM_CMD, r20 ; Load prepared command into NVM Command register. + lpm r24,Z + ret + +; This routine is called by several other routines, and contains common code +; for executing an SPM command, including the return statement itself. +; +; If the operation (SPM command) requires the R1:R0 registers to be +; prepared, this must be done before jumping to this routine. +; +; Input: +; R1:R0 - Optional input to SPM command. +; R25:R24 - Low bytes of Z pointer. +; R20 - NVM Command code. +; +; Returns: +; Nothing. +.section .spmhelper +FlashCommonSPM: + movw ZL, r24 ; Load R25:R24 into Z. + sts NVM_CMD, r20 ; Load prepared command into NVM Command register. + ldi r18, CCP_SPM_gc ; Prepare Protect SPM signature in R18 + sts CCP, r18 ; Enable SPM operation (this disables interrupts for 4 cycles). + spm ; Self-program. + clr r1 ; Clear R1 for GCC _zero_reg_ to function properly. + out RAMPZ, r19 ; Restore RAMPZ register. + ret + +/* Reserve memory for data */ +.section .flashdata +.align 1 +.skip MEMORY_SIZE, MEMORY_INIT_VALUE diff --git a/Firmware/Chameleon-Mini/README.txt b/Firmware/Chameleon-Mini/README.txt new file mode 100644 index 00000000..e84da109 --- /dev/null +++ b/Firmware/Chameleon-Mini/README.txt @@ -0,0 +1,9 @@ +== Compiling the firmware == +For compiling under windows you need to do the following: +1. Install AVR GNU Toolchain from Atmel +2. Install Cygwin for sh.exe (base installation is sufficient) +3. Add the bin path of cygwin (containing sh.exe) to the PATH environment variable for MAKE to find it + +Then you should be good to go to build the firmware by typing in the following: +> make + diff --git a/Firmware/Chameleon-Mini/Random.c b/Firmware/Chameleon-Mini/Random.c new file mode 100644 index 00000000..fb1a592d --- /dev/null +++ b/Firmware/Chameleon-Mini/Random.c @@ -0,0 +1,30 @@ +#include "Random.h" + +#include + +void RandomInit(void) +{ + +} + +uint8_t RandomGetByte(void) +{ + return rand() & 0xFF; +} + +void RandomGetBuffer(void* Buffer, uint8_t ByteCount) +{ + uint8_t* BufferPtr = (uint8_t*) Buffer; + + while(ByteCount--) { + *BufferPtr++ = RandomGetByte(); + } +} + +void RandomTick(void) +{ + rand(); + rand(); + rand(); + rand(); +} diff --git a/Firmware/Chameleon-Mini/Random.h b/Firmware/Chameleon-Mini/Random.h new file mode 100644 index 00000000..c6609ed6 --- /dev/null +++ b/Firmware/Chameleon-Mini/Random.h @@ -0,0 +1,18 @@ +/* + * Random.h + * + * Created on: 22.03.2013 + * Author: skuser + */ + +#ifndef RANDOM_H_ +#define RANDOM_H_ + +#include "Common.h" + +void RandomInit(void); +uint8_t RandomGetByte(void); +void RandomGetBuffer(void* Buffer, uint8_t ByteCount); +void RandomTick(void); + +#endif /* RANDOM_H_ */ diff --git a/Firmware/Chameleon-Mini/Settings.c b/Firmware/Chameleon-Mini/Settings.c new file mode 100644 index 00000000..ef3fada2 --- /dev/null +++ b/Firmware/Chameleon-Mini/Settings.c @@ -0,0 +1,209 @@ +#include "Settings.h" +#include +#include "Configuration.h" +#include "Log.h" +#include "Memory.h" +#include "LEDHook.h" +#include "Terminal/CommandLine.h" + +#include "System.h" + +#define SETTING_TO_INDEX(S) (S - SETTINGS_FIRST) +#define INDEX_TO_SETTING(I) (I + SETTINGS_FIRST) + +SettingsType GlobalSettings; +SettingsType EEMEM StoredSettings = { + .ActiveSettingIdx = SETTING_TO_INDEX(DEFAULT_SETTING), + .ActiveSettingPtr = &GlobalSettings.Settings[SETTING_TO_INDEX(DEFAULT_SETTING)], + + .Settings = { [0 ... (SETTINGS_COUNT-1)] = { + .Configuration = DEFAULT_CONFIGURATION, + .ButtonActions = { + [BUTTON_L_PRESS_SHORT] = DEFAULT_LBUTTON_ACTION, [BUTTON_R_PRESS_SHORT] = DEFAULT_RBUTTON_ACTION, + [BUTTON_L_PRESS_LONG] = DEFAULT_LBUTTON_ACTION, [BUTTON_R_PRESS_LONG] = DEFAULT_RBUTTON_ACTION + }, + .LogMode = DEFAULT_LOG_MODE, + .LEDRedFunction = DEFAULT_RED_LED_ACTION, + .LEDGreenFunction = DEFAULT_GREEN_LED_ACTION, + .PendingTaskTimeout = DEFAULT_PENDING_TASK_TIMEOUT + }} +}; + +static inline void NVM_EXEC(void) +{ + void *z = (void *)&NVM_CTRLA; + + __asm__ volatile("out %[ccp], %[ioreg]" "\n\t" + "st z, %[cmdex]" + : + : [ccp] "I" (_SFR_IO_ADDR(CCP)), + [ioreg] "d" (CCP_IOREG_gc), + [cmdex] "r" (NVM_CMDEX_bm), + [z] "z" (z) + ); +} + +void WaitForNVM(void) +{ + while (NVM.STATUS & NVM_NVMBUSY_bm) { }; +} + +void FlushNVMBuffer(void) +{ + WaitForNVM(); + + if ((NVM.STATUS & NVM_EELOAD_bm) != 0) { + NVM.CMD = NVM_CMD_ERASE_EEPROM_BUFFER_gc; + NVM_EXEC(); + } +} + +uint16_t ReadEEPBlock(uint16_t Address, void *DestPtr, uint16_t ByteCount) +{ + uint16_t BytesRead = 0; + uint8_t* BytePtr = (uint8_t*) DestPtr; + NVM.ADDR2 = 0; + + WaitForNVM(); + + while (ByteCount > 0) + { + NVM.ADDR0 = Address & 0xFF; + NVM.ADDR1 = (Address >> 8) & 0x1F; + + NVM.CMD = NVM_CMD_READ_EEPROM_gc; + NVM_EXEC(); + + *BytePtr++ = NVM.DATA0; + Address++; + + ByteCount--; + BytesRead++; + } + + return BytesRead; +} + + +uint16_t WriteEEPBlock(uint16_t Address, const void *SrcPtr, uint16_t ByteCount) +{ + const uint8_t* BytePtr = (const uint8_t*) SrcPtr; + uint8_t ByteAddress = Address % EEPROM_PAGE_SIZE; + uint16_t PageAddress = Address - ByteAddress; + uint16_t BytesWritten = 0; + + FlushNVMBuffer(); + WaitForNVM(); + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + NVM.ADDR1 = 0; + NVM.ADDR2 = 0; + + while (ByteCount > 0) + { + NVM.ADDR0 = ByteAddress; + + NVM.DATA0 = *BytePtr++; + + ByteAddress++; + ByteCount--; + + if (ByteCount == 0 || ByteAddress >= EEPROM_PAGE_SIZE) + { + NVM.ADDR0 = PageAddress & 0xFF; + NVM.ADDR1 = (PageAddress >> 8) & 0x1F; + + NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; + NVM_EXEC(); + + PageAddress += EEPROM_PAGE_SIZE; + ByteAddress = 0; + + WaitForNVM(); + + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + } + + BytesWritten++; + } + + return BytesWritten; +} + + +void SettingsLoad(void) { + ReadEEPBlock(0, &GlobalSettings, sizeof(SettingsType)); +} + +void SettingsSave(void) { +#if ENABLE_EEPROM_SETTINGS + WriteEEPBlock(0, &GlobalSettings, sizeof(SettingsType)); +#endif +} + +void SettingsCycle(void) { + uint8_t i = SETTINGS_COUNT; + uint8_t SettingIdx = GlobalSettings.ActiveSettingIdx; + + while (i-- > 0) { + /* Try to set one of the SETTINGS_COUNT following settings. + * But only set if it is not CONFIG_NONE. */ + SettingIdx = (SettingIdx + 1) % SETTINGS_COUNT; + + if (GlobalSettings.Settings[SettingIdx].Configuration != CONFIG_NONE) { + SettingsSetActiveById(INDEX_TO_SETTING(SettingIdx)); + break; + } + } +} + +bool SettingsSetActiveById(uint8_t Setting) { + if ( (Setting >= SETTINGS_FIRST) && (Setting <= SETTINGS_LAST) ) { + uint8_t SettingIdx = SETTING_TO_INDEX(Setting); + + /* Break potentially pending timeout task (manual timeout) */ + CommandLinePendingTaskBreak(); + + /* Store current memory contents permanently */ + MemoryStore(); + + GlobalSettings.ActiveSettingIdx = SettingIdx; + GlobalSettings.ActiveSettingPtr = + &GlobalSettings.Settings[SettingIdx]; + + /* Settings have changed. Progress changes through system */ + ConfigurationSetById(GlobalSettings.ActiveSettingPtr->Configuration); + LogSetModeById(GlobalSettings.ActiveSettingPtr->LogMode); + + /* Recall new memory contents */ + MemoryRecall(); + + /* Notify LED. blink according to current setting */ + LEDHook(LED_SETTING_CHANGE, LED_BLINK + SettingIdx); + + return true; + } else { + return false; + } +} + +uint8_t SettingsGetActiveById(void) { + return INDEX_TO_SETTING(GlobalSettings.ActiveSettingIdx); +} + +void SettingsGetActiveByName(char* SettingOut, uint16_t BufferSize) { + SettingOut[0] = SettingsGetActiveById() + '0'; + SettingOut[1] = '\0'; +} + +bool SettingsSetActiveByName(const char* Setting) { + uint8_t SettingNr = Setting[0] - '0'; + + if (Setting[1] == '\0') { + LogEntry(LOG_INFO_SETTING_SET, Setting, 1); + return SettingsSetActiveById(SettingNr); + } else { + return false; + } +} + diff --git a/Firmware/Chameleon-Mini/Settings.h b/Firmware/Chameleon-Mini/Settings.h new file mode 100644 index 00000000..29e4b9ed --- /dev/null +++ b/Firmware/Chameleon-Mini/Settings.h @@ -0,0 +1,51 @@ +/* + * Settings.h + * + * Created on: 21.12.2013 + * Author: skuser + */ +/** @file */ +#ifndef SETTINGS_H_ +#define SETTINGS_H_ + +#include "Button.h" +#include "Configuration.h" +#include "Log.h" +#include "LED.h" +#include "Memory.h" + +#define SETTINGS_COUNT (MEMORY_SIZE / MEMORY_SIZE_PER_SETTING) +#define SETTINGS_FIRST 1 +#define SETTINGS_LAST (SETTINGS_FIRST + SETTINGS_COUNT - 1) + +/** Defines one setting. + * + * \note Some properties may change globally if this is defined in the Makefile. + */ +typedef struct { + ButtonActionEnum ButtonActions[BUTTON_TYPE_COUNT]; /// Button actions for this setting. + LogModeEnum LogMode; /// Log mode for this setting. + ConfigurationEnum Configuration; /// Active configuration for this setting. + LEDHookEnum LEDRedFunction; /// Red LED function for this setting. + LEDHookEnum LEDGreenFunction; /// Green LED function for this setting. + uint16_t PendingTaskTimeout; /// Timeout for timeout commands for this setting, in multiples of 100 ms. +} SettingsEntryType; + +typedef struct { + uint8_t ActiveSettingIdx; + SettingsEntryType* ActiveSettingPtr; + SettingsEntryType Settings[SETTINGS_COUNT]; +} SettingsType; + +extern SettingsType GlobalSettings; + +void SettingsLoad(void); +void SettingsSave(void); + +void SettingsCycle(void); +bool SettingsSetActiveById(uint8_t Setting); +uint8_t SettingsGetActiveById(void); +void SettingsGetActiveByName(char* SettingOut, uint16_t BufferSize); +bool SettingsSetActiveByName(const char* Setting); + +#endif /* SETTINGS_H_ */ diff --git a/Firmware/Chameleon-Mini/System.c b/Firmware/Chameleon-Mini/System.c new file mode 100644 index 00000000..978bf49d --- /dev/null +++ b/Firmware/Chameleon-Mini/System.c @@ -0,0 +1,151 @@ +/* + * System.c + * + * Created on: 10.02.2013 + * Author: skuser + */ + +#include "System.h" +#include "LED.h" +#include + +#ifndef WDT_PER_500CLK_gc +#define WDT_PER_500CLK_gc WDT_PER_512CLK_gc +#endif + +ISR(BADISR_vect) +{ + //LED_PORT.OUTSET = LED_RED; + while(1); +} + +ISR(RTC_OVF_vect) +{ + SYSTEM_TICK_REGISTER += SYSTEM_TICK_PERIOD; +} + +void SystemInit(void) +{ + if (RST.STATUS & RST_WDRF_bm) { + /* On Watchdog reset clear WDRF bit, disable watchdog + * and jump into bootloader */ + RST.STATUS = RST_WDRF_bm; + + CCP = CCP_IOREG_gc; + WDT.CTRL = WDT_CEN_bm; + + asm volatile ("jmp %0"::"i" (BOOT_SECTION_START + 0x1FC)); + } + + /* XTAL x 2 as SysCLK */ + OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc; + OSC.CTRL |= OSC_XOSCEN_bm; + while(!(OSC.STATUS & OSC_XOSCRDY_bm)) + ; + + OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | (2 << OSC_PLLFAC_gp); + OSC.CTRL |= OSC_PLLEN_bm; + + while(!(OSC.STATUS & OSC_PLLRDY_bm)) + ; + + /* Set PLL as main clock */ + CCP = CCP_IOREG_gc; + CLK.CTRL = CLK_SCLKSEL_PLL_gc; + + SYSTEM_TICK_REGISTER = 0; + + /* Enable RTC with roughly 1kHz clock for system tick + * and to wake up while sleeping. */ + CLK.RTCCTRL = CLK_RTCSRC_ULP_gc | CLK_RTCEN_bm; + RTC.PER = SYSTEM_TICK_PERIOD - 1; + RTC.COMP = SYSTEM_TICK_PERIOD - 1; + RTC.CTRL = RTC_PRESCALER_DIV1_gc; + RTC.INTCTRL = RTC_OVFINTLVL_LO_gc; + + /* Enable EEPROM data memory mapping */ + //NVM.CTRLB |= NVM_EEMAPEN_bm; + + /* Enable DMA */ + DMA.CTRL = DMA_ENABLE_bm | DMA_DBUFMODE_DISABLED_gc | DMA_PRIMODE_RR0123_gc; + +} + +void SystemReset(void) +{ + CCP = CCP_IOREG_gc; + RST.CTRL = RST_SWRST_bm; +} + +void SystemEnterBootloader(void) +{ + /* Use Watchdog timer to reset into bootloader. */ + CCP = CCP_IOREG_gc; + WDT.CTRL = WDT_PER_500CLK_gc | WDT_ENABLE_bm | WDT_CEN_bm; +} + + +void SystemStartUSBClock(void) +{ + //SystemSleepDisable(); +#if 0 + /* 48MHz USB Clock using 12MHz XTAL */ + OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc; + OSC.CTRL |= OSC_XOSCEN_bm; + while(!(OSC.STATUS & OSC_XOSCRDY_bm)) + ; + + OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | (4 << OSC_PLLFAC_gp); + + OSC.CTRL |= OSC_PLLEN_bm; + while(!(OSC.STATUS & OSC_PLLRDY_bm)) + ; +#else + /* Use internal HS RC for USB */ + OSC.CTRL |= OSC_RC32MEN_bm; + while(!(OSC.STATUS & OSC_RC32MRDY_bm)) + ; + + /* Load RC32 CAL values for 48MHz use */ + NVM.CMD = NVM_CMD_READ_CALIB_ROW_gc; + DFLLRC32M.CALA = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBRCOSCA)); + DFLLRC32M.CALB = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBRCOSC)); + NVM.CMD = NVM_CMD_NO_OPERATION_gc; + + /* For USBSOF operation, whe need to use COMP = 48MHz/1kHz = 0xBB80 */ + DFLLRC32M.COMP1 = 0x80; + DFLLRC32M.COMP2 = 0xBB; + + /* Select USBSOF as DFLL source */ + OSC.DFLLCTRL &= ~OSC_RC32MCREF_gm; + OSC.DFLLCTRL |= OSC_RC32MCREF_USBSOF_gc; + + /* Enable DFLL */ + DFLLRC32M.CTRL |= DFLL_ENABLE_bm; +#endif +} + +void SystemStopUSBClock(void) +{ + //SystemSleepEnable(); + +#if 0 + /* Disable USB Clock to minimize power consumption */ + CLK.USBCTRL &= ~CLK_USBSEN_bm; + OSC.CTRL &= ~OSC_PLLEN_bm; + OSC.CTRL &= ~OSC_XOSCEN_bm; +#else + /* Disable USB Clock to minimize power consumption */ + CLK.USBCTRL &= ~CLK_USBSEN_bm; + DFLLRC32M.CTRL &= ~DFLL_ENABLE_bm; + OSC.CTRL &= ~OSC_RC32MEN_bm; +#endif +} + +void SystemInterruptInit(void) +{ + /* Enable all interrupt levels */ + PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; + sei(); +} + diff --git a/Firmware/Chameleon-Mini/System.h b/Firmware/Chameleon-Mini/System.h new file mode 100644 index 00000000..2fcce7cd --- /dev/null +++ b/Firmware/Chameleon-Mini/System.h @@ -0,0 +1,58 @@ +/* + * System.h + * + * Created on: 10.02.2013 + * Author: skuser + */ + +#ifndef SYSTEM_H +#define SYSTEM_H + +#include +#include +#include +#include +#include +#include "Common.h" + +#define F_RTC 1000 +#define SYSTEM_MILLISECONDS_TO_RTC_CYCLES(x) \ + ( (uint16_t) ( (double) F_RTC * x / 1E3 + 0.5) ) + +#define SYSTEM_TICK_WIDTH 7 /* Bits */ +#define SYSTEM_TICK_PERIOD (1<<7) +#define SYSTEM_TICK_MS (SYSTEM_TICK_PERIOD) +#define SYSTEM_TICK_FREQ (1000 / SYSTEM_TICK_PERIOD) + +#define SYSTEM_SMODE_PSAVE SLEEP_SMODE_PSAVE_gc +#define SYSTEM_SMODE_IDLE SLEEP_SMODE_IDLE_gc + +/* Use GPIORE and GPIORF as global tick register */ +#define SYSTEM_TICK_REGISTER (*((volatile uint16_t*) &GPIORE)) + +void SystemInit(void); +void SystemReset(void); +void SystemEnterBootloader(void); +void SystemStartUSBClock(void); +void SystemStopUSBClock(void); +void SystemInterruptInit(void); +INLINE bool SystemTick100ms(void); + +INLINE bool SystemTick100ms(void) +{ + if (RTC.INTFLAGS & RTC_COMPIF_bm) { + while(RTC.STATUS & RTC_SYNCBUSY_bm) + ; + + RTC.INTFLAGS = RTC_COMPIF_bm; + return true; + } + + return false; +} + +INLINE uint16_t SystemGetSysTick(void) { + return SYSTEM_TICK_REGISTER | RTC.CNT; +} + +#endif /* SYSTEM_H */ diff --git a/Firmware/Chameleon-Mini/Terminal/CommandLine.c b/Firmware/Chameleon-Mini/Terminal/CommandLine.c new file mode 100644 index 00000000..c98ecdd3 --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/CommandLine.c @@ -0,0 +1,555 @@ +/* + * CommandLine.c + * + * Created on: 04.05.2013 + * Author: skuser + */ + +#include "CommandLine.h" +#include "Settings.h" +#include "System.h" + +#define CHAR_GET_MODE '?' /* ? */ +#define CHAR_SET_MODE '=' /* = */ +#define CHAR_EXEC_MODE '\0' /* */ +#define CHAR_EXEC_MODE_PARAM ' ' /* ... */ + +#define IS_COMMAND_DELIMITER(c) ( \ + ((c) == CHAR_EXEC_MODE) || ((c) == CHAR_GET_MODE) || ((c) == CHAR_SET_MODE) || ((c) == CHAR_EXEC_MODE_PARAM) \ +) + +#define IS_CHARACTER(c) ( \ + ( ((c) >= 'A') && ((c) <= 'Z') ) || \ + ( ((c) >= 'a') && ((c) <= 'z') ) || \ + ( ((c) >= '0') && ((c) <= '9') ) || \ + ( ((c) == '_') ) || \ + ( ((c) == CHAR_GET_MODE) || ((c) == CHAR_SET_MODE) || ((c) == CHAR_EXEC_MODE_PARAM) ) \ +) + +#define IS_LOWERCASE(c) ( ((c) >= 'a') && ((c) <= 'z') ) +#define TO_UPPERCASE(c) ( (c) - 'a' + 'A' ) + +#define IS_WHITESPACE(c) ( ((c) == ' ') || ((c) == '\t') ) + +#define NO_FUNCTION ((void*) 0) + +#define STATUS_MESSAGE_TRAILER "\r\n" +#define OPTIONAL_ANSWER_TRAILER "\r\n" + +/* Include all command functions */ +#include "Commands.h" + +const PROGMEM CommandEntryType CommandTable[] = { + { + .Command = COMMAND_VERSION, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetVersion, + }, + { + .Command = COMMAND_CONFIG, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetConfig, + .GetFunc = CommandGetConfig + }, + { + .Command = COMMAND_UID, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetUid, + .GetFunc = CommandGetUid + }, + { + .Command = COMMAND_READONLY, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .GetFunc = CommandGetReadOnly, + .SetFunc = CommandSetReadOnly + + }, + { + .Command = COMMAND_UPLOAD, + .ExecFunc = CommandExecUpload, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_DOWNLOAD, + .ExecFunc = CommandExecDownload, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_RESET, + .ExecFunc = CommandExecReset, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, +#ifdef SUPPORT_FIRMWARE_UPGRADE + { + .Command = COMMAND_UPGRADE, + .ExecFunc = CommandExecUpgrade, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, +#endif + { + .Command = COMMAND_MEMSIZE, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetMemSize + }, + { + .Command = COMMAND_UIDSIZE, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetUidSize + }, + { + .Command = COMMAND_RBUTTON, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetRButton, + .GetFunc = CommandGetRButton + }, + { + .Command = COMMAND_RBUTTON_LONG, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetRButtonLong, + .GetFunc = CommandGetRButtonLong + }, + { + .Command = COMMAND_LBUTTON, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetLButton, + .GetFunc = CommandGetLButton + }, + { + .Command = COMMAND_LBUTTON_LONG, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetLButtonLong, + .GetFunc = CommandGetLButtonLong + }, + { + .Command = COMMAND_LEDGREEN, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetLedGreen, + .GetFunc = CommandGetLedGreen + }, + { + .Command = COMMAND_LEDRED, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetLedRed, + .GetFunc = CommandGetLedRed + }, + { + .Command = COMMAND_LOGMODE, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetLogMode, + .GetFunc = CommandGetLogMode + }, + { + .Command = COMMAND_LOGMEM, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetLogMem + }, + { + .Command = COMMAND_LOGDOWNLOAD, + .ExecFunc = CommandExecLogDownload, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_STORELOG, + .ExecFunc = CommandExecStoreLog, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_LOGCLEAR, + .ExecFunc = CommandExecLogClear, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_SETTING, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetSetting, + .GetFunc = CommandGetSetting + }, + { + .Command = COMMAND_CLEAR, + .ExecFunc = CommandExecClear, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_STORE, + .ExecFunc = CommandExecStore, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_RECALL, + .ExecFunc = CommandExecRecall, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_CHARGING, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetCharging + }, + { + .Command = COMMAND_HELP, + .ExecFunc = CommandExecHelp, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_RSSI, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetRssi + }, + { + .Command = COMMAND_SYSTICK, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = CommandGetSysTick + }, + { + .Command = COMMAND_SEND_RAW, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = CommandExecParamSendRaw, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_SEND, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = CommandExecParamSend, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_GETUID, + .ExecFunc = CommandExecGetUid, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_DUMP_MFU, + .ExecFunc = CommandExecDumpMFU, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_IDENTIFY_CARD, + .ExecFunc = CommandExecIdentifyCard, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, + { + .Command = COMMAND_TIMEOUT, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetTimeout, + .GetFunc = CommandGetTimeout + }, + { + .Command = COMMAND_THRESHOLD, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetThreshold, + .GetFunc = CommandGetThreshold + }, + { + .Command = COMMAND_FIELD, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandSetField, + .GetFunc = CommandGetField + }, + { /* This has to be last element */ + .Command = COMMAND_LIST_END, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + } +}; + +#define STATUS_TABLE_ENTRY(Id, Text) \ + { Id, STRINGIFY(Id) ":" Text } + +typedef struct { + CommandStatusIdType Id; + CommandStatusMessageType Message; +} CommandStatusType; + +static const CommandStatusType PROGMEM StatusTable[] = { + STATUS_TABLE_ENTRY(COMMAND_INFO_OK_ID, COMMAND_INFO_OK), + STATUS_TABLE_ENTRY(COMMAND_INFO_OK_WITH_TEXT_ID, COMMAND_INFO_OK_WITH_TEXT), + STATUS_TABLE_ENTRY(COMMAND_INFO_XMODEM_WAIT_ID, COMMAND_INFO_XMODEM_WAIT), + STATUS_TABLE_ENTRY(COMMAND_ERR_UNKNOWN_CMD_ID, COMMAND_ERR_UNKNOWN_CMD), + STATUS_TABLE_ENTRY(COMMAND_ERR_INVALID_USAGE_ID, COMMAND_ERR_INVALID_USAGE), + STATUS_TABLE_ENTRY(COMMAND_ERR_INVALID_PARAM_ID, COMMAND_ERR_INVALID_PARAM), + STATUS_TABLE_ENTRY(COMMAND_INFO_FALSE_ID, COMMAND_INFO_FALSE), + STATUS_TABLE_ENTRY(COMMAND_INFO_TRUE_ID, COMMAND_INFO_TRUE), + STATUS_TABLE_ENTRY(COMMAND_ERR_TIMEOUT_ID, COMMAND_ERR_TIMEOUT), +}; + +static uint16_t BufferIdx; + +void (*CommandLinePendingTaskTimeout) (void) = NO_FUNCTION; // gets called on Timeout +static bool TaskPending = false; +static uint16_t TaskPendingSince; + +static const char* GetStatusMessageP(CommandStatusIdType StatusId) +{ + uint8_t i; + + for (i=0; i<(sizeof(StatusTable)/sizeof(*StatusTable)); i++) { + if (pgm_read_byte(&StatusTable[i].Id) == StatusId) + return StatusTable[i].Message; + } + + return (void*) 0; +} + +static CommandStatusIdType CallCommandFunc( + const CommandEntryType* CommandEntry, char CommandDelimiter, char* pParam) { + char* pTerminalBuffer = (char*) TerminalBuffer; + CommandStatusIdType Status = COMMAND_ERR_INVALID_USAGE_ID; + + /* Call appropriate function depending on CommandDelimiter */ + if (CommandDelimiter == CHAR_GET_MODE) { + CommandGetFuncType GetFunc = pgm_read_ptr(&CommandEntry->GetFunc); + if (GetFunc != NO_FUNCTION) { + Status = GetFunc(pTerminalBuffer); + } + } else if (CommandDelimiter == CHAR_SET_MODE) { + CommandSetFuncType SetFunc = pgm_read_ptr(&CommandEntry->SetFunc); + if (SetFunc != NO_FUNCTION) { + Status = SetFunc(pTerminalBuffer, pParam); + } + } else if (CommandDelimiter == CHAR_EXEC_MODE) { + CommandExecFuncType ExecFunc = pgm_read_ptr(&CommandEntry->ExecFunc); + if (ExecFunc != NO_FUNCTION) { + Status = ExecFunc(pTerminalBuffer); + } + } else if (CommandDelimiter == CHAR_EXEC_MODE_PARAM) { + CommandExecParamFuncType ExecParamFunc = pgm_read_ptr(&CommandEntry->ExecParamFunc); + if (ExecParamFunc != NO_FUNCTION) { + Status = ExecParamFunc(pTerminalBuffer, pParam); + } + } else { + /* This should not happen (TM) */ + } + + if (Status == TIMEOUT_COMMAND) + { + TaskPending = true; + TaskPendingSince = SystemGetSysTick(); + } + + /* This delimiter has not been registered with this command */ + return Status; +} + +static void DecodeCommand(void) +{ + uint8_t i; + bool CommandFound = false; + CommandStatusIdType StatusId = COMMAND_ERR_UNKNOWN_CMD_ID; + char* pTerminalBuffer = (char*) TerminalBuffer; + + /* Do some sanity check first */ + if (!IS_COMMAND_DELIMITER(pTerminalBuffer[0])) { + char* pCommandDelimiter = pTerminalBuffer; + char CommandDelimiter = '\0'; + + /* Search for command delimiter, store it and replace with '\0' */ + while(!(IS_COMMAND_DELIMITER(*pCommandDelimiter))) + pCommandDelimiter++; + + CommandDelimiter = *pCommandDelimiter; + *pCommandDelimiter = '\0'; + + /* Search in command table */ + for (i=0; i<(sizeof(CommandTable) / sizeof(*CommandTable)); i++) { + if (strcmp_P(pTerminalBuffer, CommandTable[i].Command) == 0) { + /* Command found. Clear buffer, and call appropriate function */ + char* pParam = ++pCommandDelimiter; + + pTerminalBuffer[0] = '\0'; + CommandFound = true; + + StatusId = CallCommandFunc(&CommandTable[i], CommandDelimiter, pParam); + + break; + } + } + } + + if (StatusId == TIMEOUT_COMMAND) // it is a timeout command, so we return + return; + + /* Send command status message */ + TerminalSendStringP(GetStatusMessageP(StatusId)); + TerminalSendStringP(PSTR(STATUS_MESSAGE_TRAILER)); + + if (CommandFound && (pTerminalBuffer[0] != '\0') ) { + /* Send optional answer */ + TerminalSendString(pTerminalBuffer); + TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); + } +} + +void CommandLineInit(void) +{ + BufferIdx = 0; +} + +bool CommandLineProcessByte(uint8_t Byte) { + if (IS_CHARACTER(Byte)) { + /* Store uppercase character */ + if (IS_LOWERCASE(Byte)) { + Byte = TO_UPPERCASE(Byte); + } + + /* Prevent buffer overflow and account for '\0' */ + if (BufferIdx + < (sizeof(TerminalBuffer) / sizeof(*TerminalBuffer) - 1)) { + TerminalBuffer[BufferIdx++] = Byte; + } + } else if (Byte == '\r') { + /* Process on \r. Terminate string and decode. */ + TerminalBuffer[BufferIdx] = '\0'; + BufferIdx = 0; + + if (!TaskPending) + DecodeCommand(); + } else if (Byte == '\b') { + /* Backspace. Delete last character in buffer. */ + if (BufferIdx > 0) { + BufferIdx--; + } + } else if (Byte == 0x1B) { + /* Drop buffer on escape */ + BufferIdx = 0; + } else { + /* Ignore other chars */ + } + + return true; +} + +INLINE void Timeout(void) +{ + TaskPending = false; + TerminalSendStringP(GetStatusMessageP(COMMAND_ERR_TIMEOUT_ID)); + TerminalSendStringP(PSTR(STATUS_MESSAGE_TRAILER)); + + if (CommandLinePendingTaskTimeout != NO_FUNCTION) + { + CommandLinePendingTaskTimeout(); // call the function that ends the task + CommandLinePendingTaskTimeout = NO_FUNCTION; + } +} + +void CommandLineTick(void) +{ + if (TaskPending && + GlobalSettings.ActiveSettingPtr->PendingTaskTimeout != 0 && // 0 means no timeout + SYSTICK_DIFF_100MS(TaskPendingSince) >= GlobalSettings.ActiveSettingPtr->PendingTaskTimeout) // timeout expired + { + Timeout(); + } +} + +void CommandLinePendingTaskBreak(void) +{ + if (!TaskPending) + return; + + Timeout(); +} + +void CommandLinePendingTaskFinished(CommandStatusIdType ReturnStatusID, char const * const OutMessage) +{ + if (!TaskPending) // if no task is pending, no task can be finished + return; + TaskPending = false; + + TerminalSendStringP(GetStatusMessageP(ReturnStatusID)); + TerminalSendStringP(PSTR(STATUS_MESSAGE_TRAILER)); + + if (OutMessage != NULL) + { + TerminalSendString(OutMessage); + TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); + } +} + +void CommandLineAppendData(void const * const Buffer, uint16_t Bytes) +{ + char* pTerminalBuffer = (char*) TerminalBuffer; + + uint16_t tmpBytes = Bytes; + if (Bytes > (sizeof(TerminalBuffer) / 2)) + tmpBytes = sizeof(TerminalBuffer) / 2; + Bytes -= tmpBytes; + + BufferToHexString(pTerminalBuffer, sizeof(TerminalBuffer), Buffer, tmpBytes); + TerminalSendString(pTerminalBuffer); + + uint8_t i = 1; + while (Bytes > (sizeof(TerminalBuffer) / 2)) + { + Bytes -= sizeof(TerminalBuffer) / 2; + BufferToHexString(pTerminalBuffer, sizeof(TerminalBuffer), Buffer + i * sizeof(TerminalBuffer) / 2, sizeof(TerminalBuffer)); + TerminalSendString(pTerminalBuffer); + i++; + } + + if (Bytes > 0) + { + BufferToHexString(pTerminalBuffer, sizeof(TerminalBuffer), Buffer + i * sizeof(TerminalBuffer) / 2, Bytes); + TerminalSendString(pTerminalBuffer); + } + + TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); +} diff --git a/Firmware/Chameleon-Mini/Terminal/CommandLine.h b/Firmware/Chameleon-Mini/Terminal/CommandLine.h new file mode 100644 index 00000000..3ee0388f --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/CommandLine.h @@ -0,0 +1,25 @@ +/* + * CommandLine.h + * + * Created on: 04.05.2013 + * Author: skuser + */ + +#ifndef COMMANDLINE_H_ +#define COMMANDLINE_H_ + +#include "Terminal.h" +#include "Commands.h" + +void CommandLineInit(void); +bool CommandLineProcessByte(uint8_t Byte); +void CommandLineTick(void); + +void CommandLineAppendData(void const * const Buffer, uint16_t Bytes); + +/* Functions for timeout commands */ +void CommandLinePendingTaskFinished(CommandStatusIdType ReturnStatusID, char const * const OutMessage); // must be called, when the intended task is finished +extern void (*CommandLinePendingTaskTimeout) (void); // gets called on timeout to end the pending task +void CommandLinePendingTaskBreak(void); // this manually triggers a timeout + +#endif /* COMMANDLINE_H_ */ diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c new file mode 100644 index 00000000..92b208d4 --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -0,0 +1,625 @@ + +#include "Commands.h" +#include +#include +#include "XModem.h" +#include "../Settings.h" +#include "../Chameleon-Mini.h" +#include "../LUFA/Version.h" +#include "../Configuration.h" +#include "../Random.h" +#include "../Memory.h" +#include "../System.h" +#include "../Button.h" +#include "../AntennaLevel.h" +#include "../Battery.h" +#include "../Codec/Codec.h" + +extern Reader14443Command Reader14443CurrentCommand; + +extern const PROGMEM CommandEntryType CommandTable[]; + +CommandStatusIdType CommandGetVersion(char* OutParam) +{ + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR( + "ChameleonMini RevG %S using LUFA %S compiled with AVR-GCC %S\r\nBased on the open-source NFC tool ChameleonMini\r\nhttps://github.com/emsec/ChameleonMini\r\ncommit %S" + ), PSTR(CHAMELEON_MINI_VERSION_STRING), PSTR(LUFA_VERSION_STRING), PSTR(__VERSION__), PSTR(COMMIT_ID) + ); + + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandGetConfig(char* OutParam) +{ + ConfigurationGetByName(OutParam, TERMINAL_BUFFER_SIZE); + + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandSetConfig(char* OutMessage, const char* InParam) +{ + if (COMMAND_IS_SUGGEST_STRING(InParam)) { + ConfigurationGetList(OutMessage, TERMINAL_BUFFER_SIZE); + return COMMAND_INFO_OK_WITH_TEXT_ID; + } else if (ConfigurationSetByName(InParam)) { + SettingsSave(); + return COMMAND_INFO_OK_ID; + } else { + return COMMAND_ERR_INVALID_PARAM_ID; + } +} + +CommandStatusIdType CommandGetUid(char* OutParam) +{ + uint8_t UidBuffer[COMMAND_UID_BUFSIZE]; + uint16_t UidSize = ActiveConfiguration.UidSize; + + if (UidSize == 0) + { + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("NO UID.")); + return COMMAND_INFO_OK_WITH_TEXT_ID; + } + + ApplicationGetUid(UidBuffer); + + BufferToHexString(OutParam, TERMINAL_BUFFER_SIZE, + UidBuffer, UidSize); + + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandSetUid(char* OutMessage, const char* InParam) +{ + uint8_t UidBuffer[COMMAND_UID_BUFSIZE]; + uint16_t UidSize = ActiveConfiguration.UidSize; + + if (strcmp_P(InParam, PSTR(COMMAND_UID_RANDOM)) == 0) { + /* Load with random bytes */ + for (uint8_t i=0; iCommand) != 0 && ByteCount > 0) { + const char* CommandName = EntryPtr->Command; + char c; + + while( (c = pgm_read_byte(CommandName)) != '\0' && ByteCount > 1) { + *OutMessage++ = c; + CommandName++; + ByteCount--; + } + + *OutMessage++ = ','; + ByteCount--; + + EntryPtr++; + } + + *--OutMessage = '\0'; + + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandGetRssi(char* OutParam) +{ + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, + PSTR("%5u mV"), AntennaLevelGet()); + + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandGetSysTick(char* OutParam) +{ + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%4.4X"), SystemGetSysTick()); + + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandExecParamSend(char* OutMessage, const char* InParams) +{ + if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) + return COMMAND_ERR_INVALID_USAGE_ID; + + ApplicationReset(); + Reader14443CurrentCommand = Reader14443_Send; + + char const * paramTwo = strchr(InParams, ' '); + uint16_t length; + if (paramTwo == NULL) // this means, we have to calculate the length + { + length = strlen(InParams); + if (length&1) // return error when length is odd + return COMMAND_ERR_INVALID_PARAM_ID; + length /= 2; + if (length == 1) + { + ReaderSendBitCount = 7; // this is a short frame + } else { + ReaderSendBitCount = length * 8; + } + } else if(paramTwo == (InParams+4)) { // we have a bitcount prepended + uint8_t tmp[2]; + HexStringToBuffer(tmp, 2, InParams); + ReaderSendBitCount = (tmp[0]<<8) + tmp[1]; // set our BitCount to the given value + InParams = ++paramTwo; // set InParams to the beginning of the second parameter + length = strlen(InParams); + if ((length&1) || (length / 2 * 8) < ReaderSendBitCount) // this parameter is malformed, if it is odd or if there are less bits than the BitCount indicates + return COMMAND_ERR_INVALID_PARAM_ID; + } else { // any other case means we have malformed parameters + return COMMAND_ERR_INVALID_PARAM_ID; + } + + HexStringToBuffer(ReaderSendBuffer, (ReaderSendBitCount+7)/8, InParams); + + Reader14443ACodecStart(); + + return TIMEOUT_COMMAND; +} + +CommandStatusIdType CommandExecParamSendRaw(char* OutMessage, const char* InParams) +{ + if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) + return COMMAND_ERR_INVALID_USAGE_ID; + + ApplicationReset(); + Reader14443CurrentCommand = Reader14443_Send_Raw; + + char const * paramTwo = strchr(InParams, ' '); + uint16_t length; + if (paramTwo == NULL) // this means, we have to calculate the length + { + length = strlen(InParams); + if (length&1) // return error when length is odd + return COMMAND_ERR_INVALID_PARAM_ID; + length /= 2; + if (length == 1) + { + ReaderSendBitCount = 7; // this is a short frame + } else { + length *= 8; + ReaderSendBitCount = length - (length % 9); // how many bytes+paritybit match into our input? + } + } else if(paramTwo == (InParams+4)) { // we have a bitcount prepended + uint8_t tmp[2]; + HexStringToBuffer(tmp, 2, InParams); + ReaderSendBitCount = (tmp[0]<<8) + tmp[1]; // set our BitCount to the given value + if (ReaderSendBitCount != 7 && (ReaderSendBitCount % 8)) // since we have to add parity bits here (in case this is not a short frame), the number of bits to be sent has to be a multiple of 8 + return COMMAND_ERR_INVALID_PARAM_ID; + InParams = ++paramTwo; // set InParams to the beginning of the second parameter + length = strlen(InParams); + if ((length&1) || (length / 2 * 8) < ReaderSendBitCount) // this parameter is malformed, if it is odd or if there are less bits than the BitCount indicates + return COMMAND_ERR_INVALID_PARAM_ID; + } else { // any other case means we have malformed parameters + return COMMAND_ERR_INVALID_PARAM_ID; + } + + HexStringToBuffer(ReaderSendBuffer, (ReaderSendBitCount+7)/8, InParams); + + Reader14443ACodecStart(); + + return TIMEOUT_COMMAND; +} + +CommandStatusIdType CommandExecDumpMFU(char* OutMessage) +{ + if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) + return COMMAND_ERR_INVALID_USAGE_ID; + ApplicationReset(); + + Reader14443CurrentCommand = Reader14443_Read_MF_Ultralight; + Reader14443AAppInit(); + Reader14443ACodecStart(); + CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; + return TIMEOUT_COMMAND; +} + +CommandStatusIdType CommandExecGetUid(char* OutMessage) // this function is for reading the uid in reader mode +{ + if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) + return COMMAND_ERR_INVALID_USAGE_ID; + ApplicationReset(); + + Reader14443CurrentCommand = Reader14443_Get_UID; + Reader14443AAppInit(); + Reader14443ACodecStart(); + CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; + return TIMEOUT_COMMAND; +} + +CommandStatusIdType CommandExecIdentifyCard(char* OutMessage) +{ + if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) + return COMMAND_ERR_INVALID_USAGE_ID; + ApplicationReset(); + + Reader14443CurrentCommand = Reader14443_Indentify; + Reader14443AAppInit(); + Reader14443ACodecStart(); + CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; + return TIMEOUT_COMMAND; +} + +CommandStatusIdType CommandGetTimeout(char* OutParam) +{ + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%u ms"), GlobalSettings.ActiveSettingPtr->PendingTaskTimeout * 100); + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandSetTimeout(char* OutMessage, const char* InParam) +{ + if (COMMAND_IS_SUGGEST_STRING(InParam)) + { + snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("0 = no timeout\r\n1-600 = 100 ms - 60000 ms timeout")); + return COMMAND_INFO_OK_WITH_TEXT_ID; + } + uint16_t tmp = 601; + if (!sscanf(InParam, "%5d", &tmp) || tmp > 600) + return COMMAND_ERR_INVALID_PARAM_ID; + GlobalSettings.ActiveSettingPtr->PendingTaskTimeout = tmp; + return COMMAND_INFO_OK_ID; +} + +CommandStatusIdType CommandGetThreshold(char* OutParam) +{ + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%u"), ReaderThreshold); + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandSetThreshold(char* OutMessage, const char* InParam) +{ + if (COMMAND_IS_SUGGEST_STRING(InParam)) + { + snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("Any integer from 0 to %u. Reference voltage will be (VCC * THRESHOLD / 4095) mV."), CODEC_MAXIMUM_THRESHOLD); + return COMMAND_INFO_OK_WITH_TEXT_ID; + } + uint16_t tmp = 0; + if (!sscanf(InParam, "%5d", &tmp) || tmp > CODEC_MAXIMUM_THRESHOLD) + return COMMAND_ERR_INVALID_PARAM_ID; + DACB.CH0DATA = tmp; + ReaderThreshold = tmp; + return COMMAND_INFO_OK_ID; +} + +CommandStatusIdType CommandSetField(char* OutMessage, const char* InParam) +{ + if (COMMAND_IS_SUGGEST_STRING(InParam)) + { + snprintf_P(OutMessage, TERMINAL_BUFFER_SIZE, PSTR("%c,%c"), COMMAND_CHAR_TRUE, COMMAND_CHAR_FALSE); + return COMMAND_INFO_OK_WITH_TEXT_ID; + } + if (InParam[0] == COMMAND_CHAR_TRUE) + { + CodecReaderFieldStart(); + } else if(InParam[0] == COMMAND_CHAR_FALSE) { + CodecReaderFieldStop(); + } else { + return COMMAND_ERR_INVALID_PARAM_ID; + } + return COMMAND_INFO_OK_ID; +} + +CommandStatusIdType CommandGetField(char* OutMessage) +{ + if (CodecGetReaderField()) + OutMessage[0] = COMMAND_CHAR_TRUE; + else + OutMessage[0] = COMMAND_CHAR_FALSE; + OutMessage[1] = '\0'; + return COMMAND_INFO_OK_WITH_TEXT_ID; +} diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.h b/Firmware/Chameleon-Mini/Terminal/Commands.h new file mode 100644 index 00000000..6e2e364f --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/Commands.h @@ -0,0 +1,187 @@ + + +#ifndef COMMANDS_H_ +#define COMMANDS_H_ + +#include "../Common.h" + +#define MAX_COMMAND_LENGTH 16 +#define MAX_STATUS_LENGTH 32 + + +#define COMMAND_INFO_OK_ID 100 +#define COMMAND_INFO_OK "OK" +#define COMMAND_INFO_OK_WITH_TEXT_ID 101 +#define COMMAND_INFO_OK_WITH_TEXT "OK WITH TEXT" +#define COMMAND_INFO_XMODEM_WAIT_ID 110 +#define COMMAND_INFO_XMODEM_WAIT "WAITING FOR XMODEM" +#define COMMAND_INFO_FALSE_ID 120 +#define COMMAND_INFO_FALSE "FALSE" +#define COMMAND_INFO_TRUE_ID 121 +#define COMMAND_INFO_TRUE "TRUE" +#define COMMAND_ERR_UNKNOWN_CMD_ID 200 +#define COMMAND_ERR_UNKNOWN_CMD "UNKNOWN COMMAND" +#define COMMAND_ERR_INVALID_USAGE_ID 201 +#define COMMAND_ERR_INVALID_USAGE "INVALID COMMAND USAGE" +#define COMMAND_ERR_INVALID_PARAM_ID 202 +#define COMMAND_ERR_INVALID_PARAM "INVALID PARAMETER" +#define COMMAND_ERR_TIMEOUT_ID 203 +#define COMMAND_ERR_TIMEOUT "TIMEOUT" +#define TIMEOUT_COMMAND 255 // this is just for the CommandLine module to know that this is a timeout command + + +#define COMMAND_CHAR_TRUE '1' +#define COMMAND_CHAR_FALSE '0' +#define COMMAND_CHAR_SUGGEST '?' /* =? for help */ + +#define COMMAND_UID_BUFSIZE 32 + +#define COMMAND_IS_SUGGEST_STRING(x) ( ((x)[0] == COMMAND_CHAR_SUGGEST) && ((x)[1] == '\0') ) + +typedef uint8_t CommandStatusIdType; +typedef const char CommandStatusMessageType[MAX_STATUS_LENGTH]; + +typedef CommandStatusIdType (*CommandExecFuncType) (char* OutMessage); +typedef CommandStatusIdType (*CommandExecParamFuncType) (char* OutMessage, const char* InParams); +typedef CommandStatusIdType (*CommandSetFuncType) (char* OutMessage, const char* InParam); +typedef CommandStatusIdType (*CommandGetFuncType) (char* OutParam); + +typedef struct { + char Command[MAX_COMMAND_LENGTH]; + CommandExecFuncType ExecFunc; + CommandExecParamFuncType ExecParamFunc; + CommandSetFuncType SetFunc; + CommandGetFuncType GetFunc; +} CommandEntryType; + +#define COMMAND_VERSION "VERSION" +CommandStatusIdType CommandGetVersion(char* OutParam); + +#define COMMAND_CONFIG "CONFIG" +CommandStatusIdType CommandGetConfig(char* OutParam); +CommandStatusIdType CommandSetConfig(char* OutMessage, const char* InParam); + +#define COMMAND_UID "UID" +#define COMMAND_UID_RANDOM "RANDOM" +CommandStatusIdType CommandGetUid(char* OutParam); +CommandStatusIdType CommandSetUid(char* OutMessage, const char* InParam); + +#define COMMAND_READONLY "READONLY" +CommandStatusIdType CommandGetReadOnly(char* OutParam); +CommandStatusIdType CommandSetReadOnly(char* OutMessage, const char* InParam); + +#define COMMAND_UPLOAD "UPLOAD" +CommandStatusIdType CommandExecUpload(char* OutMessage); + +#define COMMAND_DOWNLOAD "DOWNLOAD" +CommandStatusIdType CommandExecDownload(char* OutMessage); + +#define COMMAND_RESET "RESET" +CommandStatusIdType CommandExecReset(char* OutMessage); + +#define COMMAND_UPGRADE "UPGRADE" +CommandStatusIdType CommandExecUpgrade(char* OutMessage); + +#define COMMAND_MEMSIZE "MEMSIZE" +CommandStatusIdType CommandGetMemSize(char* OutParam); + +#define COMMAND_UIDSIZE "UIDSIZE" +CommandStatusIdType CommandGetUidSize(char* OutParam); + +#define COMMAND_RBUTTON "RBUTTON" +CommandStatusIdType CommandGetRButton(char* OutParam); +CommandStatusIdType CommandSetRButton(char* OutMessage, const char* InParam); + +#define COMMAND_RBUTTON_LONG "RBUTTON_LONG" +CommandStatusIdType CommandGetRButtonLong(char* OutParam); +CommandStatusIdType CommandSetRButtonLong(char* OutMessage, const char* InParam); + +#define COMMAND_LBUTTON "LBUTTON" +CommandStatusIdType CommandGetLButton(char* OutParam); +CommandStatusIdType CommandSetLButton(char* OutMessage, const char* InParam); + +#define COMMAND_LBUTTON_LONG "LBUTTON_LONG" +CommandStatusIdType CommandGetLButtonLong(char* OutParam); +CommandStatusIdType CommandSetLButtonLong(char* OutMessage, const char* InParam); + + +#define COMMAND_LEDGREEN "LEDGREEN" +CommandStatusIdType CommandGetLedGreen(char* OutParam); +CommandStatusIdType CommandSetLedGreen(char* OutMessage, const char* InParam); + +#define COMMAND_LEDRED "LEDRED" +CommandStatusIdType CommandGetLedRed(char* OutParam); +CommandStatusIdType CommandSetLedRed(char* OutMessage, const char* InParam); + +#define COMMAND_LOGMODE "LOGMODE" +CommandStatusIdType CommandGetLogMode(char* OutParam); +CommandStatusIdType CommandSetLogMode(char* OutMessage, const char* InParam); + +#define COMMAND_LOGMEM "LOGMEM" +CommandStatusIdType CommandGetLogMem(char* OutParam); + +#define COMMAND_LOGDOWNLOAD "LOGDOWNLOAD" +CommandStatusIdType CommandExecLogDownload(char* OutMessage); + +#define COMMAND_STORELOG "LOGSTORE" +CommandStatusIdType CommandExecStoreLog(char* OutMessage); + +#define COMMAND_LOGCLEAR "LOGCLEAR" +CommandStatusIdType CommandExecLogClear(char* OutMessage); + +#define COMMAND_SETTING "SETTING" +CommandStatusIdType CommandGetSetting(char* OutParam); +CommandStatusIdType CommandSetSetting(char* OutMessage, const char* InParam); + +#define COMMAND_CLEAR "CLEAR" +CommandStatusIdType CommandExecClear(char* OutMessage); + +#define COMMAND_STORE "STORE" +CommandStatusIdType CommandExecStore(char* OutMessage); + +#define COMMAND_RECALL "RECALL" +CommandStatusIdType CommandExecRecall(char* OutMessage); + +#define COMMAND_CHARGING "CHARGING" +CommandStatusIdType CommandGetCharging(char* OutParam); + +#define COMMAND_HELP "HELP" +CommandStatusIdType CommandExecHelp(char* OutMessage); + +#define COMMAND_RSSI "RSSI" +CommandStatusIdType CommandGetRssi(char* OutParam); + +#define COMMAND_SYSTICK "SYSTICK" +CommandStatusIdType CommandGetSysTick(char* OutParam); + +#define COMMAND_SEND_RAW "SEND_RAW" +CommandStatusIdType CommandExecParamSendRaw(char* OutMessage, const char* InParams); + +#define COMMAND_SEND "SEND" +CommandStatusIdType CommandExecParamSend(char* OutMessage, const char* InParams); + +#define COMMAND_GETUID "GETUID" +CommandStatusIdType CommandExecGetUid(char* OutMessage); + +#define COMMAND_DUMP_MFU "DUMP_MFU" +CommandStatusIdType CommandExecDumpMFU(char* OutMessage); + +#define COMMAND_IDENTIFY_CARD "IDENTIFY" +CommandStatusIdType CommandExecIdentifyCard(char* OutMessage); + +#define COMMAND_TIMEOUT "TIMEOUT" +CommandStatusIdType CommandGetTimeout(char* OutMessage); +CommandStatusIdType CommandSetTimeout(char* OutMessage, const char* InParam); + +#define COMMAND_THRESHOLD "THRESHOLD" +CommandStatusIdType CommandGetThreshold(char* OutParam); +CommandStatusIdType CommandSetThreshold(char* OutMessage, const char* InParam); + +#define COMMAND_FIELD "FIELD" +CommandStatusIdType CommandSetField(char* OutMessage, const char* InParam); +CommandStatusIdType CommandGetField(char* OutMessage); + +#define COMMAND_LIST_END "" +/* Defines the end of command list. This is no actual command */ + +#endif /* COMMANDS_H_ */ diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.c b/Firmware/Chameleon-Mini/Terminal/Terminal.c new file mode 100644 index 00000000..9b779986 --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.c @@ -0,0 +1,170 @@ + +#include "Terminal.h" +#include "../System.h" +#include "../LEDHook.h" + +#include "../LUFADescriptors.h" + +#define INIT_DELAY (2000 / SYSTEM_TICK_MS) + + +USB_ClassInfo_CDC_Device_t TerminalHandle = { + .Config = { + .ControlInterfaceNumber = 0, + .DataINEndpoint = { + .Address = CDC_TX_EPADDR, + .Size = CDC_TXRX_EPSIZE, + .Banks = 1, + }, .DataOUTEndpoint = { + .Address = CDC_RX_EPADDR, + .Size = CDC_TXRX_EPSIZE, + .Banks = 1, + }, .NotificationEndpoint = { + .Address = CDC_NOTIFICATION_EPADDR, + .Size = CDC_NOTIFICATION_EPSIZE, + .Banks = 1, + }, + } +}; + +uint8_t TerminalBuffer[TERMINAL_BUFFER_SIZE]; +TerminalStateEnum TerminalState = TERMINAL_UNINITIALIZED; +static uint8_t TerminalInitDelay = INIT_DELAY; + +void TerminalSendString(const char* s) { + CDC_Device_SendString(&TerminalHandle, s); +} + +void TerminalSendStringP(const char* s) { + char c; + + while( (c = pgm_read_byte(s++)) != '\0' ) { + TerminalSendChar(c); + } +} + +/* +void TerminalSendHex(void* Buffer, uint16_t ByteCount) +{ + char* pTerminalBuffer = (char*) TerminalBuffer; + + BufferToHexString(pTerminalBuffer, sizeof(TerminalBuffer), Buffer, ByteCount); + + TerminalSendString(pTerminalBuffer); +} + +*/ + + +void TerminalSendBlock(const void* Buffer, uint16_t ByteCount) +{ + CDC_Device_SendData(&TerminalHandle, Buffer, ByteCount); +} + + +static void ProcessByte(void) { + int16_t Byte = CDC_Device_ReceiveByte(&TerminalHandle); + + if (Byte >= 0) { + /* Byte received */ + LEDHook(LED_TERMINAL_RXTX, LED_PULSE); + + if (XModemProcessByte(Byte)) { + /* XModem handled the byte */ + } else if (CommandLineProcessByte(Byte)) { + /* CommandLine handled the byte */ + } + } +} + +static void SenseVBus(void) +{ + switch(TerminalState) { + case TERMINAL_UNINITIALIZED: + if (TERMINAL_VBUS_PORT.IN & TERMINAL_VBUS_MASK) { + /* Not initialized and VBUS sense high */ + TerminalInitDelay = INIT_DELAY; + TerminalState = TERMINAL_INITIALIZING; + } + break; + + case TERMINAL_INITIALIZING: + if (--TerminalInitDelay == 0) { + SystemStartUSBClock(); + USB_Init(); + TerminalState = TERMINAL_INITIALIZED; + } + break; + + case TERMINAL_INITIALIZED: + if (!(TERMINAL_VBUS_PORT.IN & TERMINAL_VBUS_MASK)) { + /* Initialized and VBUS sense low */ + TerminalInitDelay = INIT_DELAY; + TerminalState = TERMINAL_UNITIALIZING; + } + break; + + case TERMINAL_UNITIALIZING: + if (--TerminalInitDelay == 0) { + USB_Disable(); + SystemStopUSBClock(); + TerminalState = TERMINAL_UNINITIALIZED; + } + break; + + default: + break; + } +} + +void TerminalInit(void) +{ + TERMINAL_VBUS_PORT.DIRCLR = TERMINAL_VBUS_MASK; +} + +void TerminalTask(void) +{ + if (TerminalState == TERMINAL_INITIALIZED) { + CDC_Device_USBTask(&TerminalHandle); + USB_USBTask(); + + ProcessByte(); + } +} + +void TerminalTick(void) +{ + SenseVBus(); + + if (TerminalState == TERMINAL_INITIALIZED) { + XModemTick(); + CommandLineTick(); + } +} + +/** Event handler for the library USB Connection event. */ +void EVENT_USB_Device_Connect(void) +{ + LEDHook(LED_TERMINAL_CONN, LED_ON); +} + +/** Event handler for the library USB Disconnection event. */ +void EVENT_USB_Device_Disconnect(void) +{ + LEDHook(LED_TERMINAL_CONN, LED_OFF); +} + + +/** Event handler for the library USB Configuration Changed event. */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + CDC_Device_ConfigureEndpoints(&TerminalHandle); +} + +/** Event handler for the library USB Control Request reception event. */ +void EVENT_USB_Device_ControlRequest(void) +{ + CDC_Device_ProcessControlRequest(&TerminalHandle); +} + + diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.h b/Firmware/Chameleon-Mini/Terminal/Terminal.h new file mode 100644 index 00000000..47e40694 --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.h @@ -0,0 +1,52 @@ +/* + * CommandLine.h + * + * Created on: 10.02.2013 + * Author: skuser + */ + +#ifndef TERMINAL_H_ +#define TERMINAL_H_ + +#include "../Common.h" +#include "../LUFA/Drivers/USB/USB.h" +#include "XModem.h" +#include "CommandLine.h" + +#define TERMINAL_VBUS_PORT PORTD +#define TERMINAL_VBUS_MASK PIN5_bm + +#define TERMINAL_BUFFER_SIZE 512 + +typedef enum { + TERMINAL_UNINITIALIZED, + TERMINAL_INITIALIZING, + TERMINAL_INITIALIZED, + TERMINAL_UNITIALIZING +} TerminalStateEnum; + +extern uint8_t TerminalBuffer[TERMINAL_BUFFER_SIZE]; +extern USB_ClassInfo_CDC_Device_t TerminalHandle; +extern TerminalStateEnum TerminalState; + +void TerminalInit(void); +void TerminalTask(void); +void TerminalTick(void); + +/*void TerminalSendHex(void* Buffer, uint16_t ByteCount);*/ +INLINE void TerminalSendByte(uint8_t Byte); +void TerminalSendBlock(const void* Buffer, uint16_t ByteCount); + +INLINE void TerminalSendChar(char c); +void TerminalSendString(const char* s); +void TerminalSendStringP(const char* s); + +void EVENT_USB_Device_Connect(void); +void EVENT_USB_Device_Disconnect(void); +void EVENT_USB_Device_ConfigurationChanged(void); +void EVENT_USB_Device_ControlRequest(void); + +INLINE void TerminalSendChar(char c) { CDC_Device_SendByte(&TerminalHandle, c); } +INLINE void TerminalSendByte(uint8_t Byte) { CDC_Device_SendByte(&TerminalHandle, Byte); } + +#endif /* TERMINAL_H_ */ diff --git a/Firmware/Chameleon-Mini/Terminal/XModem.c b/Firmware/Chameleon-Mini/Terminal/XModem.c new file mode 100644 index 00000000..6ea379f4 --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/XModem.c @@ -0,0 +1,248 @@ +#include "XModem.h" +#include "Terminal.h" + +#define BYTE_NAK 0x15 +#define BYTE_SOH 0x01 +#define BYTE_ACK 0x06 +#define BYTE_CAN 0x18 +#define BYTE_EOF 0x1A +#define BYTE_EOT 0x04 +#define BYTE_ESC 0x1B + +#define XMODEM_BLOCK_SIZE 128 + +#define RECV_INIT_TIMEOUT 5 /* #Ticks between sending of NAKs to the sender */ +#define RECV_INIT_COUNT 60 /* #Timeouts until receive failure */ +#define SEND_INIT_TIMEOUT 300 /* #Ticks waiting for NAKs from the receiver before failure */ + +#define FIRST_FRAME_NUMBER 1 +#define CHECKSUM_INIT_VALUE 0 + +static enum { + STATE_OFF, + STATE_RECEIVE_INIT, + STATE_RECEIVE_WAIT, + STATE_RECEIVE_FRAMENUM1, + STATE_RECEIVE_FRAMENUM2, + STATE_RECEIVE_DATA, + STATE_RECEIVE_PROCESS, + STATE_SEND_INIT, + STATE_SEND_WAIT, + STATE_SEND_EOT +} State = STATE_OFF; + +static uint8_t CurrentFrameNumber; +static uint8_t ReceivedFrameNumber; +static uint8_t Checksum; +static uint8_t RetryCount; +static uint16_t RetryTimeout; +static uint16_t BufferIdx; +static uint32_t BlockAddress; + +static XModemCallbackType CallbackFunc; + +static uint8_t CalcChecksum(const void* Buffer, uint16_t ByteCount) { + uint8_t Checksum = CHECKSUM_INIT_VALUE; + uint8_t* DataPtr = (uint8_t*) Buffer; + + while(ByteCount--) { + Checksum += *DataPtr++; + } + + return Checksum; +} + +void XModemReceive(XModemCallbackType TheCallbackFunc) +{ + State = STATE_RECEIVE_INIT; + CurrentFrameNumber = FIRST_FRAME_NUMBER; + RetryCount = RECV_INIT_COUNT; + RetryTimeout = RECV_INIT_TIMEOUT; + BlockAddress = 0; + + CallbackFunc = TheCallbackFunc; +} + +void XModemSend(XModemCallbackType TheCallbackFunc) +{ + State = STATE_SEND_INIT; + RetryTimeout = SEND_INIT_TIMEOUT; + BlockAddress = 0; + + CallbackFunc = TheCallbackFunc; +} + +bool XModemProcessByte(uint8_t Byte) +{ + switch(State) { + case STATE_RECEIVE_INIT: + case STATE_RECEIVE_WAIT: + if (Byte == BYTE_SOH) { + /* Next frame incoming */ + BufferIdx = 0; + Checksum = CHECKSUM_INIT_VALUE; + State = STATE_RECEIVE_FRAMENUM1; + } else if (Byte == BYTE_EOT) { + /* Transmission finished */ + TerminalSendByte(BYTE_ACK); + State = STATE_OFF; + } else if ( (Byte == BYTE_CAN) || (Byte == BYTE_ESC) ) { + /* Cancel transmission */ + State = STATE_OFF; + } else { + /* Ignore other bytes */ + } + + break; + + case STATE_RECEIVE_FRAMENUM1: + /* Store frame number */ + ReceivedFrameNumber = Byte; + State = STATE_RECEIVE_FRAMENUM2; + break; + + case STATE_RECEIVE_FRAMENUM2: + if (Byte == (255 - ReceivedFrameNumber)) { + /* frame-number check passed. */ + State = STATE_RECEIVE_DATA; + } else { + /* Something went wrong. Try to recover by sending NAK */ + TerminalSendByte(BYTE_NAK); + State = STATE_RECEIVE_WAIT; + } + + break; + + case STATE_RECEIVE_DATA: + /* Process byte and update checksum */ + TerminalBuffer[BufferIdx++] = Byte; + + if (BufferIdx == XMODEM_BLOCK_SIZE) { + /* Block full */ + State = STATE_RECEIVE_PROCESS; + } + + break; + + case STATE_RECEIVE_PROCESS: + if (ReceivedFrameNumber == CurrentFrameNumber) { + /* This is the expected frame. Calculate and verify checksum */ + + if (CalcChecksum(TerminalBuffer, XMODEM_BLOCK_SIZE) == Byte) { + /* Checksum is valid. Pass received data to callback function */ + if (CallbackFunc(TerminalBuffer, BlockAddress, XMODEM_BLOCK_SIZE)) { + /* Proceed to next frame and send ACK */ + CurrentFrameNumber++; + BlockAddress += XMODEM_BLOCK_SIZE; + TerminalSendChar(BYTE_ACK); + State = STATE_RECEIVE_WAIT; + } else { + /* Application signals to cancel the transmission */ + TerminalSendByte(BYTE_CAN); + TerminalSendByte(BYTE_CAN); + State = STATE_OFF; + } + } else { + /* Data seems to be damaged */ + TerminalSendByte(BYTE_NAK); + State = STATE_RECEIVE_WAIT; + } + } else if (ReceivedFrameNumber == (CurrentFrameNumber - 1)) { + /* This is a retransmission */ + TerminalSendByte(BYTE_ACK); + State = STATE_RECEIVE_WAIT; + } else { + /* This frame is completely out of order. Just cancel */ + TerminalSendByte(BYTE_CAN); + State = STATE_OFF; + } + + break; + + case STATE_SEND_INIT: + /* Start sending on NAK */ + if (Byte == BYTE_NAK) { + CurrentFrameNumber = FIRST_FRAME_NUMBER - 1; + Byte = BYTE_ACK; + } else if (Byte == BYTE_ESC) { + State = STATE_OFF; + } + + /* Fallthrough */ + + case STATE_SEND_WAIT: + if (Byte == BYTE_CAN) { + /* Cancel */ + TerminalSendByte(BYTE_ACK); + State = STATE_OFF; + } else if (Byte == BYTE_ACK) { + /* Acknowledge. Proceed to next frame, get data and calc checksum */ + CurrentFrameNumber++; + + if (CallbackFunc(TerminalBuffer, BlockAddress, XMODEM_BLOCK_SIZE)) { + TerminalSendByte(BYTE_SOH); + TerminalSendByte(CurrentFrameNumber); + TerminalSendByte(255 - CurrentFrameNumber); + TerminalSendBlock(TerminalBuffer, XMODEM_BLOCK_SIZE); + TerminalSendByte(CalcChecksum(TerminalBuffer, XMODEM_BLOCK_SIZE)); + + BlockAddress += XMODEM_BLOCK_SIZE; + } else { + TerminalSendByte(BYTE_EOT); + State = STATE_SEND_EOT; + } + } else if (Byte == BYTE_NAK){ + /* Resend frame */ + TerminalSendByte(BYTE_SOH); + TerminalSendByte(CurrentFrameNumber); + TerminalSendByte(255 - CurrentFrameNumber); + TerminalSendBlock(TerminalBuffer, XMODEM_BLOCK_SIZE); + TerminalSendByte(CalcChecksum(TerminalBuffer, XMODEM_BLOCK_SIZE)); + } else { + /* Ignore other chars */ + } + + break; + + case STATE_SEND_EOT: + /* Receive Ack */ + State = STATE_OFF; + break; + + default: + return false; + break; + } + + return true; +} + +void XModemTick(void) +{ + /* Timeouts go here */ + switch(State) { + case STATE_RECEIVE_INIT: + if (RetryTimeout-- == 0) { + if (RetryCount-- > 0) { + /* Put out communication request */ + TerminalSendChar(BYTE_NAK); + } else { + /* Just shut off after some time. */ + State = STATE_OFF; + } + + RetryTimeout = RECV_INIT_TIMEOUT; + } + break; + + case STATE_SEND_INIT: + if (RetryTimeout-- == 0) { + /* Abort */ + State = STATE_OFF; + } + break; + + default: + break; + } +} diff --git a/Firmware/Chameleon-Mini/Terminal/XModem.h b/Firmware/Chameleon-Mini/Terminal/XModem.h new file mode 100644 index 00000000..ac839b4e --- /dev/null +++ b/Firmware/Chameleon-Mini/Terminal/XModem.h @@ -0,0 +1,21 @@ +/* + * TerminalXModem.h + * + * Created on: 22.03.2013 + * Author: skuser + */ + +#ifndef XMODEM_H_ +#define XMODEM_H_ + +#include "../Common.h" + +typedef bool (*XModemCallbackType) (void* ByteBuffer, uint32_t BlockAddress, uint16_t ByteCount); + +void XModemReceive(XModemCallbackType CallbackFunc); +void XModemSend(XModemCallbackType CallbackFunc); + +bool XModemProcessByte(uint8_t Byte); +void XModemTick(void); + +#endif /* TERMINALXMODEM_H_ */ diff --git a/Firmware/LUFA/.gitignore b/Firmware/LUFA/.gitignore new file mode 100644 index 00000000..9f9d3949 --- /dev/null +++ b/Firmware/LUFA/.gitignore @@ -0,0 +1,15 @@ +*.o +*.d +*.elf +*.hex +*.eep +*.sym +*.bin +*.lss +*.map +*.bak +*.class +Documentation/ +LUFA/StudioIntegration/ProjectGenerator/* +LUFA/StudioIntegration/DocBook/* +!LUFA/StudioIntegration/Docbook/mshelp/* diff --git a/Firmware/LUFA/Bootloaders/CDC/BootloaderAPI.c b/Firmware/LUFA/Bootloaders/CDC/BootloaderAPI.c new file mode 100644 index 00000000..7dd75301 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/BootloaderAPI.c @@ -0,0 +1,75 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Bootloader user application API functions. + */ + +#include "BootloaderAPI.h" + +void BootloaderAPI_ErasePage(const uint32_t Address) +{ + boot_page_erase_safe(Address); + boot_spm_busy_wait(); + boot_rww_enable(); +} + +void BootloaderAPI_WritePage(const uint32_t Address) +{ + boot_page_write_safe(Address); + boot_spm_busy_wait(); + boot_rww_enable(); +} + +void BootloaderAPI_FillWord(const uint32_t Address, const uint16_t Word) +{ + boot_page_fill_safe(Address, Word); +} + +uint8_t BootloaderAPI_ReadSignature(const uint16_t Address) +{ + return boot_signature_byte_get(Address); +} + +uint8_t BootloaderAPI_ReadFuse(const uint16_t Address) +{ + return boot_lock_fuse_bits_get(Address); +} + +uint8_t BootloaderAPI_ReadLock(void) +{ + return boot_lock_fuse_bits_get(GET_LOCK_BITS); +} + +void BootloaderAPI_WriteLock(const uint8_t LockBits) +{ + boot_lock_bits_set_safe(LockBits); +} diff --git a/Firmware/LUFA/Bootloaders/CDC/BootloaderAPI.h b/Firmware/LUFA/Bootloaders/CDC/BootloaderAPI.h new file mode 100644 index 00000000..c8984485 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/BootloaderAPI.h @@ -0,0 +1,58 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for BootloaderAPI.c. + */ + +#ifndef _BOOTLOADER_API_H_ +#define _BOOTLOADER_API_H_ + + /* Includes: */ + #include + #include + #include + + #include + + #include "Config/AppConfig.h" + + /* Function Prototypes: */ + void BootloaderAPI_ErasePage(const uint32_t Address); + void BootloaderAPI_WritePage(const uint32_t Address); + void BootloaderAPI_FillWord(const uint32_t Address, const uint16_t Word); + uint8_t BootloaderAPI_ReadSignature(const uint16_t Address); + uint8_t BootloaderAPI_ReadFuse(const uint16_t Address); + uint8_t BootloaderAPI_ReadLock(void); + void BootloaderAPI_WriteLock(const uint8_t LockBits); + +#endif + diff --git a/Firmware/LUFA/Bootloaders/CDC/BootloaderAPITable.S b/Firmware/LUFA/Bootloaders/CDC/BootloaderAPITable.S new file mode 100644 index 00000000..fa83ce2a --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/BootloaderAPITable.S @@ -0,0 +1,91 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +; Trampolines to actual API implementations if the target address is outside the +; range of a rjmp instruction (can happen with large bootloader sections) +.section .apitable_trampolines, "ax" +.global BootloaderAPI_Trampolines +BootloaderAPI_Trampolines: + + BootloaderAPI_ErasePage_Trampoline: + jmp BootloaderAPI_ErasePage + BootloaderAPI_WritePage_Trampoline: + jmp BootloaderAPI_WritePage + BootloaderAPI_FillWord_Trampoline: + jmp BootloaderAPI_FillWord + BootloaderAPI_ReadSignature_Trampoline: + jmp BootloaderAPI_ReadSignature + BootloaderAPI_ReadFuse_Trampoline: + jmp BootloaderAPI_ReadFuse + BootloaderAPI_ReadLock_Trampoline: + jmp BootloaderAPI_ReadLock + BootloaderAPI_WriteLock_Trampoline: + jmp BootloaderAPI_WriteLock + BootloaderAPI_UNUSED1: + ret + BootloaderAPI_UNUSED2: + ret + BootloaderAPI_UNUSED3: + ret + BootloaderAPI_UNUSED4: + ret + BootloaderAPI_UNUSED5: + ret + + + +; API function jump table +.section .apitable_jumptable, "ax" +.global BootloaderAPI_JumpTable +BootloaderAPI_JumpTable: + + rjmp BootloaderAPI_ErasePage_Trampoline + rjmp BootloaderAPI_WritePage_Trampoline + rjmp BootloaderAPI_FillWord_Trampoline + rjmp BootloaderAPI_ReadSignature_Trampoline + rjmp BootloaderAPI_ReadFuse_Trampoline + rjmp BootloaderAPI_ReadLock_Trampoline + rjmp BootloaderAPI_WriteLock_Trampoline + rjmp BootloaderAPI_UNUSED1 ; UNUSED ENTRY 1 + rjmp BootloaderAPI_UNUSED2 ; UNUSED ENTRY 2 + rjmp BootloaderAPI_UNUSED3 ; UNUSED ENTRY 3 + rjmp BootloaderAPI_UNUSED4 ; UNUSED ENTRY 4 + rjmp BootloaderAPI_UNUSED5 ; UNUSED ENTRY 5 + + + +; Bootloader table signatures and information +.section .apitable_signatures, "ax" +.global BootloaderAPI_Signatures +BootloaderAPI_Signatures: + + .long BOOT_START_ADDR ; Start address of the bootloader + .word 0xDF00 ; Signature for the CDC class bootloader + .word 0xDCFB ; Signature for a LUFA class bootloader diff --git a/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.c b/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.c new file mode 100644 index 00000000..cb6a980c --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.c @@ -0,0 +1,674 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Main source file for the CDC class bootloader. This file contains the complete bootloader logic. + */ + +#define INCLUDE_FROM_BOOTLOADERCDC_C +#include "BootloaderCDC.h" + +/** Contains the current baud rate and other settings of the first virtual serial port. This must be retained as some + * operating systems will not open the port unless the settings can be set successfully. + */ +static CDC_LineEncoding_t LineEncoding = { .BaudRateBPS = 0, + .CharFormat = CDC_LINEENCODING_OneStopBit, + .ParityType = CDC_PARITY_None, + .DataBits = 8 }; + +/** Current address counter. This stores the current address of the FLASH or EEPROM as set by the host, + * and is used when reading or writing to the AVRs memory (either FLASH or EEPROM depending on the issued + * command.) + */ +static uint32_t CurrAddress; + +/** Flag to indicate if the bootloader should be running, or should exit and allow the application code to run + * via a watchdog reset. When cleared the bootloader will exit, starting the watchdog and entering an infinite + * loop until the AVR restarts and the application runs. + */ +static bool RunBootloader = true; + +/** Magic lock for forced application start. If the HWBE fuse is programmed and BOOTRST is unprogrammed, the bootloader + * will start if the /HWB line of the AVR is held low and the system is reset. However, if the /HWB line is still held + * low when the application attempts to start via a watchdog reset, the bootloader will re-start. If set to the value + * \ref MAGIC_BOOT_KEY the special init function \ref Application_Jump_Check() will force the application to start. + */ +uint16_t MagicBootKey ATTR_NO_INIT; + + +/** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application + * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, + * this will force the user application to start via a software jump. + */ +void Application_Jump_Check(void) +{ + bool JumpToApplication = false; + + #if (BOARD == BOARD_LEONARDO) + /* Enable pull-up on the IO13 pin so we can use it to select the mode */ + PORTC |= (1 << 7); + Delay_MS(10); + + /* If IO13 is not jumpered to ground, start the user application instead */ + JumpToApplication = ((PINC & (1 << 7)) != 0); + + /* Disable pull-up after the check has completed */ + PORTC &= ~(1 << 7); + #elif ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) + /* Disable JTAG debugging */ + JTAG_DISABLE(); + + /* Enable pull-up on the JTAG TCK pin so we can use it to select the mode */ + PORTF |= (1 << 4); + Delay_MS(10); + + /* If the TCK pin is not jumpered to ground, start the user application instead */ + JumpToApplication = ((PINF & (1 << 4)) != 0); + + /* Re-enable JTAG debugging */ + JTAG_ENABLE(); + #else + /* Check if the device's BOOTRST fuse is set */ + if (boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS) & FUSE_BOOTRST) + { + /* If the reset source was not an external reset or the key is correct, clear it and jump to the application */ + if (!(MCUSR & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY)) + JumpToApplication = true; + + /* Clear reset source */ + MCUSR &= ~(1 << EXTRF); + } + else + { + /* If the reset source was the bootloader and the key is correct, clear it and jump to the application; + * this can happen in the HWBE fuse is set, and the HBE pin is low during the watchdog reset */ + if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) + JumpToApplication = true; + + /* Clear reset source */ + MCUSR &= ~(1 << WDRF); + } + #endif + + /* Don't run the user application if the reset vector is blank (no app loaded) */ + bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF); + + /* If a request has been made to jump to the user application, honor it */ + if (JumpToApplication && ApplicationValid) + { + /* Turn off the watchdog */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Clear the boot key and jump to the user application */ + MagicBootKey = 0; + + // cppcheck-suppress constStatement + ((void (*)(void))0x0000)(); + } +} + +/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously + * runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start + * the loaded application code. + */ +int main(void) +{ + /* Setup hardware required for the bootloader */ + SetupHardware(); + + /* Turn on first LED on the board to indicate that the bootloader has started */ + LEDs_SetAllLEDs(LEDS_LED1); + + /* Enable global interrupts so that the USB stack can function */ + GlobalInterruptEnable(); + + while (RunBootloader) + { + CDC_Task(); + USB_USBTask(); + } + + /* Wait a short time to end all USB transactions and then disconnect */ + _delay_us(1000); + + /* Disconnect from the host - USB interface will be reset later along with the AVR */ + USB_Detach(); + + /* Unlock the forced application start mode of the bootloader if it is restarted */ + MagicBootKey = MAGIC_BOOT_KEY; + + /* Enable the watchdog and force a timeout to reset the AVR */ + wdt_enable(WDTO_250MS); + + for (;;); +} + +/** Configures all hardware required for the bootloader. */ +static void SetupHardware(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + /* Relocate the interrupt vector table to the bootloader section */ + MCUCR = (1 << IVCE); + MCUCR = (1 << IVSEL); + + /* Initialize the USB and other board hardware drivers */ + USB_Init(); + LEDs_Init(); + + /* Bootloader active LED toggle timer initialization */ + TIMSK1 = (1 << TOIE1); + TCCR1B = ((1 << CS11) | (1 << CS10)); +} + +/** ISR to periodically toggle the LEDs on the board to indicate that the bootloader is active. */ +ISR(TIMER1_OVF_vect, ISR_BLOCK) +{ + LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2); +} + +/** Event handler for the USB_ConfigurationChanged event. This configures the device's endpoints ready + * to relay data to and from the attached USB host. + */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + /* Setup CDC Notification, Rx and Tx Endpoints */ + Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPADDR, EP_TYPE_INTERRUPT, + CDC_NOTIFICATION_EPSIZE, 1); + + Endpoint_ConfigureEndpoint(CDC_TX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1); + + Endpoint_ConfigureEndpoint(CDC_RX_EPADDR, EP_TYPE_BULK, CDC_TXRX_EPSIZE, 1); +} + +/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to + * the device from the USB host before passing along unhandled control requests to the library for processing + * internally. + */ +void EVENT_USB_Device_ControlRequest(void) +{ + /* Ignore any requests that aren't directed to the CDC interface */ + if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) != + (REQTYPE_CLASS | REQREC_INTERFACE)) + { + return; + } + + /* Activity - toggle indicator LEDs */ + LEDs_ToggleLEDs(LEDS_LED1 | LEDS_LED2); + + /* Process CDC specific control requests */ + switch (USB_ControlRequest.bRequest) + { + case CDC_REQ_GetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + /* Write the line coding data to the control endpoint */ + Endpoint_Write_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t)); + Endpoint_ClearOUT(); + } + + break; + case CDC_REQ_SetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + /* Read the line coding data in from the host into the global struct */ + Endpoint_Read_Control_Stream_LE(&LineEncoding, sizeof(CDC_LineEncoding_t)); + Endpoint_ClearIN(); + } + + break; + case CDC_REQ_SetControlLineState: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_ClearStatusStage(); + } + + break; + } +} + +#if !defined(NO_BLOCK_SUPPORT) +/** Reads or writes a block of EEPROM or FLASH memory to or from the appropriate CDC data endpoint, depending + * on the AVR109 protocol command issued. + * + * \param[in] Command Single character AVR109 protocol command indicating what memory operation to perform + */ +static void ReadWriteMemoryBlock(const uint8_t Command) +{ + uint16_t BlockSize; + char MemoryType; + + uint8_t HighByte = 0; + uint8_t LowByte = 0; + + BlockSize = (FetchNextCommandByte() << 8); + BlockSize |= FetchNextCommandByte(); + + MemoryType = FetchNextCommandByte(); + + if ((MemoryType != MEMORY_TYPE_FLASH) && (MemoryType != MEMORY_TYPE_EEPROM)) + { + /* Send error byte back to the host */ + WriteNextResponseByte('?'); + + return; + } + + /* Check if command is to read a memory block */ + if (Command == AVR109_COMMAND_BlockRead) + { + /* Re-enable RWW section */ + boot_rww_enable(); + + while (BlockSize--) + { + if (MemoryType == MEMORY_TYPE_FLASH) + { + /* Read the next FLASH byte from the current FLASH page */ + #if (FLASHEND > 0xFFFF) + WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte)); + #else + WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte)); + #endif + + /* If both bytes in current word have been read, increment the address counter */ + if (HighByte) + CurrAddress += 2; + + HighByte = !HighByte; + } + else + { + /* Read the next EEPROM byte into the endpoint */ + WriteNextResponseByte(eeprom_read_byte((uint8_t*)(intptr_t)(CurrAddress >> 1))); + + /* Increment the address counter after use */ + CurrAddress += 2; + } + } + } + else + { + uint32_t PageStartAddress = CurrAddress; + + if (MemoryType == MEMORY_TYPE_FLASH) + { + boot_page_erase(PageStartAddress); + boot_spm_busy_wait(); + } + + while (BlockSize--) + { + if (MemoryType == MEMORY_TYPE_FLASH) + { + /* If both bytes in current word have been written, increment the address counter */ + if (HighByte) + { + /* Write the next FLASH word to the current FLASH page */ + boot_page_fill(CurrAddress, ((FetchNextCommandByte() << 8) | LowByte)); + + /* Increment the address counter after use */ + CurrAddress += 2; + } + else + { + LowByte = FetchNextCommandByte(); + } + + HighByte = !HighByte; + } + else + { + /* Write the next EEPROM byte from the endpoint */ + eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte()); + + /* Increment the address counter after use */ + CurrAddress += 2; + } + } + + /* If in FLASH programming mode, commit the page after writing */ + if (MemoryType == MEMORY_TYPE_FLASH) + { + /* Commit the flash page to memory */ + boot_page_write(PageStartAddress); + + /* Wait until write operation has completed */ + boot_spm_busy_wait(); + } + + /* Send response byte back to the host */ + WriteNextResponseByte('\r'); + } +} +#endif + +/** Retrieves the next byte from the host in the CDC data OUT endpoint, and clears the endpoint bank if needed + * to allow reception of the next data packet from the host. + * + * \return Next received byte from the host in the CDC data OUT endpoint + */ +static uint8_t FetchNextCommandByte(void) +{ + /* Select the OUT endpoint so that the next data byte can be read */ + Endpoint_SelectEndpoint(CDC_RX_EPADDR); + + /* If OUT endpoint empty, clear it and wait for the next packet from the host */ + while (!(Endpoint_IsReadWriteAllowed())) + { + Endpoint_ClearOUT(); + + while (!(Endpoint_IsOUTReceived())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return 0; + } + } + + /* Fetch the next byte from the OUT endpoint */ + return Endpoint_Read_8(); +} + +/** Writes the next response byte to the CDC data IN endpoint, and sends the endpoint back if needed to free up the + * bank when full ready for the next byte in the packet to the host. + * + * \param[in] Response Next response byte to send to the host + */ +static void WriteNextResponseByte(const uint8_t Response) +{ + /* Select the IN endpoint so that the next data byte can be written */ + Endpoint_SelectEndpoint(CDC_TX_EPADDR); + + /* If IN endpoint full, clear it and wait until ready for the next packet to the host */ + if (!(Endpoint_IsReadWriteAllowed())) + { + Endpoint_ClearIN(); + + while (!(Endpoint_IsINReady())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + } + + /* Write the next byte to the IN endpoint */ + Endpoint_Write_8(Response); +} + +/** Task to read in AVR109 commands from the CDC data OUT endpoint, process them, perform the required actions + * and send the appropriate response back to the host. + */ +static void CDC_Task(void) +{ + /* Select the OUT endpoint */ + Endpoint_SelectEndpoint(CDC_RX_EPADDR); + + /* Check if endpoint has a command in it sent from the host */ + if (!(Endpoint_IsOUTReceived())) + return; + + /* Read in the bootloader command (first byte sent from host) */ + uint8_t Command = FetchNextCommandByte(); + + if (Command == AVR109_COMMAND_ExitBootloader) + { + RunBootloader = false; + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if ((Command == AVR109_COMMAND_SetLED) || (Command == AVR109_COMMAND_ClearLED) || + (Command == AVR109_COMMAND_SelectDeviceType)) + { + FetchNextCommandByte(); + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if ((Command == AVR109_COMMAND_EnterProgrammingMode) || (Command == AVR109_COMMAND_LeaveProgrammingMode)) + { + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if (Command == AVR109_COMMAND_ReadPartCode) + { + /* Return ATMEGA128 part code - this is only to allow AVRProg to use the bootloader */ + WriteNextResponseByte(0x44); + WriteNextResponseByte(0x00); + } + else if (Command == AVR109_COMMAND_ReadAutoAddressIncrement) + { + /* Indicate auto-address increment is supported */ + WriteNextResponseByte('Y'); + } + else if (Command == AVR109_COMMAND_SetCurrentAddress) + { + /* Set the current address to that given by the host (translate 16-bit word address to byte address) */ + CurrAddress = (FetchNextCommandByte() << 9); + CurrAddress |= (FetchNextCommandByte() << 1); + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if (Command == AVR109_COMMAND_ReadBootloaderInterface) + { + /* Indicate serial programmer back to the host */ + WriteNextResponseByte('S'); + } + else if (Command == AVR109_COMMAND_ReadBootloaderIdentifier) + { + /* Write the 7-byte software identifier to the endpoint */ + for (uint8_t CurrByte = 0; CurrByte < 7; CurrByte++) + WriteNextResponseByte(SOFTWARE_IDENTIFIER[CurrByte]); + } + else if (Command == AVR109_COMMAND_ReadBootloaderSWVersion) + { + WriteNextResponseByte('0' + BOOTLOADER_VERSION_MAJOR); + WriteNextResponseByte('0' + BOOTLOADER_VERSION_MINOR); + } + else if (Command == AVR109_COMMAND_ReadSignature) + { + WriteNextResponseByte(AVR_SIGNATURE_3); + WriteNextResponseByte(AVR_SIGNATURE_2); + WriteNextResponseByte(AVR_SIGNATURE_1); + } + else if (Command == AVR109_COMMAND_EraseFLASH) + { + /* Clear the application section of flash */ + for (uint32_t CurrFlashAddress = 0; CurrFlashAddress < (uint32_t)BOOT_START_ADDR; CurrFlashAddress += SPM_PAGESIZE) + { + boot_page_erase(CurrFlashAddress); + boot_spm_busy_wait(); + boot_page_write(CurrFlashAddress); + boot_spm_busy_wait(); + } + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + #if !defined(NO_LOCK_BYTE_WRITE_SUPPORT) + else if (Command == AVR109_COMMAND_WriteLockbits) + { + /* Set the lock bits to those given by the host */ + boot_lock_bits_set(FetchNextCommandByte()); + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + #endif + else if (Command == AVR109_COMMAND_ReadLockbits) + { + WriteNextResponseByte(boot_lock_fuse_bits_get(GET_LOCK_BITS)); + } + else if (Command == AVR109_COMMAND_ReadLowFuses) + { + WriteNextResponseByte(boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)); + } + else if (Command == AVR109_COMMAND_ReadHighFuses) + { + WriteNextResponseByte(boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)); + } + else if (Command == AVR109_COMMAND_ReadExtendedFuses) + { + WriteNextResponseByte(boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)); + } + #if !defined(NO_BLOCK_SUPPORT) + else if (Command == AVR109_COMMAND_GetBlockWriteSupport) + { + WriteNextResponseByte('Y'); + + /* Send block size to the host */ + WriteNextResponseByte(SPM_PAGESIZE >> 8); + WriteNextResponseByte(SPM_PAGESIZE & 0xFF); + } + else if ((Command == AVR109_COMMAND_BlockWrite) || (Command == AVR109_COMMAND_BlockRead)) + { + /* Delegate the block write/read to a separate function for clarity */ + ReadWriteMemoryBlock(Command); + } + #endif + #if !defined(NO_FLASH_BYTE_SUPPORT) + else if (Command == AVR109_COMMAND_FillFlashPageWordHigh) + { + /* Write the high byte to the current flash page */ + boot_page_fill(CurrAddress, FetchNextCommandByte()); + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if (Command == AVR109_COMMAND_FillFlashPageWordLow) + { + /* Write the low byte to the current flash page */ + boot_page_fill(CurrAddress | 0x01, FetchNextCommandByte()); + + /* Increment the address */ + CurrAddress += 2; + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if (Command == AVR109_COMMAND_WriteFlashPage) + { + /* Commit the flash page to memory */ + boot_page_write(CurrAddress); + + /* Wait until write operation has completed */ + boot_spm_busy_wait(); + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if (Command == AVR109_COMMAND_ReadFLASHWord) + { + #if (FLASHEND > 0xFFFF) + uint16_t ProgramWord = pgm_read_word_far(CurrAddress); + #else + uint16_t ProgramWord = pgm_read_word(CurrAddress); + #endif + + WriteNextResponseByte(ProgramWord >> 8); + WriteNextResponseByte(ProgramWord & 0xFF); + } + #endif + #if !defined(NO_EEPROM_BYTE_SUPPORT) + else if (Command == AVR109_COMMAND_WriteEEPROM) + { + /* Read the byte from the endpoint and write it to the EEPROM */ + eeprom_write_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)), FetchNextCommandByte()); + + /* Increment the address after use */ + CurrAddress += 2; + + /* Send confirmation byte back to the host */ + WriteNextResponseByte('\r'); + } + else if (Command == AVR109_COMMAND_ReadEEPROM) + { + /* Read the EEPROM byte and write it to the endpoint */ + WriteNextResponseByte(eeprom_read_byte((uint8_t*)((intptr_t)(CurrAddress >> 1)))); + + /* Increment the address after use */ + CurrAddress += 2; + } + #endif + else if (Command != AVR109_COMMAND_Sync) + { + /* Unknown (non-sync) command, return fail code */ + WriteNextResponseByte('?'); + } + + /* Select the IN endpoint */ + Endpoint_SelectEndpoint(CDC_TX_EPADDR); + + /* Remember if the endpoint is completely full before clearing it */ + bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed()); + + /* Send the endpoint data to the host */ + Endpoint_ClearIN(); + + /* If a full endpoint's worth of data was sent, we need to send an empty packet afterwards to signal end of transfer */ + if (IsEndpointFull) + { + while (!(Endpoint_IsINReady())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + + Endpoint_ClearIN(); + } + + /* Wait until the data has been sent to the host */ + while (!(Endpoint_IsINReady())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + + /* Select the OUT endpoint */ + Endpoint_SelectEndpoint(CDC_RX_EPADDR); + + /* Acknowledge the command from the host */ + Endpoint_ClearOUT(); +} + diff --git a/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.h b/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.h new file mode 100644 index 00000000..80c74039 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.h @@ -0,0 +1,144 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for BootloaderCDC.c. + */ + +#ifndef _CDC_H_ +#define _CDC_H_ + + /* Includes: */ + #include + #include + #include + #include + #include + #include + #include + + #include "Descriptors.h" + #include "BootloaderAPI.h" + #include "Config/AppConfig.h" + + #include + #include + #include + + /* Preprocessor Checks: */ + #if !defined(__OPTIMIZE_SIZE__) + #error This bootloader requires that it be optimized for size, not speed, to fit into the target device. Change optimization settings and try again. + #endif + + /* Macros: */ + /** Version major of the CDC bootloader. */ + #define BOOTLOADER_VERSION_MAJOR 0x01 + + /** Version minor of the CDC bootloader. */ + #define BOOTLOADER_VERSION_MINOR 0x00 + + /** Hardware version major of the CDC bootloader. */ + #define BOOTLOADER_HWVERSION_MAJOR 0x01 + + /** Hardware version minor of the CDC bootloader. */ + #define BOOTLOADER_HWVERSION_MINOR 0x00 + + /** Eight character bootloader firmware identifier reported to the host when requested. */ + #define SOFTWARE_IDENTIFIER "LUFACDC" + + /** Magic bootloader key to unlock forced application start mode. */ + #define MAGIC_BOOT_KEY 0xDC42 + + /* Enums: */ + /** Possible memory types that can be addressed via the bootloader. */ + enum AVR109_Memories + { + MEMORY_TYPE_FLASH = 'F', + MEMORY_TYPE_EEPROM = 'E', + }; + + /** Possible commands that can be issued to the bootloader. */ + enum AVR109_Commands + { + AVR109_COMMAND_Sync = 27, + AVR109_COMMAND_ReadEEPROM = 'd', + AVR109_COMMAND_WriteEEPROM = 'D', + AVR109_COMMAND_ReadFLASHWord = 'R', + AVR109_COMMAND_WriteFlashPage = 'm', + AVR109_COMMAND_FillFlashPageWordLow = 'c', + AVR109_COMMAND_FillFlashPageWordHigh = 'C', + AVR109_COMMAND_GetBlockWriteSupport = 'b', + AVR109_COMMAND_BlockWrite = 'B', + AVR109_COMMAND_BlockRead = 'g', + AVR109_COMMAND_ReadExtendedFuses = 'Q', + AVR109_COMMAND_ReadHighFuses = 'N', + AVR109_COMMAND_ReadLowFuses = 'F', + AVR109_COMMAND_ReadLockbits = 'r', + AVR109_COMMAND_WriteLockbits = 'l', + AVR109_COMMAND_EraseFLASH = 'e', + AVR109_COMMAND_ReadSignature = 's', + AVR109_COMMAND_ReadBootloaderSWVersion = 'V', + AVR109_COMMAND_ReadBootloaderHWVersion = 'v', + AVR109_COMMAND_ReadBootloaderIdentifier = 'S', + AVR109_COMMAND_ReadBootloaderInterface = 'p', + AVR109_COMMAND_SetCurrentAddress = 'A', + AVR109_COMMAND_ReadAutoAddressIncrement = 'a', + AVR109_COMMAND_ReadPartCode = 't', + AVR109_COMMAND_EnterProgrammingMode = 'P', + AVR109_COMMAND_LeaveProgrammingMode = 'L', + AVR109_COMMAND_SelectDeviceType = 'T', + AVR109_COMMAND_SetLED = 'x', + AVR109_COMMAND_ClearLED = 'y', + AVR109_COMMAND_ExitBootloader = 'E', + }; + + /* Type Defines: */ + /** Type define for a non-returning pointer to the start of the loaded application in flash memory. */ + typedef void (*AppPtr_t)(void) ATTR_NO_RETURN; + + /* Function Prototypes: */ + static void CDC_Task(void); + static void SetupHardware(void); + + void Application_Jump_Check(void) ATTR_INIT_SECTION(3); + + void EVENT_USB_Device_ConfigurationChanged(void); + + #if defined(INCLUDE_FROM_BOOTLOADERCDC_C) || defined(__DOXYGEN__) + #if !defined(NO_BLOCK_SUPPORT) + static void ReadWriteMemoryBlock(const uint8_t Command); + #endif + static uint8_t FetchNextCommandByte(void); + static void WriteNextResponseByte(const uint8_t Response); + #endif + +#endif + diff --git a/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.txt b/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.txt new file mode 100644 index 00000000..f8c349cd --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/BootloaderCDC.txt @@ -0,0 +1,242 @@ +/** \file + * + * This file contains special DoxyGen information for the generation of the main page and other special + * documentation pages. It is not a project source file. + */ + +/** \mainpage CDC Class USB AVR Bootloader + * + * \section Sec_Compat Demo Compatibility: + * + * The following list indicates what microcontrollers are compatible with this demo. + * + * \li Series 7 USB AVRs (AT90USBxxx7) + * \li Series 6 USB AVRs (AT90USBxxx6) + * \li Series 4 USB AVRs (ATMEGAxxU4) + * \li Series 2 USB AVRs (AT90USBxx2, ATMEGAxxU2) + * + * \section Sec_Info USB Information: + * + * The following table gives a rundown of the USB utilization of this demo. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
USB Mode:Device
USB Class:Communications Device Class (CDC)
USB Subclass:Abstract Control Model (ACM)
Relevant Standards:USBIF CDC Class Standard
Supported USB Speeds:Full Speed Mode
+ * + * \section Sec_Description Project Description: + * + * This bootloader enumerates to the host as a CDC Class device (virtual serial port), allowing for AVR109 + * protocol compatible programming software to load firmware onto the AVR. + * + * Out of the box this bootloader builds for the AT90USB1287 with an 8KB bootloader section size, and will fit + * into 4KB of bootloader space. If you wish to alter this size and/or change the AVR model, you will need to + * edit the MCU, FLASH_SIZE_KB and BOOT_SECTION_SIZE_KB values in the accompanying makefile. + * + * When the bootloader is running, the board's LED(s) will flash at regular intervals to distinguish the + * bootloader from the normal user application. + * + * \warning THIS BOOTLOADER IS NOT SECURE. Malicious entities can recover written data, even if the device + * lockbits are set. + * + * \section Sec_Running Running the Bootloader + * + * On the USB AVR8 devices, setting the \c HWBE device fuse will cause the bootloader to run if the \c HWB pin of + * the AVR is grounded when the device is reset. + * + * The are two behaviours of this bootloader, depending on the device's fuses: + * + * If the device's BOOTRST fuse is set, the bootloader will run any time the system is reset from + * the external reset pin, unless no valid user application has been loaded. To initiate the bootloader, the + * device's external reset pin should be grounded momentarily. + * + * If the device's BOOTRST fuse is not set, the bootloader will run only if initiated via a software + * jump, or if the \c HWB pin was low during the last device reset (if the \c HWBE fuse is set). + * + * For board specific exceptions to the above, see below. + * + * \subsection SSec_XPLAIN Atmel Xplain Board + * Ground the USB AVR JTAG's \c TCK pin to ground when powering on the board to start the bootloader. This assumes the + * \c HWBE fuse is cleared and the \c BOOTRST fuse is set as the HWBE pin is not user accessible on this board. + * + * \subsection SSec_Leonardo Arduino Leonardo Board + * Ground \c IO13 when powering the board to start the bootloader. This assumes the \c HWBE fuse is cleared and the + * \c BOOTRST fuse is set as the HWBE pin is not user accessible on this board. + * + * \section Sec_Installation Driver Installation + * + * After running this bootloader for the first time on a new computer, you will need to supply the .INF + * file located in this bootloader project's directory as the device's driver when running under Windows. + * This will enable Windows to use its inbuilt CDC drivers, negating the need for custom drivers for the + * device. Other Operating Systems should automatically use their own inbuilt CDC-ACM drivers. + * + * \section Sec_HostApp Host Controller Application + * + * This bootloader is compatible with the open source application AVRDUDE, Atmel's AVRPROG, or other + * applications implementing the AVR109 protocol, which is documented on the Atmel website as an application + * note. + * + * \subsection SSec_AVRDude AVRDUDE (Windows, Mac, Linux) + * + * AVRDude is a free, cross-platform and open source command line programmer for Atmel and third party AVR + * programmers. It is available on the the Windows platform as part of the "WinAVR" package, or on other systems + * either from a build from the official source code, or in many distributions as a precompiled binary package. + * + * To load a new HEX file with AVRDude, specify "AVR109" as the programmer, with the allocated COM port. On Windows + * platforms this will be a COMx port name: + * \code + * avrdude -c AVR109 -p at90usb1287 -P COM0 -U flash:w:Mouse.hex + * \endcode + * + * On Linux systems, this will typically be a /dev/ttyACMx port name: + * \code + * avrdude -c AVR109 -p at90usb1287 -P /dev/ttyACM0 -U flash:w:Mouse.hex + * \endcode + * + * Refer to the AVRDude project documentation for additional usage instructions. + * + * \section Sec_API User Application API + * + * Several user application functions for FLASH and other special memory area manipulations are exposed by the bootloader, + * allowing the user application to call into the bootloader at runtime to read and write FLASH data. + * + * By default, the bootloader API jump table is located 32 bytes from the end of the device's FLASH memory, and follows the + * following layout: + * + * \code + * #define BOOTLOADER_API_TABLE_SIZE 32 + * #define BOOTLOADER_API_TABLE_START ((FLASHEND + 1UL) - BOOTLOADER_API_TABLE_SIZE) + * #define BOOTLOADER_API_CALL(Index) (void*)((BOOTLOADER_API_TABLE_START + (Index * 2)) / 2) + * + * void (*BootloaderAPI_ErasePage)(uint32_t Address) = BOOTLOADER_API_CALL(0); + * void (*BootloaderAPI_WritePage)(uint32_t Address) = BOOTLOADER_API_CALL(1); + * void (*BootloaderAPI_FillWord)(uint32_t Address, uint16_t Word) = BOOTLOADER_API_CALL(2); + * uint8_t (*BootloaderAPI_ReadSignature)(uint16_t Address) = BOOTLOADER_API_CALL(3); + * uint8_t (*BootloaderAPI_ReadFuse)(uint16_t Address) = BOOTLOADER_API_CALL(4); + * uint8_t (*BootloaderAPI_ReadLock)(void) = BOOTLOADER_API_CALL(5); + * void (*BootloaderAPI_WriteLock)(uint8_t LockBits) = BOOTLOADER_API_CALL(6); + * + * #define BOOTLOADER_MAGIC_SIGNATURE_START (BOOTLOADER_API_TABLE_START + (BOOTLOADER_API_TABLE_SIZE - 2)) + * #define BOOTLOADER_MAGIC_SIGNATURE 0xDCFB + * + * #define BOOTLOADER_CLASS_SIGNATURE_START (BOOTLOADER_API_TABLE_START + (BOOTLOADER_API_TABLE_SIZE - 4)) + * #define BOOTLOADER_CDC_SIGNATURE 0xDF00 + * + * #define BOOTLOADER_ADDRESS_START (BOOTLOADER_API_TABLE_START + (BOOTLOADER_API_TABLE_SIZE - 8)) + * #define BOOTLOADER_ADDRESS_LENGTH 4 + * \endcode + * + * From the application the API support of the bootloader can be detected by reading the FLASH memory bytes located at address + * \c BOOTLOADER_MAGIC_SIGNATURE_START and comparing them to the value \c BOOTLOADER_MAGIC_SIGNATURE. The class of bootloader + * can be determined by reading the FLASH memory bytes located at address \c BOOTLOADER_CLASS_SIGNATURE_START and comparing them + * to the value \c BOOTLOADER_CDC_SIGNATURE. The start address of the bootloader can be retrieved by reading the bytes of FLASH + * memory starting from address \c BOOTLOADER_ADDRESS_START. + * + * \subsection SSec_API_MemLayout Device Memory Map + * The following illustration indicates the final memory map of the device when loaded with the bootloader. + * + * \verbatim + * +----------------------------+ 0x0000 + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | User Application | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * +----------------------------+ FLASHEND - BOOT_SECTION_SIZE + * | | + * | Bootloader Application | + * | (Not User App. Accessible) | + * | | + * +----------------------------+ FLASHEND - 96 + * | API Table Trampolines | + * | (Not User App. Accessible) | + * +----------------------------+ FLASHEND - 32 + * | Bootloader API Table | + * | (User App. Accessible) | + * +----------------------------+ FLASHEND - 8 + * | Bootloader ID Constants | + * | (User App. Accessible) | + * +----------------------------+ FLASHEND + * \endverbatim + * + * \section Sec_KnownIssues Known Issues: + * + * \par On Linux machines, the CDC bootloader is unstable or inaccessible. + * A change to the \c ModemManager module in many Linux distributions causes + * this module to try to take control over inserted CDC devices, corrupting the + * datastream. A UDEV rule is required to prevent this. + * See here for resolution steps. + * If the issue still persists then uninstall modemmanager by executing sudo apt-get remove modemmanager, or + * the equivalent using your chosen distribution's package manager. + * + * \par On Linux machines, the CDC bootloader is inaccessible. + * On many Linux systems, non-root users do not have automatic access to newly + * inserted CDC devices. Root privileges or a UDEV rule is required to gain + * access. + * See here for resolution steps. + * + * \section Sec_Options Project Options + * + * The following defines can be found in this demo, which can control the demo behaviour when defined, or changed in value. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Define Name:Location:Description:
NO_BLOCK_SUPPORTAppConfig.hDefine to disable memory block read/write support in the bootloader, requiring all reads and writes to be made + * using the byte-level commands.
NO_EEPROM_BYTE_SUPPORTAppConfig.hDefine to disable EEPROM memory byte read/write support in the bootloader, requiring all EEPROM reads and writes + * to be made using the block-level commands.
NO_FLASH_BYTE_SUPPORTAppConfig.hDefine to disable FLASH memory byte read/write support in the bootloader, requiring all FLASH reads and writes + * to be made using the block-level commands.
NO_LOCK_BYTE_WRITE_SUPPORTAppConfig.hDefine to disable lock byte write support in the bootloader, preventing the lock bits from being set programmatically.
+ */ + diff --git a/Firmware/LUFA/Bootloaders/CDC/Config/AppConfig.h b/Firmware/LUFA/Bootloaders/CDC/Config/AppConfig.h new file mode 100644 index 00000000..613c0a66 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/Config/AppConfig.h @@ -0,0 +1,50 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * \brief Application Configuration Header File + * + * This is a header file which is be used to configure LUFA's + * compile time options, as an alternative to the compile time + * constants supplied through a makefile. + * + * For information on what each token does, refer to the + * \ref Sec_Options section of the application documentation. + */ + +#ifndef _APP_CONFIG_H_ +#define _APP_CONFIG_H_ + +// #define NO_BLOCK_SUPPORT +// #define NO_EEPROM_BYTE_SUPPORT +// #define NO_FLASH_BYTE_SUPPORT +// #define NO_LOCK_BYTE_WRITE_SUPPORT + +#endif diff --git a/Firmware/LUFA/Bootloaders/CDC/Config/LUFAConfig.h b/Firmware/LUFA/Bootloaders/CDC/Config/LUFAConfig.h new file mode 100644 index 00000000..4494b576 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/Config/LUFAConfig.h @@ -0,0 +1,93 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * \brief LUFA Library Configuration Header File + * + * This header file is used to configure LUFA's compile time options, + * as an alternative to the compile time constants supplied through + * a makefile. + * + * For information on what each token does, refer to the LUFA + * manual section "Summary of Compile Tokens". + */ + +#ifndef _LUFA_CONFIG_H_ +#define _LUFA_CONFIG_H_ + + #if (ARCH == ARCH_AVR8) + + /* Non-USB Related Configuration Tokens: */ +// #define DISABLE_TERMINAL_CODES + + /* USB Class Driver Related Tokens: */ +// #define HID_HOST_BOOT_PROTOCOL_ONLY +// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} +// #define HID_USAGE_STACK_DEPTH {Insert Value Here} +// #define HID_MAX_COLLECTIONS {Insert Value Here} +// #define HID_MAX_REPORTITEMS {Insert Value Here} +// #define HID_MAX_REPORT_IDS {Insert Value Here} +// #define NO_CLASS_DRIVER_AUTOFLUSH + + /* General USB Driver Related Tokens: */ + #define ORDERED_EP_CONFIG + #define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL) + #define USB_DEVICE_ONLY +// #define USB_HOST_ONLY +// #define USB_STREAM_TIMEOUT_MS {Insert Value Here} +// #define NO_LIMITED_CONTROLLER_CONNECT + #define NO_SOF_EVENTS + + /* USB Device Mode Driver Related Tokens: */ + #define USE_RAM_DESCRIPTORS +// #define USE_FLASH_DESCRIPTORS +// #define USE_EEPROM_DESCRIPTORS + #define NO_INTERNAL_SERIAL + #define FIXED_CONTROL_ENDPOINT_SIZE 8 + #define DEVICE_STATE_AS_GPIOR 0 + #define FIXED_NUM_CONFIGURATIONS 1 +// #define CONTROL_ONLY_DEVICE +// #define INTERRUPT_CONTROL_ENDPOINT + #define NO_DEVICE_REMOTE_WAKEUP + #define NO_DEVICE_SELF_POWER + + /* USB Host Mode Driver Related Tokens: */ +// #define HOST_STATE_AS_GPIOR {Insert Value Here} +// #define USB_HOST_TIMEOUT_MS {Insert Value Here} +// #define HOST_DEVICE_SETTLE_DELAY_MS {Insert Value Here} +// #define NO_AUTO_VBUS_MANAGEMENT +// #define INVERTED_VBUS_ENABLE_LINE + + #else + + #error Unsupported architecture for this LUFA configuration file. + + #endif +#endif diff --git a/Firmware/LUFA/Bootloaders/CDC/Descriptors.c b/Firmware/LUFA/Bootloaders/CDC/Descriptors.c new file mode 100644 index 00000000..bfb590ee --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/Descriptors.c @@ -0,0 +1,244 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "Descriptors.h" + +/** Device descriptor structure. This descriptor, located in SRAM memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +const USB_Descriptor_Device_t DeviceDescriptor = +{ + .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, + + .USBSpecification = VERSION_BCD(1,1,0), + .Class = CDC_CSCP_CDCClass, + .SubClass = CDC_CSCP_NoSpecificSubclass, + .Protocol = CDC_CSCP_NoSpecificProtocol, + + .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, + + .VendorID = 0x03EB, + .ProductID = 0x204A, + .ReleaseNumber = VERSION_BCD(1,0,0), + + .ManufacturerStrIndex = STRING_ID_Manufacturer, + .ProductStrIndex = STRING_ID_Product, + .SerialNumStrIndex = NO_DESCRIPTOR, + + .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS +}; + +/** Configuration descriptor structure. This descriptor, located in SRAM memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +const USB_Descriptor_Configuration_t ConfigurationDescriptor = +{ + .Config = + { + .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, + + .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), + .TotalInterfaces = 2, + + .ConfigurationNumber = 1, + .ConfigurationStrIndex = NO_DESCRIPTOR, + + .ConfigAttributes = USB_CONFIG_ATTR_RESERVED, + + .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) + }, + + .CDC_CCI_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = INTERFACE_ID_CDC_CCI, + .AlternateSetting = 0, + + .TotalEndpoints = 1, + + .Class = CDC_CSCP_CDCClass, + .SubClass = CDC_CSCP_ACMSubclass, + .Protocol = CDC_CSCP_ATCommandProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .CDC_Functional_Header = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = DTYPE_CSInterface}, + .Subtype = 0x00, + + .CDCSpecification = VERSION_BCD(1,1,0), + }, + + .CDC_Functional_ACM = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = DTYPE_CSInterface}, + .Subtype = 0x02, + + .Capabilities = 0x02, + }, + + .CDC_Functional_Union = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = DTYPE_CSInterface}, + .Subtype = 0x06, + + .MasterInterfaceNumber = INTERFACE_ID_CDC_CCI, + .SlaveInterfaceNumber = INTERFACE_ID_CDC_DCI, + }, + + .CDC_NotificationEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_NOTIFICATION_EPADDR, + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_NOTIFICATION_EPSIZE, + .PollingIntervalMS = 0xFF + }, + + .CDC_DCI_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = INTERFACE_ID_CDC_DCI, + .AlternateSetting = 0, + + .TotalEndpoints = 2, + + .Class = CDC_CSCP_CDCDataClass, + .SubClass = CDC_CSCP_NoDataSubclass, + .Protocol = CDC_CSCP_NoDataProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .CDC_DataOutEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_RX_EPADDR, + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_TXRX_EPSIZE, + .PollingIntervalMS = 0x05 + }, + + .CDC_DataInEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_TX_EPADDR, + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_TXRX_EPSIZE, + .PollingIntervalMS = 0x05 + } +}; + +/** Language descriptor structure. This descriptor, located in SRAM memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. + */ +const USB_Descriptor_String_t LanguageString = USB_STRING_DESCRIPTOR_ARRAY(LANGUAGE_ID_ENG); + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +const USB_Descriptor_String_t ManufacturerString = USB_STRING_DESCRIPTOR(L"Dean Camera"); + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +const USB_Descriptor_String_t ProductString = USB_STRING_DESCRIPTOR(L"LUFA CDC"); + +/** This function is called by the library when in device mode, and must be overridden (see LUFA library "USB Descriptors" + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + const void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = &DeviceDescriptor; + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = &ConfigurationDescriptor; + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + if (DescriptorNumber == STRING_ID_Language) + { + Address = &LanguageString; + Size = LanguageString.Header.Size; + } + else if (DescriptorNumber == STRING_ID_Manufacturer) + { + Address = &ManufacturerString; + Size = ManufacturerString.Header.Size; + } + else if (DescriptorNumber == STRING_ID_Product) + { + Address = &ProductString; + Size = ProductString.Header.Size; + } + + break; + } + + *DescriptorAddress = Address; + return Size; +} + diff --git a/Firmware/LUFA/Bootloaders/CDC/Descriptors.h b/Firmware/LUFA/Bootloaders/CDC/Descriptors.h new file mode 100644 index 00000000..538449fb --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/Descriptors.h @@ -0,0 +1,158 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2015. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2015 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include "Config/AppConfig.h" + + /* Macros: */ + #if defined(__AVR_AT90USB1287__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x97 + #define AVR_SIGNATURE_3 0x82 + #elif defined(__AVR_AT90USB647__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x96 + #define AVR_SIGNATURE_3 0x82 + #elif defined(__AVR_AT90USB1286__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x97 + #define AVR_SIGNATURE_3 0x82 + #elif defined(__AVR_AT90USB646__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x96 + #define AVR_SIGNATURE_3 0x82 + #elif defined(__AVR_ATmega32U4__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x95 + #define AVR_SIGNATURE_3 0x87 + #elif defined(__AVR_ATmega16U4__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x94 + #define AVR_SIGNATURE_3 0x88 + #elif defined(__AVR_ATmega32U2__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x95 + #define AVR_SIGNATURE_3 0x8A + #elif defined(__AVR_ATmega16U2__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x94 + #define AVR_SIGNATURE_3 0x89 + #elif defined(__AVR_AT90USB162__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x94 + #define AVR_SIGNATURE_3 0x82 + #elif defined(__AVR_ATmega8U2__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x93 + #define AVR_SIGNATURE_3 0x89 + #elif defined(__AVR_AT90USB82__) + #define AVR_SIGNATURE_1 0x1E + #define AVR_SIGNATURE_2 0x93 + #define AVR_SIGNATURE_3 0x82 + #else + #error The selected AVR part is not currently supported by this bootloader. + #endif + + /** Endpoint address for the CDC control interface event notification endpoint. */ + #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2) + + /** Endpoint address for the CDC data interface TX (data IN) endpoint. */ + #define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3) + + /** Endpoint address for the CDC data interface RX (data OUT) endpoint. */ + #define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4) + + /** Size of the CDC data interface TX and RX data endpoint banks, in bytes. */ + #define CDC_TXRX_EPSIZE 16 + + /** Size of the CDC control interface notification endpoint bank, in bytes. */ + #define CDC_NOTIFICATION_EPSIZE 8 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; + + // CDC Control Interface + USB_Descriptor_Interface_t CDC_CCI_Interface; + USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header; + USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM; + USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union; + USB_Descriptor_Endpoint_t CDC_NotificationEndpoint; + + // CDC Data Interface + USB_Descriptor_Interface_t CDC_DCI_Interface; + USB_Descriptor_Endpoint_t CDC_DataOutEndpoint; + USB_Descriptor_Endpoint_t CDC_DataInEndpoint; + } USB_Descriptor_Configuration_t; + + /** Enum for the device interface descriptor IDs within the device. Each interface descriptor + * should have a unique ID index associated with it, which can be used to refer to the + * interface from other descriptors. + */ + enum InterfaceDescriptors_t + { + INTERFACE_ID_CDC_CCI = 0, /**< CDC CCI interface descriptor ID */ + INTERFACE_ID_CDC_DCI = 1, /**< CDC DCI interface descriptor ID */ + }; + + /** Enum for the device string descriptor IDs within the device. Each string descriptor should + * have a unique ID index associated with it, which can be used to refer to the string from + * other descriptors. + */ + enum StringDescriptors_t + { + STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */ + STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ + STRING_ID_Product = 2, /**< Product string ID */ + }; + + /* Function Prototypes: */ + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/Firmware/LUFA/Bootloaders/CDC/LUFA CDC Bootloader.inf b/Firmware/LUFA/Bootloaders/CDC/LUFA CDC Bootloader.inf new file mode 100644 index 00000000..61624c73 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/LUFA CDC Bootloader.inf @@ -0,0 +1,66 @@ +;************************************************************ +; Windows USB CDC ACM Setup File +; Copyright (c) 2000 Microsoft Corporation +;************************************************************ + +[DefaultInstall] +CopyINF="LUFA CDC Bootloader.inf" + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%MFGNAME% +DriverVer=7/1/2012,10.0.0.0 + +[Manufacturer] +%MFGNAME%=DeviceList, NTx86, NTamd64, NTia64 + +[SourceDisksNames] + +[SourceDisksFiles] + +[DestinationDirs] +DefaultDestDir=12 + +[DriverInstall] +Include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=DriverInstall.AddReg + +[DriverInstall.Services] +Include=mdmcpq.inf +AddService=usbser, 0x00000002, LowerFilter_Service_Inst + +[DriverInstall.AddReg] +HKR,,EnumPropPages32,,"msports.dll,SerialPortPropPageProvider" + +;------------------------------------------------------------------------------ +; Vendor and Product ID Definitions +;------------------------------------------------------------------------------ +; When developing your USB device, the VID and PID used in the PC side +; application program and the firmware on the microcontroller must match. +; Modify the below line to use your VID and PID. Use the format as shown below. +; Note: One INF file can be used for multiple devices with different VID and PIDs. +; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the end of the line. +;------------------------------------------------------------------------------ +[DeviceList] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_204A + +[DeviceList.NTx86] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_204A + +[DeviceList.NTamd64] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_204A + +[DeviceList.NTia64] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_204A + +;------------------------------------------------------------------------------ +; String Definitions +;------------------------------------------------------------------------------ +;Modify these strings to customize your device +;------------------------------------------------------------------------------ +[Strings] +MFGNAME="http://www.lufa-lib.org" +DESCRIPTION="LUFA CDC Class Bootloader" diff --git a/Firmware/LUFA/Bootloaders/CDC/asf.xml b/Firmware/LUFA/Bootloaders/CDC/asf.xml new file mode 100644 index 00000000..02e7063c --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/asf.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CDC Class Bootloader, capable of reprogramming a device using avrdude or other AVR109 protocol compliant software when plugged into a host. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firmware/LUFA/Bootloaders/CDC/doxyfile b/Firmware/LUFA/Bootloaders/CDC/doxyfile new file mode 100644 index 00000000..41469347 --- /dev/null +++ b/Firmware/LUFA/Bootloaders/CDC/doxyfile @@ -0,0 +1,2396 @@ +# Doxyfile 1.8.9 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single 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. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "LUFA Library - CDC Class Bootloader" + +# 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 = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. 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 = ./Documentation/ + +# 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 causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, 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. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, 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. +# The default value is: YES. + +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 and 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. +# The default value is: NO. + +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. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, 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 +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# 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. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +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 list of 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. +# The default value is: NO. + +SHORT_NAMES = YES + +# 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-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# 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 Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +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 behavior. 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 behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +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. +# The default value is: NO. + +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. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act 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 = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# 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. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = NO + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# 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); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) 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. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES 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. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# 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. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If 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, only methods in the interface are +# included. +# The default value is: NO. + +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. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO 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. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +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, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +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 then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +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. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES 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. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the 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. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = 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. +# The default value is: YES. + +GENERATE_TODOLIST = NO + +# 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. +# The default value is: YES. + +GENERATE_TESTLIST = NO + +# 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. +# The default value is: YES. + +GENERATE_BUGLIST = NO + +# 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. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have 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 value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# 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. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command 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. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag 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. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag 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. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# 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) +# The default value is: $file:$line: $text. + +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 standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is 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. +# Note: If this tag is empty the current directory is searched. + +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. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +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 patterns (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, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.h \ + *.c \ + *.txt + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# 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. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = Documentation/ + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +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 +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = __* \ + INCLUDE_FROM_* + +# 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. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +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 information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# 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 that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = NO + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = 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. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES 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. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# 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. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +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 a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +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. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +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). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +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 left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = 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. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# 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. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# 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. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# 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). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# 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. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = YES + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 1 + +# 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. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /